Editorial manifesto
Big statements gain contrast in sequence as --sv-t advances. Natural document flow, no pin and no split spans.
Less noise. More meaning.
We build things people want to spend time with.
Every detail should earn its place.
From the first idea to the final interaction. A small team, accountable for the whole experience.
// ScrollVars fx · editorial-manifesto
// Requires: npm i scrollvars · no preset stylesheet required
'use client'
import * as React from 'react'
import { Track } from 'scrollvars/react'
const css = `
.sv-manifesto { background: #e9e4db; color: #232722; padding: clamp(40px, 9vw, 128px) clamp(24px, 6vw, 88px); }
.sv-manifesto .manifesto-label { display: flex; justify-content: space-between; padding-bottom: 22px; border-bottom: 1px solid currentColor; font: 12px monospace; text-transform: uppercase; }
.sv-manifesto .manifesto-copy { padding-block: 32px; }
.sv-manifesto .manifesto-copy p { font-size: clamp(30px, 5.8vw, 82px); font-weight: 600; line-height: 1.08; letter-spacing: -.045em; margin: 0 0 .55em; }
.sv-on .sv-manifesto .manifesto-copy p { --read: clamp(0, calc(var(--sv-t, 1) * (var(--count) + 1) - var(--i)), 1); opacity: calc(.55 + .45 * var(--read)); } /* the floor keeps unread copy at 3:1 on this paper (axe, large text) */
.sv-manifesto .manifesto-end { max-width: 36ch; margin-left: auto; font-size: 16px; line-height: 1.6; }
[data-sv-off].sv-manifesto .manifesto-copy p { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .sv-on .sv-manifesto .manifesto-copy p { opacity: 1; } }
/* the same under html[data-sv-motion="reduce"], the site's own switch */
.sv-on:where([data-sv-motion="reduce"]) .sv-manifesto .manifesto-copy p { opacity: 1; }
`
export function EditorialManifesto({ label = 'What we believe', paragraphs, closing, className, nonce }: {
label?: string
paragraphs: string[]
closing?: string
className?: string
nonce?: string
}) {
return <Track as="section" travel className={className ? 'sv-manifesto ' + className : 'sv-manifesto'} style={{ '--count': paragraphs.length } as React.CSSProperties}>
<style nonce={nonce} dangerouslySetInnerHTML={{ __html: css }} />
<header className="manifesto-label"><span>{label}</span><span>Scroll to read ↓</span></header>
<div className="manifesto-copy">{paragraphs.map((text, i) => <p key={i} style={{ '--i': i } as React.CSSProperties}>{text}</p>)}</div>
{closing && <p className="manifesto-end">{closing}</p>}
</Track>
}