stack-scene: centered title, per-card counters, earlier anchor
- Stack title bar moves from top-left next to the site-mark to
centered at ~14vh so the title anchors visually to the cards
below. Font size bumped to clamp(2rem, 3.6vw, 3rem).
- Counter ("1 / 4 … 4 / 4") relocates from the title bar into
each .layer-card as a .card-counter element in the top-right of
each card-box. No longer driven by ScrollTrigger onUpdate —
each card carries its own number, so stacked + grid phases
both read correctly without JS. Grid phase shrinks the counter
so it doesn't compete with the per-cell label.
- SCENE_ANCHOR_OFFSET for stack-scene drops from 1800 back to 0,
so clicking the "Capabilities" dot lands at the top of the
pin — the title and first card come in together instead of
starting mid-stack.
Welcome step: the "desktop experience" aside and its CSS are
removed. Users now see only the two definitions before the CTA.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
43129717bf
commit
a2cbf57ce2
3 changed files with 49 additions and 106 deletions
|
|
@ -463,11 +463,6 @@
|
||||||
// to yPercent, so centering is preserved).
|
// to yPercent, so centering is preserved).
|
||||||
copyLayers.forEach(el => gsap.set(el, { yPercent: -50, opacity: 0, y: 20 }));
|
copyLayers.forEach(el => gsap.set(el, { yPercent: -50, opacity: 0, y: 20 }));
|
||||||
|
|
||||||
// Counter element in the stack-scene title bar. Updated on scroll to
|
|
||||||
// tick 1/4 → 4/4 as each card lands. Read inside the ScrollTrigger
|
|
||||||
// onUpdate below. Null-safe so missing markup doesn't break the scene.
|
|
||||||
const stackCounterEl = document.querySelector('#stack-counter .sc-current');
|
|
||||||
|
|
||||||
const stackTl = gsap.timeline({
|
const stackTl = gsap.timeline({
|
||||||
scrollTrigger: {
|
scrollTrigger: {
|
||||||
trigger: '#stack-scene',
|
trigger: '#stack-scene',
|
||||||
|
|
@ -478,22 +473,6 @@
|
||||||
pinSpacing: true,
|
pinSpacing: true,
|
||||||
anticipatePin: 1,
|
anticipatePin: 1,
|
||||||
invalidateOnRefresh: true,
|
invalidateOnRefresh: true,
|
||||||
// Drive the "N/4" counter in the title bar. Each card in Phase A
|
|
||||||
// occupies ~0.105 of the timeline (see cards.forEach below), so
|
|
||||||
// the Nth card is fully landed at roughly N * 0.105. We show the
|
|
||||||
// *current* card — i.e. the highest-index card that has started
|
|
||||||
// its fall. After Phase A completes (~0.42) we hold on 4/4.
|
|
||||||
onUpdate(self) {
|
|
||||||
if (!stackCounterEl) return;
|
|
||||||
const p = self.progress;
|
|
||||||
// Landing midpoints: card i (0-indexed) finishes at roughly
|
|
||||||
// i * 0.105 + 0.1. Use floor((p - 0.01) / 0.105) + 1 so the
|
|
||||||
// tick advances slightly after each card starts, then clamp.
|
|
||||||
const n = Math.min(4, Math.max(1, Math.floor(p / 0.105) + 1));
|
|
||||||
if (stackCounterEl.textContent !== String(n)) {
|
|
||||||
stackCounterEl.textContent = String(n);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1236,9 +1215,9 @@
|
||||||
// dot-nav button anchors to it, so the reader lands AFTER the scene's
|
// dot-nav button anchors to it, so the reader lands AFTER the scene's
|
||||||
// initial reveal rather than at an empty pre-scrub frame.
|
// initial reveal rather than at an empty pre-scrub frame.
|
||||||
//
|
//
|
||||||
// stack-scene — pin is 5000px long; Phase A (cards falling in) is
|
// stack-scene — offset 0 (top of the pin) so the reader lands right
|
||||||
// complete at ~0.42 of that (~2100px). 1800 lands just before the
|
// when the title appears and the first card starts its fall, and
|
||||||
// 4th card fully settles, so the reveal still has one tick to go.
|
// sees the full progression through all 4 landings.
|
||||||
//
|
//
|
||||||
// bifrost — section is 200vh with a scrubbed reveal that runs from
|
// bifrost — section is 200vh with a scrubbed reveal that runs from
|
||||||
// top-top to bottom-bottom (100vh scroll range). The sub-headline
|
// top-top to bottom-bottom (100vh scroll range). The sub-headline
|
||||||
|
|
@ -1251,7 +1230,6 @@
|
||||||
function getSceneAnchorOffset(sceneId) {
|
function getSceneAnchorOffset(sceneId) {
|
||||||
const vh = window.innerHeight;
|
const vh = window.innerHeight;
|
||||||
switch (sceneId) {
|
switch (sceneId) {
|
||||||
case 'stack-scene': return 1800;
|
|
||||||
case 'bifrost': return Math.round(vh * 0.85);
|
case 'bifrost': return Math.round(vh * 0.85);
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1072,52 +1072,30 @@ html {
|
||||||
|
|
||||||
/* ───────── Stack scene title bar ─────────
|
/* ───────── Stack scene title bar ─────────
|
||||||
Sits above the card theatre and rides with the pin so it remains
|
Sits above the card theatre and rides with the pin so it remains
|
||||||
visible through all four card landings and the grid rearrange. The
|
visible through all four card landings and the grid rearrange.
|
||||||
.sc-current token is updated from bifrost.js's ScrollTrigger onUpdate
|
Centered horizontally; positioned lower so the title anchors
|
||||||
— 1/4 → 4/4 — one tick per landing card.
|
visually to the cards below rather than floating at the top of
|
||||||
|
the viewport. Per-card counter (1/4, 2/4, …) now lives inside
|
||||||
Vertical top is aligned with the fixed .site-mark (top:28px) so
|
each .layer-card rather than being slaved to scroll progress. */
|
||||||
the title rides beside the wordmark at the very top of the scene,
|
|
||||||
floating horizontally at the same baseline. Horizontal padding on
|
|
||||||
the left is sized to clear the wordmark's right edge (~146px). */
|
|
||||||
.stack-title-bar {
|
.stack-title-bar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: clamp(1.25rem, 2.8vh, 1.85rem);
|
top: clamp(5.5rem, 14vh, 10rem);
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
display: flex;
|
text-align: center;
|
||||||
justify-content: space-between;
|
padding-inline: clamp(1rem, 4vw, 3rem);
|
||||||
align-items: baseline;
|
|
||||||
gap: 1.5rem;
|
|
||||||
padding-left: clamp(10rem, 12vw, 12rem);
|
|
||||||
padding-right: clamp(0.75rem, 2vw, 2.25rem);
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.stack-title {
|
.stack-title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: "Newsreader", Georgia, serif;
|
font-family: "Newsreader", Georgia, serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: clamp(1.4rem, 2.6vw, 2.2rem);
|
font-size: clamp(2rem, 3.6vw, 3rem);
|
||||||
letter-spacing: -0.01em;
|
letter-spacing: -0.015em;
|
||||||
line-height: 1.2;
|
line-height: 1.12;
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
}
|
}
|
||||||
.stack-counter {
|
|
||||||
font-family: "Newsreader", Georgia, serif;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: clamp(1.1rem, 2vw, 1.6rem);
|
|
||||||
color: var(--ink-soft);
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.stack-counter .sc-current {
|
|
||||||
color: var(--accent);
|
|
||||||
font-weight: 600;
|
|
||||||
transition: color 180ms var(--ease);
|
|
||||||
}
|
|
||||||
.stack-counter .sc-sep,
|
|
||||||
.stack-counter .sc-total { color: var(--ink-soft); }
|
|
||||||
|
|
||||||
/* LEFT COPY (visible only during grid phase) */
|
/* LEFT COPY (visible only during grid phase) */
|
||||||
.copy-stage {
|
.copy-stage {
|
||||||
|
|
@ -1302,6 +1280,32 @@ html {
|
||||||
z-index: 2;
|
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 {
|
.in-grid .card-box {
|
||||||
/* 15% reduction from the original 20vw — matches the drop-phase shrink.
|
/* 15% reduction from the original 20vw — matches the drop-phase shrink.
|
||||||
Also matches cellSize and targetW in bifrost.js (both are vw * 0.17). */
|
Also matches cellSize and targetW in bifrost.js (both are vw * 0.17). */
|
||||||
|
|
@ -2485,13 +2489,11 @@ html {
|
||||||
<section id="stack-scene" aria-label="The Fenja AI architecture">
|
<section id="stack-scene" aria-label="The Fenja AI architecture">
|
||||||
<div class="stack-pin">
|
<div class="stack-pin">
|
||||||
<!-- Title bar: rides along with the pin so it stays visible while
|
<!-- Title bar: rides along with the pin so it stays visible while
|
||||||
the reader scrolls through all 4 capability cards. The counter
|
the reader scrolls through all 4 capability cards. The per-card
|
||||||
ticks 1/4 → 4/4 as each layer lands (driven from bifrost.js). -->
|
counter now lives inside each .layer-card (see .card-counter
|
||||||
|
below), so the title here is a standalone centered lockup. -->
|
||||||
<div class="stack-title-bar" aria-hidden="true">
|
<div class="stack-title-bar" aria-hidden="true">
|
||||||
<h2 class="stack-title">The Fenja AI platform in four steps</h2>
|
<h2 class="stack-title">The Fenja AI platform in four steps</h2>
|
||||||
<span class="stack-counter" id="stack-counter">
|
|
||||||
<span class="sc-current">1</span><span class="sc-sep">/</span><span class="sc-total">4</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="layer-theatre">
|
<div class="layer-theatre">
|
||||||
|
|
||||||
|
|
@ -2518,6 +2520,7 @@ html {
|
||||||
<article class="layer-card" data-layer="0" aria-label="Layer 1: the AI">
|
<article class="layer-card" data-layer="0" aria-label="Layer 1: the AI">
|
||||||
<span class="card-eyebrow">The AI</span>
|
<span class="card-eyebrow">The AI</span>
|
||||||
<div class="card-box">
|
<div class="card-box">
|
||||||
|
<span class="card-counter" aria-hidden="true">1 / 4</span>
|
||||||
<span class="card-grid-label" aria-hidden="true">The AI</span>
|
<span class="card-grid-label" aria-hidden="true">The AI</span>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<h3 class="card-title">An <b>open-source</b> model, running on your <em>own hardware.</em></h3>
|
<h3 class="card-title">An <b>open-source</b> model, running on your <em>own hardware.</em></h3>
|
||||||
|
|
@ -2530,6 +2533,7 @@ html {
|
||||||
<article class="layer-card" data-layer="1" aria-label="Layer 2: Knowledge">
|
<article class="layer-card" data-layer="1" aria-label="Layer 2: Knowledge">
|
||||||
<span class="card-eyebrow">The Knowledge</span>
|
<span class="card-eyebrow">The Knowledge</span>
|
||||||
<div class="card-box">
|
<div class="card-box">
|
||||||
|
<span class="card-counter" aria-hidden="true">2 / 4</span>
|
||||||
<span class="card-grid-label" aria-hidden="true">The Knowledge</span>
|
<span class="card-grid-label" aria-hidden="true">The Knowledge</span>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<h3 class="card-title">The business context that makes <em>AI understand your world.</em></h3>
|
<h3 class="card-title">The business context that makes <em>AI understand your world.</em></h3>
|
||||||
|
|
@ -2542,6 +2546,7 @@ html {
|
||||||
<article class="layer-card" data-layer="2" aria-label="Layer 3: Tools">
|
<article class="layer-card" data-layer="2" aria-label="Layer 3: Tools">
|
||||||
<span class="card-eyebrow">The Tools</span>
|
<span class="card-eyebrow">The Tools</span>
|
||||||
<div class="card-box">
|
<div class="card-box">
|
||||||
|
<span class="card-counter" aria-hidden="true">3 / 4</span>
|
||||||
<span class="card-grid-label" aria-hidden="true">The Tools</span>
|
<span class="card-grid-label" aria-hidden="true">The Tools</span>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<h3 class="card-title">How AI <b>acts</b> — not just what it <em>knows.</em></h3>
|
<h3 class="card-title">How AI <b>acts</b> — not just what it <em>knows.</em></h3>
|
||||||
|
|
@ -2554,6 +2559,7 @@ html {
|
||||||
<article class="layer-card" data-layer="3" aria-label="Layer 4: Agents">
|
<article class="layer-card" data-layer="3" aria-label="Layer 4: Agents">
|
||||||
<span class="card-eyebrow">The Agents</span>
|
<span class="card-eyebrow">The Agents</span>
|
||||||
<div class="card-box">
|
<div class="card-box">
|
||||||
|
<span class="card-counter" aria-hidden="true">4 / 4</span>
|
||||||
<span class="card-grid-label" aria-hidden="true">The Agents</span>
|
<span class="card-grid-label" aria-hidden="true">The Agents</span>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<h3 class="card-title">Specialized AI agents <b>working together</b> around <em>real tasks.</em></h3>
|
<h3 class="card-title">Specialized AI agents <b>working together</b> around <em>real tasks.</em></h3>
|
||||||
|
|
|
||||||
|
|
@ -211,39 +211,6 @@
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Practical viewing-experience note. Lives between the definitions
|
|
||||||
and the CTA so readers see it before committing to "Learn more".
|
|
||||||
Left-bordered callout in the editorial voice — same Newsreader as
|
|
||||||
the surrounding copy, tempered colour so it reads as guidance not
|
|
||||||
body text. */
|
|
||||||
.welcome-note {
|
|
||||||
max-width: 620px;
|
|
||||||
margin: 22px 0 8px 0;
|
|
||||||
padding: 14px 18px;
|
|
||||||
border-left: 3px solid var(--crimson);
|
|
||||||
background: rgba(138, 58, 47, 0.04);
|
|
||||||
font-family: "Newsreader", Georgia, "Times New Roman", serif;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 17px;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
.welcome-note strong {
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
.welcome-note em {
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
color: var(--crimson);
|
|
||||||
}
|
|
||||||
.welcome-note p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.welcome-note p + p {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.welcome-cta {
|
.welcome-cta {
|
||||||
all: unset;
|
all: unset;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
@ -378,14 +345,6 @@
|
||||||
<h3 class="welcome-term"><em>Project Bifrost</em></h3>
|
<h3 class="welcome-term"><em>Project Bifrost</em></h3>
|
||||||
<p class="welcome-def">The initiative created to ensure that Fenja AI is built not just for organisations like yours, but <em>with</em> you.</p>
|
<p class="welcome-def">The initiative created to ensure that Fenja AI is built not just for organisations like yours, but <em>with</em> you.</p>
|
||||||
</div>
|
</div>
|
||||||
<aside class="welcome-note" aria-label="Viewing recommendation">
|
|
||||||
<p>
|
|
||||||
This site is a <strong>desktop experience</strong>. It showcases many of the capabilities of our products, and is therefore not optimised for mobile — we recommend viewing it on a <em>desktop screen</em>.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Be mindful of the scrolling experience: <em>scroll gently</em> so you don’t accidentally pass over a section before it finishes animating.
|
|
||||||
</p>
|
|
||||||
</aside>
|
|
||||||
<button type="button" class="welcome-cta" id="welcome-continue">
|
<button type="button" class="welcome-cta" id="welcome-continue">
|
||||||
<svg class="c-icon" width="20" height="20" viewBox="0 0 24 24" fill="none"
|
<svg class="c-icon" width="20" height="20" viewBox="0 0 24 24" fill="none"
|
||||||
stroke="currentColor" stroke-width="1.3"
|
stroke="currentColor" stroke-width="1.3"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue