diff --git a/SITE_STRUCTURE_REFERENCE.md b/SITE_STRUCTURE_REFERENCE.md new file mode 100644 index 0000000..d187864 --- /dev/null +++ b/SITE_STRUCTURE_REFERENCE.md @@ -0,0 +1,327 @@ +# Project Bifrost — Site Structure Reference + +This document labels every editable piece of the site with a short name you can quote when asking for changes, and notes where each piece lives in the code. Use the labels (e.g. **S1 lede**, **P3 footer**) to point at changes precisely. + +--- + +## Top-level structure + +The site has **three pages**, each occupying the full viewport. A dot-nav at the bottom switches between them. + +``` +/timeline → ┌─────────────────────────────────────────────┐ + │ [P1] TIMELINE │ + │ [P2] OVERVIEW (Project Bifrost scenes) │ + │ [P3] ARCHIVE │ + └─────────────────────────────────────────────┘ +``` + +Only one page is visible at a time. They are mutually exclusive — switching between them is a class toggle on the page wrapper, not a navigation. + +Before reaching any of the three, users see the **entrance** at `/` (email form → welcome step). The entrance is a separate HTML file in `public/`. + +--- + +## [P1] TIMELINE — horizontal scroll catalog + +**Files:** `protected/index.html` (`#page-timeline`, lines ~739–758) + `protected/timeline.js` + +A horizontal mousewheel-driven scroll through 23 editorial cards, set over a slowly rotating orthographic globe. Cards alternate above and below a central spine; each is accented by one of four colours (copper/ochre/terracotta/crimson) denoting register. + +| Label | What it is | Where to change | +|---|---|---| +| **P1 page title** | *"From the promise of AI to the loss of **sovereignty.**"* | `index.html` line 740 | +| **P1 subtitle** | *"Twenty-three headlines, quietly laid across a tinted map. Scroll the wheel — the map turns with you."* | `index.html` line 741 | +| **P1 globe** | Rotating orthographic globe that tracks scroll position from N. America → Europe | `timeline.js` — `buildGlobe()` + `setRotation` in `applyScroll()` | +| **P1 events** | The 23 headline cards. Each has `date`, `kind`, `accent`, `hed`, `body`, `source` | `timeline.js` — `EVENTS` array, lines 4–102 | +| **P1 card styles** | Card layout, above/below-spine positioning, colour accents per `accent` value | `index.html` CSS `.evt`, `.accent-*` | +| **P1 year ticks** | "2022", "2023", … on the spine between groups of cards | `timeline.js` — `buildTimeline()`, year-tick loop | +| **P1 "Read the editor's note" button** | Bottom-right, appears near the end of the catalog; fires dot-nav switch to Overview | `index.html` line 747 (text) + `.continue-btn` CSS + `timeline.js` click handler | + +--- + +## [P2] OVERVIEW — The Project Bifrost scroll + +**Files:** `protected/index.html` (`#page-overview`, lines ~2232–2619) + `protected/bifrost.js` + +A vertically scrolling container that holds six scroll-bound scenes. The Europe map sits as a fixed background behind them all and fades in/out with scroll position. + +``` +┌─ S1 HERO ──────────────┐ +│ "Secure & Sovereign │ ← Europe map fades behind +│ AI, hosted where it │ +│ belongs." │ +└────────────────────────┘ +┌─ S2 ARCHITECTURE ──────┐ +│ 4 layer cards fall + │ ← pinned, scrubbed +│ morph into 2x2 grid │ +└────────────────────────┘ +┌─ S3 WORDS ─────────────┐ +│ "...built with them, │ ← words fly in +│ not just for them." │ +└────────────────────────┘ +┌─ S4 BIFROST ARC ───────┐ +│ 🌈 aurora arc draws │ ← "Introducing Project Bifrost" +│ "Project Bifrost" │ +└────────────────────────┘ +┌─ S5 TREASURE MAP ──────┐ +│ Community, Advisory │ ← 3 stops on a winding path +│ Council, Pilot Proj. │ +└────────────────────────┘ +┌─ S6 JOIN CTA + FOOTER ─┐ +│ "Join us in shaping…" │ ← button → confirmation panel +│ [Proj] [Fenja] [Innov]│ ← 3-column footer +└────────────────────────┘ +``` + +### S0 — Europe map background + +The map stays static behind all six scenes. It does not rotate with scroll; it only fades. + +| Label | What it is | Where | +|---|---|---| +| **P2 Europe map** | Static orthographic globe centered on Europe, sitting behind the hero | `index.html` line 2234 (`.overview-globe`) + CSS line 441 | +| **P2 map opacity ceiling** | Maximum map opacity (currently `0.42`) | `bifrost.js` — `MAP_MAX_OPACITY` constant | +| **P2 map fade curve** | Fully visible 0–20% scroll, fades to 0 by 80% scroll, fades back in when scrolling up | `bifrost.js` — `updateMapOpacity()` function | + +### S1 — Hero + +| Label | What it is | Where | +|---|---|---| +| **S1 eyebrow** | *"For regulated environments"* | `index.html` line 2246 | +| **S1 headline** | *"Secure & **Sovereign** AI, hosted where it **belongs.**"* | `index.html` lines 2247–2250 | +| **S1 lede** | *"Enabling highly advanced AI capabilities hosted within the client's own secure infrastructure."* | `index.html` lines 2251–2253 | +| **S1 supported-by** | Innovationsfonden placeholder logo + *"Supported by"* strip | `index.html` lines 2258–2267 | +| **S1 scroll hint** | "Scroll →" indicator bottom-right | `index.html` lines 2268–2271 | +| **S1 hero styles** | Type scale, colours, grid positioning, left-column anchoring | `index.html` CSS `#hero`, `.hero-title`, `.hero-lede`, `.hero-foot` | +| **S1 hero animation** | Word-by-word reveal of the headline on scene entry | `bifrost.js` — search `HERO — staggered intro` | + +### S2 — Architecture stack + +Four cards fall into a stack one at a time, then rearrange into a 2x2 grid. As they do, three copy panels crossfade on the left. + +| Label | What it is | Where | +|---|---|---| +| **S2 copy panel A** | *"All the capabilities to solve business use cases with AI. Four layers. One architecture. Every piece yours to own."* | `index.html` lines 2284–2288 (`data-copy="0"`) | +| **S2 copy panel B** | *"Full client **control.** Complete **sovereignty.**"* + *"Nothing proprietary above the hardware…"* | `index.html` lines 2289–2292 (`data-copy="1"`) | +| **S2 copy panel C** | *"Built in **Denmark.** For **Europe.**"* + *"Engineered against the standards that matter here…"* | `index.html` lines 2293–2297 (`data-copy="2"`) | +| **S2 card 1 — Foundation** | *"AI — An **open-source** model, running on your **own hardware.**"* | `index.html` lines 2302–2310 (`data-layer="0"`) | +| **S2 card 2 — Knowledge** | *"The **vocabulary** of your business — **learned, retained.**"* | `index.html` lines 2312–2320 (`data-layer="1"`) | +| **S2 card 3 — Tools** | *"How the AIs **act** — not just what they **know.**"* | `index.html` lines 2322–2330 (`data-layer="2"`) | +| **S2 card 4 — Agents** | *"**Specialists**, **collaborating** to solve distinct tasks."* | `index.html` lines 2332–2340 (`data-layer="3"`) | +| **S2 stack animation** | The fall, stack, morph-to-grid scrub sequence | `bifrost.js` — search `ARCHITECTURE — two-phase scrubbed sequence` | +| **S2 card styles** | Shape, padding, "brain" illustration, eyebrow, grid-mode styles | `index.html` CSS `.layer-card`, `.card-box`, `.card-brain`, `.in-grid` | + +### S3 — Words fly in + +Sixteen individual words fly in from random directions as the user scrolls, assembling into one full sentence. Two words (`with` and `them,`) are given extra visual weight. + +| Label | What it is | Where | +|---|---|---| +| **S3 full sentence** | *"But a platform for regulated organisations has to be built with them, not just for them."* | `index.html` lines 2361–2376 | +| **S3 highlight words** | `with`, `them,` — the two words with emphasis class `hi` | `index.html` lines 2371–2372 | +| **S3 word styles + animation** | Individual word reveal with scatter/scale/blur | `bifrost.js` — search `WORDS fly in`; CSS `.words`, `.w`, `.w.hi` | + +### S4 — Bifrost aurora arc + +A rainbow arc draws across the scene, then the "Project Bifrost" title fades in below it. This is the only place on the site where a gradient is used. + +| Label | What it is | Where | +|---|---|---| +| **S4 eyebrow** | *"Introducing"* | `index.html` line 2441 | +| **S4 name** | *"**Project Bifrost**"* (split into two tokens — "Project" + "Bifrost") | `index.html` lines 2442–2445 | +| **S4 subtitle** | *"The bridge **between** an industrial-grade AI platform and the realities of regulated organisations — built **with** them, not just for them."* | `index.html` lines 2446–2448 | +| **S4 arc** | The rainbow arc that draws across the scene | `index.html` lines 2391–2436 — `` with `#arcHalo`, `#arcMain`, `#arcThin` | +| **S4 arc colors** | The aurora gradient stops (ochre → terracotta → indigo → heather) | `index.html` lines 2393–2408 — `` stops | +| **S4 arc animation** | Stroke-dashoffset draw-in on scroll | `bifrost.js` — search `PROJECT BIFROST REVEAL` | + +### S5 — Treasure map (3 stops) + +A winding path draws down the scene, passing through three "stops" — each an illustrated card about one way to participate in Project Bifrost. Stops alternate left / right of the path. + +| Label | What it is | Where | +|---|---|---| +| **S5 intro title** | *"What being part of **Project Bifrost** means"* | `index.html` lines 2469–2471 | +| **S5 intro lede** | *"Three ways to **shape**, to **influence**, and to **build with** the platform from the inside — a journey through what participation actually looks like."* | `index.html` lines 2472–2474 | +| **S5 winding path** | The bezier curve drawn between stops; rebuilt at runtime to pass through dot positions | `index.html` lines 2482–2494 (SVG shell); `bifrost.js` — `buildMapPath()` | +| **S5 intro stop** | *"Being part of **Project Bifrost** means **three** 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."* (centered introductory copy) | `index.html` lines 2497–2504 | +| **S5 stop 1 — Community** | Eyebrow *"Be part of a"* + title ***"Community"*** + sub *"Shape the future together"* + body copy + illustration of six people in discussion | `index.html` lines 2507–2518; illustration `fenja/illustrations/community.svg` | +| **S5 stop 2 — Advisory Council** | Eyebrow *"Be part of an"* + title ***"Advisory Council"*** + sub *"Turn insight into influence"* + body copy + illustration of a man and a woman in conversation | `index.html` lines 2521–2532; illustration `fenja/illustrations/council.svg` | +| **S5 stop 3 — Pilot Projects** | Eyebrow *"Be part of"* + title ***"Pilot Projects"*** + sub *"Access the platform before others"* + body copy + illustration of two people at a computer | `index.html` lines 2535–2546; illustration `fenja/illustrations/pilot.svg` | +| **S5 path animation + per-stop reveals** | Draw-in of path; dot pops in + text/image fade on reach | `bifrost.js` — search `Treasure-map path draw` | +| **S5 styles** | Layout, alternating left/right stops, dots, path styling | `index.html` CSS `.map-intro`, `.map-canvas`, `.map-stop`, `.dot-anchor`, `.stop-*` | + +### S6 — Join CTA + footer + +The final scene is a large call-to-action headline with a single button. Clicking the button crossfades to a confirmation panel listing what happens next. Below, a three-column footer with brand marks. + +| Label | What it is | Where | +|---|---|---| +| **S6 CTA eyebrow** | *"Ready?"* | `index.html` line 2565 | +| **S6 CTA headline** | *"Join us in shaping the future of **trusted sovereign AI.**"* | `index.html` lines 2566–2568 | +| **S6 CTA button text** | *"Join Project Bifrost"* | `index.html` lines 2569–2572 | +| **S6 CTA subtext** | *"Built in Denmark. Supported by the Innovation Fund."* | `index.html` line 2573 | +| **S6 confirmation eyebrow** | *"You're in"* | `index.html` line 2578 | +| **S6 confirmation headline** | *"Thank you for joining **Project Bifrost**."* | `index.html` lines 2579–2581 | +| **S6 confirmation list item 1** | *"The **Fenja AI team** will reach out to you shortly."* | `index.html` line 2583 | +| **S6 confirmation list item 2** | *"You'll receive an invitation to the **project portal** soon…"* | `index.html` line 2584 | +| **S6 confirmation list item 3** | *"We're currently setting the date for the **first advisory council meeting**…"* | `index.html` line 2585 | +| **S6 confirmation list item 4** | *"We'll be in touch shortly about your participation in the **pilot project**."* | `index.html` line 2586 | +| **S6 footer left — "Project Bifrost"** | Wordmark rendered in Newsreader with italic emphasis on "Bifrost" | `index.html` line 2593 | +| **S6 footer center — Fenja logo** | `` pointing to `/fenja/fenja-wordmark-black.svg` | `index.html` lines 2595–2599 | +| **S6 footer right — Innovationsfonden** | Placeholder slanted-I mark + "nnovationsfonden" text (to be swapped for real asset) | `index.html` lines 2601–2612 | +| **S6 click handler** | CTA → confirmation crossfade + staggered checkmarks on list items | `bifrost.js` — search `SCENE 6 — Join section` | + +--- + +## [P3] ARCHIVE — 23-row table + +**Files:** `protected/index.html` (`#page-archive`, lines ~2622–2651) + `protected/timeline.js` archive-builder IIFE + +A tabular view of the same 23 events from the timeline, sorted chronologically. Each row fades its background on hover. + +| Label | What it is | Where | +|---|---|---| +| **P3 headline** | *"All twenty-three entries, in order of **publication.**"* | `index.html` line 2625 | +| **P3 sub** | *"Dates, sources and plate numbers for every card in the catalog. Hover a row to lift it from the paper."* | `index.html` lines 2626–2629 | +| **P3 table** | 5 columns: №, Date, Register, Headline, Source | `index.html` table markup + `timeline.js` archive-builder IIFE (lines 406–420) | +| **P3 data** | Same `EVENTS` array as the timeline | `timeline.js` — `EVENTS` | +| **P3 footer** | *"Fenja AI · Field Notes, No. IV / Catalog closed 14 April 2026 / Page III of III"* | `index.html` lines 2644–2648 | + +--- + +## Shared chrome — visible on all three pages + +**Files:** `protected/index.html` (lines 2207 + 2653–2668) + `protected/timeline.js` + +| Label | What it is | Where | +|---|---|---| +| **Site wordmark** | Top-left Fenja logo, 118px wide | `index.html` line 2207 | +| **Dot-nav tray** | Subtle gradient fade at the bottom edge of the viewport | `index.html` `.dot-nav-tray` | +| **Dot-nav** | Bottom-center "Timeline / Overview / Archive" page switcher | `index.html` lines 2653–2668 | +| **Dot-nav logic** | Page activation + bifrost lazy-init on first Overview visit | `timeline.js` — `activatePage()` function, lines 439–457 | + +--- + +## Entrance — before login + +**Files:** `public/entrance.html` + `public/entrance.js` + +The only public-facing page. A single email field; on submit, if the email is on the invite list, advances to a welcome step. Otherwise shows an inline "not invited" message. + +| Label | What it is | Where | +|---|---|---| +| **Entrance tagline** | *"Thank you for your commitment and willingness to contribute."* | `entrance.html` step-email `.tagline` | +| **Entrance email input** | The single input field with "your email" placeholder | `entrance.html` step-email `
` | +| **Entrance topographic currents** | Concentric-circle SVG background in the top-right | `entrance.js` — `drawCurrents()` IIFE | +| **Entrance error messages** | *"Please enter a valid email address."* / *"This email is not on the invite list."* / *"Too many attempts…"* | `entrance.js` — inside the submit handler | +| **Welcome title** | *"Thanks for your interest, **[Name].**"* (or *"Thank you for your **interest.**"* when no first name) — set by JS after a successful login | `entrance.js` — `setWelcomeTitle()` | +| **Welcome body, paragraph 1** | *"Thank you for joining and for your interest in enabling sovereign AI in Denmark and Europe. Project Bifrost is a deliberate effort to advance it — the conviction that how we build these systems, and where, will shape the next decades."* | `entrance.html` step-welcome `.welcome-body` (first one) | +| **Welcome body, paragraph 2** | *"What follows is a timeline: twenty-three moments that explain why this matters now, and what the path looks like."* | `entrance.html` step-welcome `.welcome-body` (second one) | +| **"Learn more" button** | The button that routes to `/timeline` | `entrance.html` step-welcome `#welcome-continue` | +| **Welcome logo ghost** | Faint Fenja wordmark occupying the right half of the viewport | `entrance.html` `.welcome-logo` | + +--- + +## Auth — server-side + +**Files:** `src/auth.js` + `src/sessions.js` + `src/db.js` + `bin/invite.js` + +For completeness — not UI, but labelled here so you can point at it when relevant. + +| Label | What it is | Where | +|---|---|---| +| **Login endpoint** | `POST /auth/login` — accepts `{email}`, returns `{ok, firstName}` on success or `{error: "not_invited"}` with 403 | `src/auth.js` | +| **Login rate limit** | 30 attempts per IP per hour | `src/auth.js` — `rateLimit({…})` on `/login` route | +| **Logout endpoint** | `POST /auth/logout` — clears session cookie | `src/auth.js` | +| **Me endpoint** | `GET /auth/me` — returns `{email, firstName}` for current session or 401 | `src/auth.js` | +| **Invite CLI** | `node bin/invite.js add [FirstName]` / `remove` / `list` | `bin/invite.js` | +| **Invite schema** | `invites(email, first_name, invited_at, invited_by)` | `src/db.js` | +| **Session duration** | 30 days | `src/sessions.js` — `SESSION_TTL_MS` | + +--- + +## Design tokens — safe to change, affect everything cohesively + +**File:** `protected/fenja/colors_and_type.css` + +| Token | Value | Meaning | +|---|---|---| +| `--paper` / `--background` | `#faf6ee` | Primary paper background | +| `--ink` / `--on-surface` | `#383831` | Primary text colour | +| `--ink-soft` / `--on-surface-variant` | `#5f5e5e` | Muted text | +| `--ink-dim` / `--on-surface-muted` | `#8a887f` | Very muted text | +| `--walnut` / `--secondary` | `#785f53` | Primary accent (links, focus rings) | +| `--crimson` | `#8a3a2f` | Destructive / error | +| `--pigment-terracotta` | `#b96b58` | Warnings, S4 Bifrost accent | +| `--pigment-copper` | `#6d8c7c` | Success, organic / growth | +| `--pigment-ochre` | `#c29d59` | Cautions, tertiary | +| `--pigment-indigo` | `#5a6d83` | Info (only "blue" allowed) | +| `--pigment-heather` | `#8d7a85` | Categorical, supportive | +| Aurora gradient stops | ochre → terracotta → indigo → heather | S4 arc only | + +Fonts: **Newsreader** (serif, for intent) and **Manrope** (sans, for execution). Both self-hosted as variable fonts in `protected/fenja/fonts/`. + +The "no line" rule applies throughout: depth comes from tonal surface shifts, not 1px borders. Emphasis is applied via the Fenja rule — last keyword in Newsreader Bold Italic, followed by the absolute period. + +--- + +## How to ask for changes + +Pick a label from the tables above and tell me what you want changed. Examples: + +- *"Change **S1 lede** to say …"* +- *"Swap the colour of the **S4 arc** from terracotta to copper"* +- *"Remove **S5 stop 2** entirely; renumber the path"* +- *"Add a 5th item to the **S6 confirmation list**"* +- *"Reorder: move **S3 Words** to come after **S4 Bifrost Arc**"* +- *"Make the **P2 Europe map** fully fade out by 40% scroll instead of 80%"* +- *"Change the **Welcome title** to read differently when the user has no first name"* +- *"Update **P1 events** entry #14 (the November 2024 rupture) to say …"* + +If a change crosses multiple sections (for example, "add a fourth treasure map stop" or "reorganise the six scenes into five"), I'll lay out the pieces that need to move in a plan before writing code, so you can sign off. + +If something you want to change isn't on this map, quote a phrase from the site and I'll find it. + +--- + +## File index — where each label's code lives + +``` +protected/ +├── index.html [P1], [P2 except animations], [P3], shared chrome +├── timeline.js [P1 events + globe + card builder], [P3 table builder], +│ dot-nav logic + bifrost lazy-init +├── bifrost.js All [P2] scene animations + Europe map fade +├── vendor/ +│ ├── lenis.min.js Smooth scroll (for [P2]) +│ ├── gsap.min.js Animation engine +│ ├── scrolltrigger.min.js Scroll-bound timelines +│ ├── d3-array.min.js Globe math (used by timeline.js) +│ ├── d3-geo.min.js Globe projection +│ ├── topojson-client.min.js World topology parser +│ └── countries-110m.json World country shapes +└── fenja/ + ├── colors_and_type.css Design tokens + ├── fonts/ Manrope + Newsreader (variable fonts) + ├── fenja-wordmark-black.svg Logo — used by site-mark + S6 footer + └── illustrations/ + ├── community.svg S5 stop 1 + ├── council.svg S5 stop 2 + └── pilot.svg S5 stop 3 + +public/ +├── entrance.html Entrance + welcome steps (before login) +└── entrance.js Entrance form behaviour, welcome title logic + +src/ +├── auth.js /auth/login, /auth/logout, /auth/me +├── db.js SQLite schema + prepared queries +├── sessions.js Session cookie lifecycle +└── middleware.js rateLimit() + requireAuth() + +bin/ +└── invite.js CLI: add / remove / list invites + +server.js Entry point, CSP, routing +```