From 9703d47407c276e21d7bb9362af6b40352c75721 Mon Sep 17 00:00:00 2001 From: Jonathan Hvid Date: Tue, 2 Jun 2026 14:08:19 +0200 Subject: [PATCH] credits: redesign supporter lockup + mobile parity pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the supporter credits ("Backed by" / "Part of") into a three-tier lockup — a small uppercase label over an upright Newsreader serif name, with the parent body / issuing authority in a quieter serif beneath — so the credits read in the deck's editorial voice instead of as a foreign sans-serif caption. Applied consistently across all three views: - Entrance welcome screen: replaced three separately position:fixed blocks (with hand-tuned top offsets) with one centred .welcome-credits lockup; drops the brittle magic-number stacking. - Timeline hero ("Fenja introduction"): left-aligned .support-credit stack in place of the old .support / .support-bii lines. - Mobile hero: matching .m-credit stack replacing .m-support / .m-backer. Credits now read: Backed by Innofounder (Innovationsfonden); Part of AI Lab (BioInnovation Institute); Part of The AI Regulatory Sandbox (Datatilsynet & Digitaliseringsstyrelsen). Also brings the mobile view to parity with the customer-facing desktop deck: updated hero copy, platform-question framing, architecture layers, Wiki deep-dive, deployment cards, and implementation roadmap; removes the old "Join Project Bifrost" CTA + footer (mobile.js loses the join handler, keeps the session check). Co-Authored-By: Claude Opus 4.8 (1M context) --- protected/index.html | 78 +++-- protected/mobile/index.html | 443 +++++++++++++++++++----- protected/mobile/mobile.css | 651 ++++++++++++++++++++++++------------ protected/mobile/mobile.js | 44 +-- public/entrance.html | 167 +++++---- 5 files changed, 943 insertions(+), 440 deletions(-) diff --git a/protected/index.html b/protected/index.html index ebab35b..0f255b7 100644 --- a/protected/index.html +++ b/protected/index.html @@ -1037,36 +1037,46 @@ html { 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. */ + /* Backer credits — funder + affiliations, in the deck's editorial + voice: a small uppercase Manrope label over each entity name set + in upright Newsreader serif, with the parent body / issuing + authority in a quieter serif beneath. Left-aligned variant of the + entrance page's centred .welcome-credits lockup. */ .support-stack { display: flex; flex-direction: column; align-items: flex-start; - gap: 6px; + gap: 15px; } - .support-bii { + .support-credit { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + } + .support-credit-label { + font-family: "Manrope", system-ui, sans-serif; font-size: 11px; font-weight: 600; + letter-spacing: 0.22em; text-transform: uppercase; - letter-spacing: 0.18em; - color: var(--ink-soft, var(--ink-mute)); + color: var(--ink-dim); + } + .support-credit-name { + font-family: "Newsreader", Georgia, serif; + font-style: normal; + font-weight: 500; + font-size: 19px; + line-height: 1.2; + letter-spacing: 0.005em; + color: var(--ink); + } + .support-credit-auth { + font-family: "Newsreader", Georgia, serif; + font-style: normal; + font-size: 13.5px; + line-height: 1.3; + color: var(--ink-soft); } .scroll-hint { @@ -2540,17 +2550,21 @@ html { downward (see @keyframes hint below). -->
-
- Backed by - - +
+ Backed by + Innofounder + Innovationsfonden +
+
+ Part of + AI Lab + BioInnovation Institute +
+
+ Part of + The AI Regulatory Sandbox + Datatilsynet & Digitaliseringsstyrelsen
-
Part of BioInnovation Institute AI Lab

For regulated environments

- Fenja AI — Secure & Sovereign, hosted where it belongs. + Trusted & Sovereign AI built in Denmark, for Europe.

- Fenja AI is a sovereign AI platform, enabling highly advanced AI capabilities hosted within the client’s own secure infrastructure. + 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.

-
- Supported by - Innovationsfonden +
+
+ Backed by + Innofounder + Innovationsfonden +
+
+ Part of + AI Lab + BioInnovation Institute +
+
+ Part of + The AI Regulatory Sandbox + Datatilsynet & Digitaliseringsstyrelsen +
- -
-

One complete platform

-

The Fenja AI platform in four steps.

- -
- - 1 / 4 -

The AI

-

An open-source model, running on your own hardware.

-

A state-of-the-art open-source language model deployed directly in your environment. It gives you powerful AI capabilities with full control over data, performance, and security.

-
- -
- - 2 / 4 -

The Knowledge

-

The business context that makes AI understand your world.

-

A built-in knowledge layer that helps the platform understand your terminology, processes, and data. It retains what matters, improves over time, and gives the AI the context needed to deliver relevant and accurate results.

-
- -
- - 3 / 4 -

The Tools

-

How AI acts — not just what it knows.

-

The capabilities that let the platform do real work across your environment. From search and retrieval to data access, automation, and analysis, these are the tools the AI uses to solve tasks in practice.

-
- -
- - 4 / 4 -

The Agents

-

Specialized AI agents working together around real tasks.

-

Purpose-built agents designed to handle distinct roles and workflows. Fenja AI includes both ready-made agents and the framework to build new ones, so you can orchestrate AI the same way your organisation already works — through specialisation and coordination.

-
-
- -
-
-

Ready?

-

- Join us in shaping the future of trusted sovereign AI. -

- -

Built in Denmark. Supported by the Innovation Fund.

-
+ +
+

Meet the Fenja AI Advisory Board

+

Bridging industry & sovereign AI

-
-
-
- Project Bifrost + +
+

+ Renting a few AI capabilities from American companies isn’t enough. Installing an open-source language model isn’t enough. +

+

+ You need a platform you control — with the tools, the knowledge, and the framework to make AI actually do the work your organization needs done. +

+
+ + +
+

Fenja AI Platform Architecture

+

Simply explained.

+ +
+

The foundation

+

A model in your environment.

+

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.

+
+ +
+

The foundation

+

Knowledge.

+

What makes the model Fenja — 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.

+
+ +
+

What Fenja can do

+

Tools.

+

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.

+
+ +
+

When one becomes a team

+

Agents.

+

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.

+
+ +
+

The full picture

+

Everything you need and with full control.

+

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.

+
+ + +
+

Everything Client-Managed

+ +
+
+ Foundation + Sovereign by design +
+
+
+

Language model

+

State-of-the-art, open-source

+

On-prem

+
+
+

Wiki

+

Company and domain knowledge

+

Organizational · Departmental · Personal

+
+
+

Routines & memory

+

How Fenja works inside it

+

Stand-ups · Recurring tasks · Working memory

+
+
+
+ +
+
+ Tools + How Fenja acts +
+
+
+

Document retrieval

+

Find and cite

+

RAG

+
+
+

Structured data (ie SQL)

+

Query and extract

+

NL → SQL

+
+
+

System actions

+

Read and write

+

APIs · integrations

+
+
+

Custom tools

+

Your specific work

+

Defined by you

+
+
+
+ +
+
+ Agents + How Fenja scales +
+
+
+

Supervisor

+

Plan and dispatch

+

Orchestration

+
+
+

Specialists

+

Focused expertise

+

Subagents

+
+
+

Skills

+

Reusable capability

+

Portable across specialists

+
+
+

Workflows

+

Composed by you

+

Governed end-to-end

+
+
+
- Fenja AI -
- - nnovationsfonden +
+ + +
+

From scattered to structured

+

One structured source of truth.

+ +
+

What you have today

+

Scattered knowledge

+

Documents · Emails · Notes · Knowledge in people’s heads

-
+ + + +
+

Fenja Compiler

+

AI Compiler

+

Apply your rules and structure to fit your requirements

+
+ + + +
+

Fenja Wiki

+

Structured output

+

Structured output · easy for humans and AIs to read.

+
+
+ + +
+

Deployment options

+

Choose your Capability.

+ +
+
+

Fenja Core.

+

Foundational

+

Essential LLM capabilities with Fenja Semantic. Your safe and custom chatbot that understands your organization.

+
+ +
+

Fenja Dev.

+

Developer toolset

+

Code faster and better with your own secure AI-supported development platform.

+

+ Core

+
+ +
+

Fenja Analyze.

+

Strategic intel

+

Bring real insights to your people. You ask for an insight, and your agents will find, analyze, and present the relevant data.

+

+ Core

+
+ +
+

Fenja Agentic.

+

Automation

+

The complete framework. Fully governed and controlled agents collaborate to solve your most important processes.

+

+ Core. Dev. Analyze.

+
+
+
+ + +
+

Implementation roadmap

+

One foundation, many use cases.

+ +
+ + Setup + Platform live in your environment + +
+

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.

+

Key activities

+
    +
  • Foundation model installed in your environment
  • +
  • SSO and identity provider connected
  • +
  • Brand voice, tone, and visual style applied
  • +
  • Baseline governance and security policies in place
  • +
+
+
+ +
+ + Knowledge + Captured into one structured source + +
+

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.

+

Key activities

+
    +
  • Use case scope and target output defined
  • +
  • Relevant files ingested and structured
  • +
  • AI-led interviews capture tacit expert knowledge
  • +
  • Outputs tested and validated against real work
  • +
+
+
+ +
+ + Tools + Acting across your systems + +
+

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.

+

Key activities

