Neighborhood Insights

Internal reference · Design system v2

Brand Handbook

Bold/Geometric + Sparse/Authoritative. Typography-driven authority, confident whitespace, colors as accents — not backgrounds. This is the single source of truth for every design decision.

51.7519° N  1.2578° W

Design Philosophy

Core direction

  • Typography-driven authority

    Georgia serif headings do the heavy lifting. Bold type at scale creates authority without decorative chrome.

  • Confident whitespace

    Breathing room is intentional. Sections breathe at py-12 and never stack without a hairline pause.

  • Colors as accents

    Full-color backgrounds are used in exactly two places: blue (positioning band + CTA section) and tea-green (How We Work + quote bands). Everything else sits on ivory.

  • Distinctive, not corporate

    This is not a consulting firm. No deck aesthetic, no lucide icon grids. The design should feel direct and editorial.

Anti-patterns — never use these

  • ×Pill / oval tags (rounded-full badges)
  • ×Card grids with box-shadow
  • ×Wave SVGs or decorative shape dividers
  • ×Full-color section backgrounds (outside blue & green exceptions)
  • ×Lucide icons anywhere on the site
  • ×container mx-auto px-4 layout wrapper

Note: MagneticButton on the homepage does use rounded-full because the CTA pill is a deliberate editorial contrast against the otherwise rectilinear system. Hero CTA buttons also use rounded-full. Internal UI components (capability cards, border bars) remain sharp-cornered.

Brand Colors

Brand Blue

#0047bb · brand-blue
  • Positioning band (full-width section below hero)
  • Final CTA section background on all pages
  • Angled blue edge element bleeding from hero footer
  • Accent top border (6px) on capability cards
  • Left-border bars on credibility items (cycles with tangerine, tea-green)
  • Quote band left-border accent inside tea-green sections
  • MagneticButton hover background

Brand Ivory

#fffff2 · brand-ivory
  • Default background for ALL non-accent sections
  • Text and button color on dark/blue surfaces
  • Hero primary CTA button background (hovers to tangerine)

Brand Tea Green

#c6d8af · brand-tea-green
  • How We Work section on homepage — parallelogram shape
  • Mid-page quote/insight band on inner pages (flat, no clip-path)
  • Section label hairline rule (capabilities): rgba(198,216,175,0.6)
  • Left-border bar accent (third item in color cycling pattern)
  • Top border on every third capability card
  • Image frame border: rgba(198,216,175,0.3)

Brand Tangerine

#fca17d · brand-tangerine
  • Ticker / marquee band background
  • MagneticButton default background
  • Inner page CTA primary button (style={{ backgroundColor: '#fca17d' }})
  • Left-border bar accent (second item in cycling pattern)
  • Top border on second capability card
  • Cursor spotlight on hero: rgba(252,161,125,0.09)
  • Hero h1 left-border accent on some inner pages

Brand Black

#000000 · brand-black
  • All body text on ivory backgrounds
  • MagneticButton and CTA button text on tangerine backgrounds
  • Ticker item text

Typography

Headings — Georgia serif, bold

h1

Heading One

{/* Homepage hero — slightly larger */}
<h1 className="text-4xl md:text-5xl lg:text-6xl font-serif font-bold leading-tight"
    style={{ color: "#fffff2" }}>

{/* Inner page heroes — on ivory with left accent */}
<div style={{ borderLeft: "3px solid #fca17d" }} className="pl-3 mb-8">
  <h1 className="text-4xl md:text-5xl font-serif font-bold text-brand-black leading-tight">
    Page title here.
  </h1>
</div>
h2

Heading Two

<h2 className="text-2xl md:text-3xl font-serif font-bold text-brand-black">
h3

Heading Three

<h3 className="font-serif font-bold text-base leading-snug text-brand-black">

Body text — opacity hierarchy

Primary body: 70% opacity. Used for main prose content on ivory backgrounds.

Secondary body: 65% opacity. Used in How We Work step bodies, team section, and some inner-page copy.

Small / supporting: text-xs at 60% opacity. Used in credibility border-bar bodies, capability card descriptions (0.58), and dense data contexts.

{/* Primary body — ivory background */}
<p className="text-sm leading-relaxed" style={{ color: "rgba(0,0,0,0.70)" }}>

{/* Secondary body — slightly dimmer */}
<p className="text-sm leading-relaxed" style={{ color: "rgba(0,0,0,0.65)" }}>

{/* Small supporting — border-bar detail text */}
<p className="text-xs leading-snug" style={{ color: "rgba(0,0,0,0.60)" }}>

{/* Capability card desc — just slightly more transparent */}
<p className="text-sm leading-relaxed" style={{ color: "rgba(0,0,0,0.58)" }}>

{/* On dark/blue surfaces */}
<p className="text-sm leading-relaxed" style={{ color: "rgba(255,255,242,0.70)" }}>
<p className="text-lg leading-relaxed" style={{ color: "rgba(255,255,242,0.80)" }}>

Section labels — eyebrow annotations

About Us

What we do

{/* Inner page heroes and section headings — text-[10px] */}
<p className="text-[10px] font-bold tracking-widest uppercase mb-6"
   style={{ color: "rgba(0,0,0,0.35)" }}>
  About Us
</p>

{/* Homepage section labels — text-[8px] */}
<p className="text-[8px] font-bold tracking-widest uppercase"
   style={{ color: "rgba(0,0,0,0.35)" }}>
  What we do
</p>

{/* Label + tea-green hairline rule — capabilities section */}
<div className="flex items-center gap-4 mb-8">
  <span className="text-xs font-bold tracking-widest uppercase text-black/35 whitespace-nowrap">
    What we do
  </span>
  <div className="flex-1 h-px" style={{ backgroundColor: "rgba(198,216,175,0.6)" }} />
</div>

{/* On blue surfaces */}
<p className="text-[10px] font-bold tracking-widest uppercase mb-5"
   style={{ color: "rgba(255,255,242,0.45)" }}>
  Work with us
</p>

Never use a label as a pill/badge. No rounded-full on labels.

Ghost numbers — decorative counters

{/* Page-level section heading (48px, 8% opacity) */}
<span
  className="font-serif font-bold leading-none select-none"
  style={{ fontSize: "48px", color: "rgba(0,0,0,0.08)" }}
  aria-hidden="true"
>
  01
</span>

{/* In-grid item number (36px, 8% opacity) — capabilities, philosophy lists */}
<div
  className="font-serif font-bold select-none mb-3 leading-none"
  style={{ fontSize: "36px", color: "rgba(0,0,0,0.08)" }}
>
  01
</div>

{/* How We Work steps — 36px but at 18% for tea-green contrast */}
<div
  className="font-serif font-bold select-none mb-1"
  style={{ fontSize: "36px", color: "rgba(0,0,0,0.18)", lineHeight: 1 }}
>
  01
</div>

Mono — technical annotations only

51.7519° N  1.2578° W

{/* Easter egg — 28% ivory opacity on dark hero background */}
<p className="font-mono text-[9px] tracking-widest"
   style={{ color: "rgba(255,255,242,0.28)" }}>
  51.7519° N&nbsp;&nbsp;1.2578° W
</p>

{/* Metadata / hex annotations — 45% opacity on ivory */}
<code className="font-mono text-[9px]" style={{ color: "rgba(0,0,0,0.45)" }}>
  #0047bb · brand-blue
</code>

Layout Patterns

Section padding — full width, no container

All sections span full width. No container mx-auto or px-4. Horizontal padding scales with breakpoint. Vertical padding varies by section type.

{/* Standard content section */}
<section className="bg-brand-ivory px-8 md:px-14 lg:px-20 py-12">

{/* Inner page hero */}
<section className="bg-brand-ivory px-8 md:px-14 lg:px-20 pt-20 pb-16">

{/* Credibility section — extra vertical breathing room */}
<section className="bg-brand-ivory px-8 md:px-14 lg:px-20 py-16">

{/* Blue CTA — inner pages */}
<section className="px-8 md:px-14 lg:px-20 py-16" style={{ backgroundColor: "#0047bb" }}>