+
    +
  • Ongoing retrieval from data warehouses and SharePoint
  • +
  • Read and write integrations to specific APIs
  • +
  • Custom report outputs and structured deliverables
  • +
  • Each tool scoped, built, and tested for one specific job
  • +
+
+
+ +
+ + Agents + Workflows running under your control + +
+

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.

+

Key activities

+
    +
  • Agent tasks defined and scoped per workflow
  • +
  • Specialist agents built for specific jobs
  • +
  • Monitoring and audit trails configured
  • +
  • Human-in-the-loop checkpoints placed where they matter
  • +
  • Governance and security checks enforced at each step
  • +
+
+
+ +
+

Govern & scale

+

Security · compliance · change management · training · advisory council feedback

+
+ +

Setup is bounded · waves of use cases continue as your needs evolve.

+
diff --git a/protected/mobile/mobile.css b/protected/mobile/mobile.css index 53609c1..7b52002 100644 --- a/protected/mobile/mobile.css +++ b/protected/mobile/mobile.css @@ -302,83 +302,96 @@ html, body { color: var(--ink); max-width: 44ch; } -.m-support { - display: inline-flex; - align-items: baseline; - gap: 8px; - padding: 14px 18px 0; +/* Backer credits — funder + affiliations, in the deck's editorial + voice: a small uppercase Manrope label over each entity name set in + upright Newsreader serif, with the parent body / issuing authority + in a quieter serif beneath. Mirrors the desktop hero's left-aligned + .support-credit stack and the entrance page's .welcome-credits. */ +.m-credits { + margin-top: 24px; + padding-top: 22px; border-top: 1px solid var(--line); + display: flex; + flex-direction: column; + gap: 16px; } -.m-support-label { +.m-credit { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; +} +.m-credit-label { font-family: "Manrope", system-ui, sans-serif; - font-size: 10.5px; - letter-spacing: 0.16em; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.22em; text-transform: uppercase; color: var(--ink-dim); } -.m-support-name { - font-family: "Manrope", system-ui, sans-serif; - font-weight: 600; - font-size: 12.5px; - letter-spacing: 0.05em; - color: #3c6b6b; +.m-credit-name { + font-family: "Newsreader", Georgia, serif; + font-style: normal; + font-weight: 500; + font-size: 19px; + line-height: 1.2; + letter-spacing: 0.005em; + color: var(--ink); +} +.m-credit-auth { + font-family: "Newsreader", Georgia, serif; + font-style: normal; + font-size: 13.5px; + line-height: 1.3; + color: var(--ink-soft); } -/* ─── Capabilities ───────────────────────────────────────── */ -.m-caps { - padding: 88px 22px 88px; +/* ─── Platform question (framing) ────────────────────────── */ +.m-pq { + padding: 80px 22px 64px; + border-top: 1px solid var(--line); } -.m-cap { +.m-pq-title { + font-family: "Newsreader", Georgia, serif; + font-weight: 400; + font-size: 25px; + line-height: 1.18; + letter-spacing: -0.012em; + margin: 0 0 20px 0; + text-wrap: pretty; +} +.m-pq-body { + margin: 0; + font-size: 17px; + line-height: 1.6; + color: var(--ink-soft); +} +.m-pq-body em { font-style: italic; font-weight: 700; color: var(--ink); } + +/* ─── Architecture ───────────────────────────────────────── */ +.m-arch { + padding: 72px 22px 80px; +} +/* Narrative beats — colored cards, paper text. Palette mirrors the + desktop layer story (sage, slate, clay, plum), with a dark ink + "full picture" summary card to close the sequence. */ +.m-arch-beat { position: relative; - padding: 24px 22px 24px; - margin: 0 0 18px 0; + padding: 24px 22px; + margin: 0 0 14px 0; border-radius: 10px; + background: #7a8c70; + color: #fbf6e9; box-shadow: 0 16px 28px -22px rgba(46, 46, 40, 0.45), 0 4px 10px -6px rgba(46, 46, 40, 0.18); - min-height: 120px; - /* Per-layer backgrounds match the desktop palette: sage, slate, - clay, plum. Text is flipped to paper for contrast. */ - background: #7a8c70; /* default = layer 0, overridden below */ - color: #fbf6e9; - /* Clip the oversized corner icon so it reads as "tucked into the - corner" rather than floating outside the tile. */ - overflow: hidden; } -.m-cap:last-child { margin-bottom: 0; } -.m-cap:nth-of-type(1) { background: #7a8c70; } /* sage — The AI */ -.m-cap:nth-of-type(2) { background: #7b9399; } /* slate — The Knowledge */ -.m-cap:nth-of-type(3) { background: #b07556; } /* clay — The Tools */ -.m-cap:nth-of-type(4) { background: #8a7a92; } /* plum — The Agents */ - -.m-cap-icon { - position: absolute; - /* Negative offsets push the icon up and into the corner, past the - card edges. The parent's overflow: hidden clips the overflow so - the icon reads as a corner ornament that's been tucked into the - tile rather than sitting inside it. */ - top: -18px; - right: -18px; - width: 148px; - height: 148px; - object-fit: contain; - object-position: right top; - opacity: 1; - pointer-events: none; -} -.m-cap-num { - display: inline-block; - font-family: "Newsreader", Georgia, serif; - font-weight: 600; - font-size: 13.5px; - color: rgba(251, 246, 233, 0.85); - margin-bottom: 10px; - font-variant-numeric: tabular-nums; - letter-spacing: 0.02em; - /* Keep clear of the icon in the top-right. */ - padding-right: 120px; -} -.m-cap-eyebrow { +.m-arch-beat:nth-of-type(1) { background: #7a8c70; } /* sage — model */ +.m-arch-beat:nth-of-type(2) { background: #7b9399; } /* slate — knowledge */ +.m-arch-beat:nth-of-type(3) { background: #b07556; } /* clay — tools */ +.m-arch-beat:nth-of-type(4) { background: #8a7a92; } /* plum — agents */ +.m-arch-beat--summary { background: var(--ink); margin-bottom: 0; } +.m-arch-eyebrow { font-family: "Manrope", system-ui, sans-serif; font-size: 11px; font-weight: 700; @@ -386,39 +399,103 @@ html, body { text-transform: uppercase; color: rgba(251, 246, 233, 0.8); margin: 0 0 10px 0; - padding-right: 120px; } -.m-cap-title { +.m-arch-headline { font-family: "Newsreader", Georgia, serif; font-weight: 400; - font-size: 20px; - line-height: 1.22; + font-size: 21px; + line-height: 1.2; letter-spacing: -0.01em; margin: 0 0 12px 0; color: #fbf6e9; text-wrap: pretty; - padding-right: 120px; } -.m-cap-title b { - font-weight: 700; - font-style: normal; -} -.m-cap-title em { - font-style: italic; - font-weight: 700; - color: #fff9ea; -} -.m-cap-body { +.m-arch-headline em { font-style: italic; font-weight: 700; color: #fff9ea; } +.m-arch-body { margin: 0; - padding-right: 0; font-size: 15.5px; line-height: 1.55; color: rgba(251, 246, 233, 0.88); } -.m-cap-body em { - font-style: italic; +.m-arch-body em { font-style: italic; font-weight: 700; color: #fff9ea; } + +/* Component grid — light cards on paper, grouped under a labeled + "client-managed" frame. */ +.m-arch-frame { + margin-top: 32px; + padding: 16px 14px 18px; + border: 1px solid var(--line); + border-radius: 12px; + background: var(--paper-2); +} +.m-arch-frame-label { + font-family: "Manrope", system-ui, sans-serif; + font-size: 10.5px; font-weight: 700; - color: #fff9ea; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--ink-dim); + text-align: center; + margin: 0 0 16px 0; +} +.m-arch-group { margin: 0 0 18px 0; } +.m-arch-group:last-child { margin-bottom: 0; } +.m-arch-group-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 10px; + margin: 0 0 8px 0; +} +.m-arch-group-label { + font-family: "Manrope", system-ui, sans-serif; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; + color: var(--ink); +} +.m-arch-group-caption { + font-family: "Newsreader", Georgia, serif; + font-style: italic; + font-size: 13.5px; + color: var(--ink-soft); +} +.m-arch-cards { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; +} +.m-arch-card { + padding: 12px 12px 13px; + border-radius: 8px; + background: #fffdf6; + border: 1px solid var(--line); +} +.m-arch-card-name { + font-family: "Manrope", system-ui, sans-serif; + font-weight: 700; + font-size: 13px; + line-height: 1.25; + color: var(--ink); + margin: 0 0 4px 0; +} +.m-arch-card-italic { + font-family: "Newsreader", Georgia, serif; + font-style: italic; + font-size: 13px; + line-height: 1.3; + color: var(--ink-soft); + margin: 0 0 6px 0; +} +.m-arch-card-mono { + font-family: "Manrope", system-ui, sans-serif; + font-size: 10px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--ink-dim); + margin: 0; } /* ─── Project Bifrost reveal ─────────────────────────────── */ @@ -541,157 +618,295 @@ html, body { color: var(--ink); } -/* ─── Join CTA — the most emphatic section on the page ───── */ -.m-join { - padding: 100px 22px 120px; - background: var(--paper-3); +/* ─── Advisory board — 2-up portrait grid ────────────────── */ +.m-board { + padding: 80px 22px 72px; border-top: 1px solid var(--line); - border-bottom: 1px solid var(--line); } -.m-join-panel { - text-align: center; - padding: 40px 24px 36px; - background: #fffdf6; - border: 1.5px solid var(--ink); +.m-board-sub { + margin: 6px 0 36px 0; + font-family: "Newsreader", Georgia, serif; + font-style: italic; + font-size: 17px; + color: var(--ink-soft); +} +.m-board-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 32px 18px; +} +.m-board-member { margin: 0; } +.m-board-portrait { + width: 100%; + aspect-ratio: 1 / 1; + border-radius: 4px; + overflow: hidden; + background: #efeadc; +} +.m-board-portrait img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; +} +.m-bm-name { + font-family: "Newsreader", Georgia, serif; + font-weight: 700; + font-size: 17px; + line-height: 1.18; + letter-spacing: -0.01em; + color: var(--ink); + margin: 12px 0 4px 0; +} +.m-bm-title { + font-family: "Manrope", system-ui, sans-serif; + font-weight: 600; + font-size: 12.5px; + line-height: 1.3; + color: var(--ink); + margin: 0; +} +.m-bm-company { + font-family: "Manrope", system-ui, sans-serif; + font-weight: 400; + font-size: 12.5px; + line-height: 1.3; + color: var(--ink-dim); + margin: 2px 0 0 0; +} + +/* ─── Wiki deep-dive — scattered → compiler → structured ─── */ +.m-wiki { + padding: 72px 22px 80px; + border-top: 1px solid var(--line); +} +.m-wiki-zone { + padding: 22px 20px; border-radius: 10px; - box-shadow: - 0 30px 50px -24px rgba(46, 46, 40, 0.28), - 0 8px 18px -10px rgba(46, 46, 40, 0.14); - position: relative; + border: 1px solid var(--line); + background: #fffdf6; } -.m-join-panel::before { +/* Top zone reads "unsettled": muted surface, dashed edge. */ +.m-wiki-zone--scatter { + background: var(--paper-2); + border-style: dashed; + border-color: var(--ink-dim); +} +/* Compiler is the only element carrying the accent — mirrors the + desktop's single walnut highlight. */ +.m-wiki-zone--compiler { + background: var(--accent); + border-color: var(--accent); +} +.m-wiki-zone--compiler .m-wiki-eyebrow { color: rgba(255, 249, 234, 0.85); } +.m-wiki-zone--compiler .m-wiki-name { color: #fff9ea; } +.m-wiki-zone--compiler .m-wiki-sub { color: rgba(255, 249, 234, 0.92); } +.m-wiki-eyebrow { + font-family: "Manrope", system-ui, sans-serif; + font-size: 10.5px; + font-weight: 700; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--ink-dim); + margin: 0 0 8px 0; +} +.m-wiki-name { + font-family: "Newsreader", Georgia, serif; + font-weight: 400; + font-size: 23px; + line-height: 1.15; + letter-spacing: -0.012em; + color: var(--ink); + margin: 0 0 8px 0; +} +.m-wiki-sub { + margin: 0; + font-size: 15px; + line-height: 1.5; + color: var(--ink-soft); +} +/* Down-chevron connector between zones. */ +.m-wiki-arrow { + width: 14px; + height: 14px; + margin: 14px auto; + border-right: 2px solid var(--ink-dim); + border-bottom: 2px solid var(--ink-dim); + transform: rotate(45deg); +} + +/* ─── Deployment options ─────────────────────────────────── */ +.m-deploy { + padding: 72px 22px 80px; + border-top: 1px solid var(--line); +} +.m-deploy-grid { + display: flex; + flex-direction: column; + gap: 14px; +} +.m-deploy-card { + padding: 22px 20px; + border-radius: 10px; + border: 1px solid var(--line); + background: #fffdf6; +} +.m-deploy-card--dark { + background: var(--ink); + border-color: var(--ink); +} +.m-deploy-card--dark .m-deploy-name { color: #fbf6e9; } +.m-deploy-card--dark .m-deploy-name em { color: var(--accent); } +.m-deploy-card--dark .m-deploy-tier { color: rgba(251, 246, 233, 0.7); } +.m-deploy-card--dark .m-deploy-body { color: rgba(251, 246, 233, 0.9); } +.m-deploy-card--dark .m-deploy-includes { color: rgba(251, 246, 233, 0.6); } +.m-deploy-name { + font-family: "Newsreader", Georgia, serif; + font-weight: 400; + font-size: 24px; + line-height: 1.1; + letter-spacing: -0.012em; + color: var(--ink); + margin: 0 0 6px 0; +} +.m-deploy-name em { font-style: italic; font-weight: 700; color: var(--accent); } +.m-deploy-tier { + font-family: "Manrope", system-ui, sans-serif; + font-size: 10.5px; + font-weight: 700; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--ink-dim); + margin: 0 0 12px 0; +} +.m-deploy-body { + margin: 0; + font-size: 15.5px; + line-height: 1.55; + color: var(--ink); +} +.m-deploy-includes { + margin: 12px 0 0 0; + font-family: "Manrope", system-ui, sans-serif; + font-size: 12px; + font-weight: 600; + letter-spacing: 0.04em; + color: var(--ink-dim); +} + +/* ─── Implementation roadmap ─────────────────────────────── */ +.m-roadmap { + padding: 72px 22px 88px; + border-top: 1px solid var(--line); +} +.m-rm-card { + margin: 0 0 12px 0; + border-radius: 10px; + border: 1px solid var(--line); + background: #fffdf6; + overflow: hidden; +} +.m-rm-summary { + display: flex; + flex-direction: column; + gap: 4px; + padding: 18px 44px 18px 20px; + position: relative; + cursor: pointer; + list-style: none; +} +.m-rm-summary::-webkit-details-marker { display: none; } +/* +/− toggle chevron, top-right of the summary. */ +.m-rm-summary::after { content: ""; position: absolute; - top: -8px; left: 50%; - transform: translateX(-50%); - width: 48px; height: 1.5px; - background: var(--accent); + right: 20px; + top: 22px; + width: 9px; + height: 9px; + border-right: 2px solid var(--ink-dim); + border-bottom: 2px solid var(--ink-dim); + transform: rotate(45deg); + transition: transform 0.2s ease; } -.m-join-eyebrow { +.m-rm-card[open] .m-rm-summary::after { + transform: rotate(-135deg); + top: 26px; +} +.m-rm-name { + font-family: "Newsreader", Georgia, serif; + font-weight: 700; + font-size: 20px; + line-height: 1.1; + letter-spacing: -0.01em; + color: var(--ink); +} +.m-rm-italic { + font-family: "Newsreader", Georgia, serif; + font-style: italic; + font-size: 15px; + color: var(--ink-soft); +} +.m-rm-detail { + padding: 0 20px 20px; +} +.m-rm-intro { + margin: 0 0 16px 0; + font-size: 15.5px; + line-height: 1.55; + color: var(--ink); +} +.m-rm-label { + font-family: "Manrope", system-ui, sans-serif; + font-size: 10.5px; + font-weight: 700; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--ink-dim); + margin: 0 0 8px 0; +} +.m-rm-list { + margin: 0; + padding: 0 0 0 18px; +} +.m-rm-list li { + font-size: 15px; + line-height: 1.5; + color: var(--ink-soft); + margin: 0 0 6px 0; +} +.m-rm-list li:last-child { margin-bottom: 0; } +/* Cross-cutting band — neutral surface so it reads as "always on", + not as a fifth deliverable. */ +.m-rm-band { + margin-top: 20px; + padding: 18px 20px; + border-radius: 10px; + background: var(--paper-3); + border: 1px solid var(--line); +} +.m-rm-band-name { font-family: "Manrope", system-ui, sans-serif; font-size: 12px; font-weight: 700; - letter-spacing: 0.22em; + letter-spacing: 0.1em; text-transform: uppercase; - color: var(--accent); - margin: 0 0 16px 0; + color: var(--ink); + margin: 0 0 6px 0; } -.m-join-headline { +.m-rm-band-italic { font-family: "Newsreader", Georgia, serif; - font-weight: 400; - font-size: 30px; - line-height: 1.1; - letter-spacing: -0.014em; - margin: 0 0 28px 0; - text-wrap: pretty; + font-style: italic; + font-size: 14.5px; + line-height: 1.4; + color: var(--ink-soft); + margin: 0; } -.m-join-headline em { font-style: italic; font-weight: 700; color: var(--accent); } -.m-join-button { - all: unset; - display: inline-block; - background: var(--ink); - color: var(--paper); - font-family: "Newsreader", Georgia, serif; - font-size: 20px; - font-weight: 500; - letter-spacing: 0.01em; - padding: 18px 34px; - border-radius: 6px; - cursor: pointer; - box-shadow: - 0 14px 26px -14px rgba(46, 46, 40, 0.55), - 0 4px 10px -6px rgba(46, 46, 40, 0.3); -} -.m-join-button:active { - background: #000; - transform: translateY(1px); -} -.m-join-button:disabled { opacity: 0.55; cursor: progress; } -.m-join-subtext { - margin: 24px 0 0 0; +.m-rm-foot { + margin: 22px 0 0 0; + text-align: center; font-family: "Manrope", system-ui, sans-serif; - font-size: 11px; - letter-spacing: 0.14em; - text-transform: uppercase; + font-size: 11.5px; + letter-spacing: 0.04em; color: var(--ink-dim); } -.m-confirm-list { - margin: 0; - padding: 0; - list-style: none; - text-align: left; -} -.m-confirm-list li { - position: relative; - padding: 14px 0 14px 30px; - border-top: 1px solid var(--line); - font-size: 16px; - line-height: 1.5; - color: var(--ink); -} -.m-confirm-list li:first-child { border-top: none; } -.m-confirm-list li::before { - content: ""; - position: absolute; - left: 0; - top: 22px; - width: 14px; - height: 8px; - border-left: 2px solid var(--accent); - border-bottom: 2px solid var(--accent); - transform: rotate(-45deg); -} -.m-confirm-list em { font-style: italic; font-weight: 700; color: var(--accent); } - -/* ─── Footer (stacked brand marks) ───────────────────────── */ -.m-foot { - padding: 44px 22px 56px; - display: flex; - flex-direction: column; - align-items: center; - gap: 26px; - border-top: 1px solid var(--line); - background: var(--paper); -} -.m-foot-mark { - line-height: 0; - color: var(--ink); -} -.m-foot-mark--project { - font-family: "Newsreader", Georgia, serif; - font-weight: 400; - font-size: 18px; - line-height: 1; - letter-spacing: -0.005em; - color: var(--ink); -} -.m-foot-mark--project em { - font-style: italic; - font-weight: 700; - color: var(--accent); -} -.m-foot-mark--fenja { - height: 22px; - width: auto; - display: block; - opacity: 0.92; -} -.m-foot-mark--innov { - display: inline-flex; - align-items: center; - gap: 4px; - color: #3c6b6b; - line-height: 1; -} -.m-innov-mark { - width: 9px; - height: 16px; - display: block; -} -.m-innov-word { - font-family: "Manrope", system-ui, sans-serif; - font-weight: 600; - font-size: 14.5px; - letter-spacing: 0.04em; - color: #3c6b6b; -} diff --git a/protected/mobile/mobile.js b/protected/mobile/mobile.js index 84adb93..20e02d2 100644 --- a/protected/mobile/mobile.js +++ b/protected/mobile/mobile.js @@ -1,14 +1,16 @@ // ───────────────────────────────────────────────────────────── // protected/mobile/mobile.js — minimal client for the mobile view. // -// Two behaviours, nothing else: +// One behaviour, nothing else: // 1. Confirm the session is still valid on page load. If the // session expired since the server rendered the HTML, bounce // to "/" so the user doesn't read gated content without a // session cookie (defensive — requireAuth already gates the // page request itself). -// 2. POST /api/bifrost-join on CTA click; swap CTA panel → -// confirmation panel on success. +// +// The customer-facing deck ends on the implementation roadmap; there +// is no "Join" CTA on this view (matching the desktop view), so no +// POST to /api/bifrost-join. // // There is no logout button on the mobile view; the masthead is // logo-only by design. Users who want to log out can do so from a @@ -32,39 +34,3 @@ } })(); -const joinBtn = document.getElementById('m-join-btn'); -const joinCta = document.getElementById('m-join-cta'); -const joinConfirm = document.getElementById('m-join-confirm'); - -if (joinBtn && joinCta && joinConfirm) { - joinBtn.addEventListener('click', async () => { - joinBtn.disabled = true; - try { - const res = await fetch('/api/bifrost-join', { - method: 'POST', - credentials: 'same-origin', - headers: { 'content-type': 'application/json' }, - // Server reads email + sessionId from the session cookie, body - // just needs to be parseable JSON for express.json() to keep - // its rhythm. - body: '{}', - }); - if (res.status === 401) { - window.location.href = '/'; - return; - } - if (!res.ok) { - joinBtn.disabled = false; - joinBtn.textContent = 'Try again'; - return; - } - joinCta.hidden = true; - joinConfirm.hidden = false; - joinConfirm.scrollIntoView({ behavior: 'smooth', block: 'start' }); - } catch { - joinBtn.disabled = false; - joinBtn.textContent = 'Try again'; - } - }); -} - diff --git a/public/entrance.html b/public/entrance.html index 549d09d..f588051 100644 --- a/public/entrance.html +++ b/public/entrance.html @@ -131,78 +131,90 @@ } .field-input:disabled { opacity: 0.55; cursor: default; } - /* ───── Welcome-step wordmark (centered in the right half) ───── */ - .welcome-logo { + /* ───── Welcome-step brand lockup (centered in the right half) ───── + One fixed, centred container holding the Fenja wordmark and its + credits (funder + affiliations). Stacking them in a single + centred flex column — rather than three separately-pinned fixed + elements with hand-tuned top offsets — keeps the credits balanced + beneath the logo no matter how many lines they run to, and lets + the longest affiliation line wrap cleanly within a fixed width. + The whole group fades in together when the welcome step is + active. Hidden entirely on narrow screens (see the media query). */ + .welcome-lockup { position: fixed; top: 50%; left: 75%; transform: translate(-50%, -50%); - width: 280px; - height: auto; + width: clamp(280px, 32vw, 360px); + display: flex; + flex-direction: column; + align-items: center; + text-align: center; opacity: 0; pointer-events: none; z-index: 5; transition: opacity 640ms var(--ease) 120ms; } - body:has(#step-welcome.is-active) .welcome-logo { + body:has(#step-welcome.is-active) .welcome-lockup { + opacity: 1; + } + .welcome-logo { + width: 250px; + max-width: 100%; + height: auto; opacity: 0.92; } - - /* "Backed by Innovationsfonden" — sits directly beneath the fixed - welcome-logo at the same horizontal centre (left:75%). Fades in - with the welcome step (same trigger as the logo above it). */ - .welcome-backer { - position: fixed; - /* Sits below the fixed welcome-logo. The logo renders ~70px tall - at width:280px, so its bottom edge is ~50% + 35px; this sits - clear of that with enough breathing room not to crowd the - wordmark. Horizontal nudge via the transform pushes the block - slightly right of the logo's centreline so it reads as a - support line rather than a baseline caption. */ - top: calc(50% + 80px); - left: 75%; - transform: translate(calc(-38% - 5px), 0); - display: inline-flex; + /* Hairline divider between the wordmark and the credits. */ + .welcome-rule { + width: 56px; + height: 1px; + margin: 26px 0 24px; + background: var(--ink-soft); + opacity: 0.28; + } + /* Credits — funder + affiliations, rendered in the deck's editorial + voice: a small uppercase Manrope label over each entity name set + in Newsreader serif italic. This ties the credits to the Fenja + wordmark above (and to the serif headlines elsewhere) instead of + reading as a sans-serif caption stuck beneath the logo. */ + .welcome-credits { + display: flex; + flex-direction: column; + gap: 20px; + } + .welcome-credit { + display: flex; + flex-direction: column; align-items: center; - gap: 10px; + gap: 5px; + } + .welcome-credit-label { font-family: "Manrope", system-ui, -apple-system, sans-serif; - font-size: 11px; + font-size: 12px; font-weight: 600; - letter-spacing: 0.18em; + letter-spacing: 0.24em; text-transform: uppercase; + color: var(--ink-dim); + } + .welcome-credit-name { + font-family: "Newsreader", Georgia, "Times New Roman", serif; + font-style: normal; + font-weight: 500; + font-size: 21px; + line-height: 1.25; + letter-spacing: 0.005em; + color: var(--ink); + text-wrap: balance; + } + /* Parent body / issuing authority beneath an affiliation name — + quieter serif so the name above keeps the spotlight. */ + .welcome-credit-auth { + font-family: "Newsreader", Georgia, "Times New Roman", serif; + font-style: normal; + font-size: 15px; + line-height: 1.3; color: var(--ink-soft); - opacity: 0; - pointer-events: none; - z-index: 5; - transition: opacity 640ms var(--ease) 160ms; - } - .welcome-backer svg { height: 24px; width: auto; display: block; } - body:has(#step-welcome.is-active) .welcome-backer { - opacity: 0.85; - } - - /* "Part of BioInnovation Institute AI Lab" — sits directly below - the welcome-backer line. Same horizontal anchor (left:75%) and - transform offset, just nudged down so the two lines stack with - consistent breathing room. Fades in with the welcome step. */ - .welcome-bii { - position: fixed; - top: calc(50% + 112px); - left: 75%; - transform: translate(calc(-38% - 5px), 0); - font-family: "Manrope", system-ui, -apple-system, sans-serif; - font-size: 11px; - font-weight: 600; - letter-spacing: 0.18em; - text-transform: uppercase; - color: var(--ink-soft); - opacity: 0; - pointer-events: none; - z-index: 5; - transition: opacity 640ms var(--ease) 200ms; - } - body:has(#step-welcome.is-active) .welcome-bii { - opacity: 0.85; + text-wrap: balance; } /* ───── Welcome ───── */ @@ -344,9 +356,7 @@ .currents { opacity: 0.5; } .welcome-title { font-size: 38px; } .welcome-body { font-size: 18px; } - .welcome-logo { display: none; } - .welcome-backer { display: none; } - .welcome-bii { display: none; } + .welcome-lockup { display: none; } } @@ -354,21 +364,30 @@ - - -