{/* Final CTA — homepage (larger, centered) */}
<section
  className="relative py-24 px-8 md:px-14 lg:px-20 text-center overflow-hidden"
  style={{ backgroundColor: "#0047bb" }}
>

Inner page hero — standard pattern

Every inner page (About, What We Do, etc.) opens with an ivory hero that has pt-20 pb-16, a small eyebrow label, and an h1 wrapped in a left accent bar. The accent color varies by page.

<section className="bg-brand-ivory px-8 md:px-14 lg:px-20 pt-20 pb-16">
  <div className="max-w-3xl">
    {/* Eyebrow label — fades in first */}
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.6, delay: 0.1, ease: [0.22, 1, 0.36, 1] }}
    >
      <p className="text-[10px] font-bold tracking-widest uppercase mb-6"
         style={{ color: "rgba(0,0,0,0.35)" }}>
        About Us
      </p>
    </motion.div>

    {/* h1 with left accent bar — delay 0.2 */}
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.6, delay: 0.2, ease: [0.22, 1, 0.36, 1] }}
    >
      <div style={{ borderLeft: "3px solid #fca17d" }} className="pl-3 mb-8">
        <h1 className="text-4xl md:text-5xl font-serif font-bold text-brand-black leading-tight">
          Page headline here.
        </h1>
      </div>
    </motion.div>

    {/* Intro paragraph — delay 0.3 */}
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.6, delay: 0.3, ease: [0.22, 1, 0.36, 1] }}
    >
      <p className="text-sm leading-relaxed max-w-2xl"
         style={{ color: "rgba(0,0,0,0.70)" }}>
        Supporting paragraph text.
      </p>
    </motion.div>
  </div>
</section>

Page section sequence — inner pages

Every inner page follows this sequence. The tea-green band and blue CTA are not optional.

  1. [1]Inner page hero (ivory, pt-20 pb-16, eyebrow + h1 with left accent)
  2. [2]Hairline divider (h-px, rgba(0,0,0,0.08))
  3. [3]Content sections (ivory, py-12) — as many as needed, each separated by hairlines
  4. [4]Tea-green quote/insight band (py-12, flat — no clip-path on inner pages)
  5. [5]More content sections if needed
  6. [6]Blue CTA section (py-16) — always last before footer

Left border bars — data and credibility items

Technical depth

Supporting detail text.

Strategic range

Supporting detail text.

Honest scoping

Supporting detail text.

// Cycling color pattern — blue → tangerine → tea-green → repeat
const ACCENT_COLORS = ["#0047bb", "#fca17d", "#c6d8af"]

{ITEMS.map(({ label, body }, i) => (
  <div
    key={label}
    className="pl-3"
    style={{ borderLeft: `3px solid ${ACCENT_COLORS[i % 3]}` }}
  >
    <p className="font-serif font-bold text-sm text-brand-black mb-1">{label}</p>
    <p className="text-xs leading-snug" style={{ color: "rgba(0,0,0,0.60)" }}>{body}</p>
  </div>
))}

{/* Single-color variant (background items on About page — all tea-green) */}
<div className="py-5 pl-3" style={{ borderLeft: "3px solid #c6d8af" }}>

{/* Quote band left border on tea-green background — pl-4 instead of pl-3 */}
<div className="max-w-3xl" style={{ borderLeft: "3px solid #0047bb" }}>
  <p className="pl-4 text-2xl md:text-3xl font-serif font-bold italic leading-snug">
    "Quote text here."
  </p>
</div>

Hairline rules — section dividers

{/* Standard section divider — used between every section on inner pages */}
<div className="h-px w-full" style={{ backgroundColor: "rgba(0,0,0,0.08)" }} />

{/* Same but as inline style on a wrapping div (also common) */}
<div className="h-px" style={{ backgroundColor: "rgba(0,0,0,0.08)" }} />

{/* Within-section hairline — between list items or subsections */}
{i < ITEMS.length - 1 && (
  <div className="h-px" style={{ backgroundColor: "rgba(0,0,0,0.08)" }} />
)}

{/* How We Work footer rule — inside tea-green band */}
<div className="mt-6 pt-3" style={{ borderTop: "1px solid rgba(0,0,0,0.10)" }} />

Content max-widths — constrain prose, not sections

{/* Body copy — tightest constraint */}
<p className="max-w-2xl ...">

{/* Wider prose blocks and quote bands */}
<div className="max-w-3xl ...">

{/* Inner page hero text area */}
<div className="max-w-3xl">

{/* Grid content (capabilities, philosophy) */}
<div className="max-w-4xl ...">

{/* Blue CTA inner pages — left-aligned */}
<div className="max-w-2xl">

{/* Homepage hero — spans left side */}
<div className="px-8 md:px-14 lg:px-20 max-w-3xl">

Grid patterns — common column layouts

{/* 2-col: text + media (origin / credibility sections) */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-14 items-center">

{/* 2-col: text + items (credibility) */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 relative z-[1] items-center">

{/* Ghost number + content — used in philosophy and section headings */}
<div className="py-6 grid gap-4" style={{ gridTemplateColumns: "56px 1fr" }}>

{/* Capabilities — 3×2 grid with border dividers */}
<div
  className="grid grid-cols-1 md:grid-cols-2 relative"
  style={{ border: "1px solid rgba(0,0,0,0.07)" }}
>

{/* How We Work steps — 3-col on md+ */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 max-w-4xl w-full">

How We Work — tea-green parallelogram (homepage only)

The only section using clip-path. Negative margins pull it into adjacent ivory sections; clip-path creates the angled top and bottom edges. z-10 ensures it sits above its neighbors. Inner pages use a flat tea-green band instead.

{/* Homepage only — parallelogram shape */}
<section
  className="bg-brand-tea-green px-8 md:px-14 lg:px-20 flex flex-col items-center relative z-10"
  style={{
    marginTop: "-44px",
    marginBottom: "-32px",
    paddingTop: "calc(2.5rem + 44px)",
    paddingBottom: "calc(2.5rem + 32px)",
    clipPath: "polygon(0 0, 100% 44px, 100% calc(100% - 32px), 0 100%)",
  }}
>

{/* Inner pages — flat tea-green band, no clip-path */}
<section
  className="px-8 md:px-14 lg:px-20 py-12"
  style={{ backgroundColor: "#c6d8af" }}
>

Dot-grid texture — decorative overlay on blue sections

Used in both the homepage hero and the final CTA section. Always pointer-events-none and absolute inset-0. Dot opacity and grid size differ slightly between the two contexts.

{/* Hero — 8% ivory dots, 28px grid */}
<div
  className="absolute inset-0 z-[1] pointer-events-none"
  style={{
    backgroundImage: "radial-gradient(rgba(255,255,242,0.08) 1px, transparent 1px)",
    backgroundSize: "28px 28px",
  }}
/>

{/* Final CTA — 7% ivory dots, 22px grid */}
<div
  className="absolute inset-0 pointer-events-none"
  style={{
    backgroundImage: "radial-gradient(rgba(255,255,242,0.07) 1px, transparent 1px)",
    backgroundSize: "22px 22px",
  }}
/>

Buttons & Links

Homepage hero CTAs — rounded-full pair

Only context where non-magnetic buttons use rounded-full. Primary is ivory (hovers to tangerine). Secondary is an outline ghost. Both are pills.

{/* Primary */}
<Button size="lg" className="rounded-full px-8 bg-brand-ivory text-brand-black
  hover:bg-brand-tangerine transition-colors duration-300 w-full sm:w-auto font-medium">
  Start a Conversation
</Button>

{/* Secondary outline */}
<Button
  variant="outline"
  size="lg"
  className="rounded-full px-8 border-brand-ivory text-brand-ivory
    hover:bg-brand-ivory hover:text-brand-black bg-transparent
    transition-colors duration-300 w-full sm:w-auto font-medium"
>
  What We Do
</Button>

Inner page CTA buttons — sharp corners on blue backgrounds

On blue CTA sections, the primary button uses tangerine fill with text-brand-black. No rounded-full. Secondary is a ghost outline. Both use Reveal wrappers with staggered delays.

{/* Primary — tangerine with black text */}
<Button
  size="lg"
  className="px-8 text-brand-black font-medium transition-colors duration-300 w-full sm:w-auto"
  style={{ backgroundColor: "#fca17d" }}
>
  Start a Conversation
</Button>

{/* Secondary — ghost outline, ivory text */}
<Button
  variant="outline"
  size="lg"
  className="px-8 font-medium transition-colors duration-300 w-full sm:w-auto"
  style={{
    backgroundColor: "transparent",
    border: "1px solid rgba(255,255,242,0.35)",
    color: "#fffff2",
  }}
>
  See Our Work
</Button>

Inline links — text only, underline offset

{/* On ivory — blue text with underline */}
<Link
  href="/what-we-do"
  className="text-sm font-semibold text-brand-blue underline underline-offset-4
    hover:text-brand-tangerine transition-colors"
>
  Explore all capabilities →
</Link>

{/* On tea-green — subdued, no color */}
<Link
  href="/approach"
  className="text-xs underline underline-offset-4 hover:text-brand-blue transition-colors"
  style={{ color: "rgba(0,0,0,0.45)" }}
>
  Our full approach →
</Link>

Animation System

Reveal — shared scroll-triggered component

Import from @/components/reveal for all inner pages. Supports delay for stagger and direction for slide-in axis. The homepage defines its own local Reveal in ClientPage.tsx — functionally the same.

// components/reveal.tsx
"use client"
import { motion } from "framer-motion"

interface RevealProps {
  children: React.ReactNode
  className?: string
  delay?: number
  direction?: "up" | "left" | "right"
}

export function Reveal({ children, className, delay = 0, direction = "up" }: RevealProps) {
  const initial =
    direction === "left"  ? { opacity: 0, x: -20 }
    : direction === "right" ? { opacity: 0, x: 20 }
    : { opacity: 0, y: 20 }

  return (
    <motion.div
      className={className}
      initial={initial}
      whileInView={{ opacity: 1, x: 0, y: 0 }}
      viewport={{ once: true, amount: 0.15 }}
      transition={{ duration: 0.55, delay, ease: [0.22, 1, 0.36, 1] }}
    >
      {children}
    </motion.div>
  )
}

// Usage — stagger by mapping with delay={i * 0.08}
{ITEMS.map((item, i) => (
  <Reveal key={item.label} delay={i * 0.08}>
    {/* item content */}
  </Reveal>
))}

Hero load animation — animate on mount, not on scroll

Both homepage and inner page heroes use animate (fires on mount), not whileInView. Standard delay stagger: eyebrow at 0.1s, h1 at 0.2s, body at 0.3s, CTA at 0.4s.

{/* Eyebrow label — delay 0.1 */}
<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
  transition={{ duration: 0.6, delay: 0.1, ease: [0.22, 1, 0.36, 1] }}
>

{/* h1 — delay 0.2 */}
<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
  transition={{ duration: 0.6, delay: 0.2, ease: [0.22, 1, 0.36, 1] }}
>

{/* Body paragraph — delay 0.3 */}
<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
  transition={{ duration: 0.6, delay: 0.3, ease: [0.22, 1, 0.36, 1] }}
>

{/* CTA row — delay 0.4 (homepage) */}
<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
  transition={{ duration: 0.7, delay: 0.4, ease: [0.22, 1, 0.36, 1] }}
>

Stagger — per-item delay in mapped lists

Three stagger patterns in use. The standard is i * 0.08 for dense lists. Capabilities uses column-modulo to avoid over-delaying bottom rows. Credibility slides in from right instead of up.

{/* Dense lists (philosophy, background items) — delay={i * 0.08} via Reveal */}
<Reveal key={item.label} delay={i * 0.08}>

{/* How We Work steps — delay: i * 0.1 */}
transition={{ duration: 0.55, delay: i * 0.1, ease: [0.22, 1, 0.36, 1] }}

{/* Capabilities grid — stagger by column only, prevents runaway delay on row 3 */}
transition={{ duration: 0.5, delay: (i % 2) * 0.08, ease: [0.22, 1, 0.36, 1] }}

{/* Credibility items — slide in from right */}
initial={{ opacity: 0, x: 24 }}
whileInView={{ opacity: 1, x: 0 }}
transition={{ duration: 0.55, delay: i * 0.1, ease: [0.22, 1, 0.36, 1] }}

{/* CTA section on blue — Reveal wrappers with explicit delays */}
<Reveal delay={0.08}> {/* h2 */}
<Reveal delay={0.16}> {/* body */}
<Reveal delay={0.24}> {/* button row */}

Capabilities grid — animated divider lines

The gridlines in the capabilities section are Framer Motion elements that scale in from zero on scroll. The vertical line scales on Y (top origin), horizontal lines scale on X (left origin).

{/* Animated vertical divider — scales from top */}
<motion.div
  className="hidden md:block absolute top-0 bottom-0 pointer-events-none"
  style={{ left: "50%", width: "1px", backgroundColor: "rgba(0,0,0,0.07)", transformOrigin: "top" }}
  initial={{ scaleY: 0 }}
  whileInView={{ scaleY: 1 }}
  viewport={{ once: true, amount: 0.1 }}
  transition={{ duration: 0.7, ease: [0.22, 1, 0.36, 1] }}
/>

{/* Animated horizontal dividers at 33.33% and 66.66% — scales from left */}
{[33.33, 66.66].map((pct) => (
  <motion.div
    key={pct}
    className="absolute left-0 right-0 pointer-events-none"
    style={{ top: `${pct}%`, height: "1px", backgroundColor: "rgba(0,0,0,0.07)", transformOrigin: "left" }}
    initial={{ scaleX: 0 }}
    whileInView={{ scaleX: 1 }}
    viewport={{ once: true, amount: 0.1 }}
    transition={{ duration: 0.7, delay: 0.1, ease: [0.22, 1, 0.36, 1] }}
  />
))}

Capabilities hover — accent bar scales from top

Each capability card uses whileHover="hovered" on the outer motion.div, with a child that responds via variants. The accent bar matches the card's top-border color.

<motion.div
  whileHover="hovered"
  className="p-6 relative overflow-hidden"
  style={{ borderTop: `6px solid ${accent}` }}
>
  {/* Accent bar — scaleY from 0 at top on hover */}
  <motion.div
    variants={{ hovered: { scaleY: 1 }, initial: { scaleY: 0 } }}
    initial="initial"
    className="absolute left-0 top-0 bottom-0 pointer-events-none"
    style={{ width: "3px", backgroundColor: accent, transformOrigin: "top" }}
    transition={{ duration: 0.3, ease: [0.22, 1, 0.36, 1] }}
  />
  {/* card content */}
</motion.div>

Hero parallax image — useScroll + useTransform

const heroRef = useRef<HTMLElement>(null)
const { scrollYProgress } = useScroll({ target: heroRef, offset: ["start start", "end start"] })
const parallaxY = useTransform(scrollYProgress, [0, 1], [0, 80])

{/* Image wrapper — scale: 1.1 prevents white edges as it shifts */}
<motion.div style={{ y: parallaxY, scale: 1.1 }} className="absolute inset-0">
  <Image src="/images/hero-cityscape.jpg" fill className="object-cover" priority />
</motion.div>

Cursor spotlight — hero tangerine radial gradient

Mouse offset is smoothed with useSpring (stiffness 80, damping 20) before being fed into a useMotionTemplate gradient. Initial position is off-screen (-600, -600) so no glow shows until the cursor enters.

const mouseX = useMotionValue(-600)
const mouseY = useMotionValue(-600)
const smoothX = useSpring(mouseX, { stiffness: 80, damping: 20 })
const smoothY = useSpring(mouseY, { stiffness: 80, damping: 20 })
const spotlightBg = useMotionTemplate`radial-gradient(520px circle at ${smoothX}px ${smoothY}px, rgba(252,161,125,0.09), transparent 70%)`

{/* Overlay — z-[1], pointer-events-none */}
<motion.div
  className="absolute inset-0 z-[1] pointer-events-none"
  style={{ background: spotlightBg }}
/>

MagneticButton — spring cursor tracking

35% lerp on mouse offset. Springs: stiffness 300, damping 25. Used only on the homepage final CTA. The button is rounded-full — one of only two deliberate pill shapes in the system (the other being the hero CTA pair).

function MagneticButton({ children, href }: { children: React.ReactNode; href: string }) {
  const ref = useRef<HTMLDivElement>(null)
  const x = useMotionValue(0)
  const y = useMotionValue(0)
  const springX = useSpring(x, { stiffness: 300, damping: 25 })
  const springY = useSpring(y, { stiffness: 300, damping: 25 })

  const handleMouseMove = (e: React.MouseEvent) => {
    const rect = ref.current?.getBoundingClientRect()
    if (!rect) return
    x.set((e.clientX - (rect.left + rect.width / 2)) * 0.35)  // 35% lerp
    y.set((e.clientY - (rect.top + rect.height / 2)) * 0.35)
  }

  return (
    <motion.div
      ref={ref}
      style={{ x: springX, y: springY, display: "inline-block" }}
      onMouseMove={handleMouseMove}
      onMouseLeave={() => { x.set(0); y.set(0) }}
    >
      <Link href={href}>
        <Button size="lg" className="rounded-full px-10 py-6 text-base font-semibold
          bg-brand-tangerine text-brand-black hover:bg-brand-blue hover:text-brand-ivory
          transition-colors duration-300">
          {children}
        </Button>
      </Link>
    </motion.div>
  )
}

Ticker band — Framer Motion infinite scroll

Uses animate: x: ["0%", "-50%"] rather than a CSS keyframe. Items are duplicated once (2 copies) for a seamless loop. The pinned label does not scroll — it sits outside the motion track. Duration: 28s.

<section className="overflow-hidden py-3" style={{ backgroundColor: "#fca17d" }}>
  <div className="flex items-baseline gap-6 whitespace-nowrap">
    {/* Pinned label — not scrolling */}
    <span
      className="pl-8 md:pl-14 lg:pl-20 text-[8px] font-bold tracking-widest uppercase shrink-0"
      style={{ color: "rgba(0,0,0,0.42)" }}
    >
      Active focus areas
    </span>
    {/* Scrolling track */}
    <div className="relative flex overflow-hidden">
      <motion.div
        className="flex gap-8 shrink-0"
        animate={{ x: ["0%", "-50%"] }}
        transition={{ duration: 28, ease: "linear", repeat: Infinity }}
      >
        {[...Array(2)].map((_, rep) => (
          <span key={rep} className="flex gap-8 shrink-0 text-xs" style={{ color: "rgba(0,0,0,0.70)" }}>
            {ITEMS.map((item) => (
              <span key={item} className="shrink-0">
                {item}<span className="mx-4" style={{ color: "rgba(0,0,0,0.30)" }}>·</span>
              </span>
            ))}
          </span>
        ))}
      </motion.div>
    </div>
  </div>
</section>

Homepage Composition

Hero — layer stack (bottom to top)

Height: clamp(560px, 80vh, 760px).

  • [1]Parallax image (scale 1.1, y from useScroll → useTransform)
  • [2]Gradient overlay: 105deg, rgba(0,0,0,0.88) → rgba(0,0,0,0.65) → rgba(0,71,187,0.30)
  • [3]Cursor spotlight: z-[1], pointer-events-none
  • [4]Dot-grid texture: z-[1], pointer-events-none, 28px grid
  • [5]Text content: z-[2], absolute inset-0 flex items-center
  • [6]Coordinate easter egg: z-[2], absolute bottom-14 right-8 md:right-14 lg:right-20
  • [7]Angled blue edge: z-[2], absolute bottom-0, height 48px
<section
  ref={heroRef}
  className="relative w-full overflow-hidden"
  style={{ height: "clamp(560px, 80vh, 760px)" }}
  onMouseMove={handleHeroMouseMove}
  onMouseLeave={handleHeroMouseLeave}
>
  {/* [1] Parallax image */}
  <motion.div style={{ y: parallaxY, scale: 1.1 }} className="absolute inset-0"> ... </motion.div>

  {/* [2] Gradient overlay */}
  <div className="absolute inset-0"
       style={{ background: "linear-gradient(105deg, rgba(0,0,0,0.88) 0%, rgba(0,0,0,0.65) 50%, rgba(0,71,187,0.30) 100%)" }} />

  {/* [3] Cursor spotlight — z-[1] */}
  {/* [4] Dot-grid texture — z-[1] */}

  {/* [5] Text */}
  <div className="absolute inset-0 flex items-center z-[2]">
    <div className="px-8 md:px-14 lg:px-20 max-w-3xl">
      {/* motion.h1, motion.p, motion.div (CTA row) with staggered animate delays */}
    </div>
  </div>

  {/* [6] Coordinate easter egg — z-[2] */}
  {/* [7] Angled blue edge — z-[2], clipPath: "polygon(0 100%, 100% 100%, 100% 0%, 0 100%)" */}
</section>

Full homepage section order

  1. [1]Hero (full-bleed image, overlay, parallax) — clamp(560px, 80vh, 760px)
  2. [2]Positioning band (blue, py-16) — single serif sentence at font-weight 400
  3. [3]Capabilities section (ivory, py-12) — label + 3×2 grid with animated dividers
  4. [4]How We Work (tea-green parallelogram) — 3-col steps
  5. [5]Credibility (ivory, py-16) — 2-col with logo watermark
  6. [6]Ticker band (tangerine, py-3) — scrolling focus areas
  7. [7]Final CTA (blue, py-24, centered) — MagneticButton, dot-grid texture

Credibility section — logo watermark

logo-square.png at 7% opacity, absolutely positioned center-right, behind content (z-0). Content sits at z-[1]. The watermark is decorative — no alt text.

<section className="bg-brand-ivory px-8 md:px-14 lg:px-20 py-16 relative overflow-hidden">
  {/* Watermark */}
  <div
    className="absolute right-36 md:right-48 top-1/2 -translate-y-1/2 z-0 pointer-events-none"
    style={{ opacity: 0.07 }}
  >
    <Image src="/images/logo-square.png" alt="" width={220} height={220} />
  </div>

  {/* Content — must be z-[1] to sit above watermark */}
  <div className="grid grid-cols-1 md:grid-cols-2 gap-6 relative z-[1] items-center">
    {/* Reveal-wrapped heading + body left, credibility border-bar items right */}
  </div>
</section>

Easter Egg

Oxford coordinates — hero bottom-right

The coordinates 51.7519° N  1.2578° W reference The Bear pub in Oxford, England. They appear in the hero at 28% ivory opacity — barely legible, a quiet nod to the brand's intellectual character. Fades in on mount with a 1.0s delay (not on scroll).

{/* Fades in on mount with 1.0s delay — not scroll-triggered */}
<motion.div
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
  transition={{ duration: 1.2, delay: 1.0 }}
  className="absolute bottom-14 right-8 md:right-14 lg:right-20 z-[2] text-right pointer-events-none select-none"
>
  <p className="font-mono text-[9px] tracking-widest" style={{ color: "rgba(255,255,242,0.28)" }}>
    51.7519° N&nbsp;&nbsp;1.2578° W
  </p>
</motion.div>

Logo Usage

Neighborhood Insights

Main

General use

Neighborhood Insights

Header

Navigation bar

Neighborhood Insights

Footer

Footer compact

Neighborhood Insights

Square

Social / watermark

Neighborhood Insights

Banner

Wide banners

Do

  • Maintain clear space equal to the logo height
  • Use approved variants only
  • Ensure adequate contrast with background
  • Scale proportionally at all times

Don't

  • × Stretch or distort the logo
  • × Recolor outside approved palette
  • × Place on busy or low-contrast backgrounds
  • × Recreate or modify any element

Internal document

Questions about the design system?

This handbook is the canonical reference. If a pattern is not documented here, default to Bold/Geometric + Sparse/Authoritative: serif headings, ivory background, colors as accents only. When in doubt, look at ClientPage.tsx (homepage) and AboutClientPage.tsx (inner page) — they are always the ground truth.