Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions packages/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,30 @@ const nav = [

const RootLayout = ({ children }: { children: ReactNode }) => (
<html lang="en">
<body>
<body className="overflow-x-hidden">
<a
href="#main"
className="absolute -left-[9999px] top-2 focus:left-4 focus:z-10 focus:bg-accent-solid focus:text-on-accent focus:px-2 focus:py-1"
className="absolute -left-[9999px] top-2 focus:left-4 focus:z-10 focus:bg-accent-solid focus:px-3 focus:py-2 focus:text-on-accent"
>
Skip to content
</a>

<header className="border-b border-line">
<div className="mx-auto flex max-w-[1180px] items-center justify-between gap-3 px-3 py-2">
<div className="mx-auto flex max-w-[1180px] items-center justify-between gap-4 px-4 py-3 sm:px-6 lg:px-8">
<Link
href="/"
className="font-display text-[1.0625rem] font-bold tracking-[-0.02em] text-ink no-underline"
className="font-display text-base font-bold tracking-[-0.02em] text-ink no-underline sm:text-[1.0625rem]"
>
Atlantic<span className="text-accent"> Blue</span>
</Link>
<nav aria-label="Main" className="flex items-center gap-3 text-[0.9375rem]">
<nav aria-label="Main" className="flex items-center gap-5 text-[0.9375rem]">
{/* The text links go below the small breakpoint. Four items plus a
button needs about 438px, and the narrowest phone is 320. */}
{nav.map((item) => (
<Link
key={item.label}
href={item.href}
className="text-dim no-underline hover:text-ink"
className="hidden text-dim no-underline hover:text-ink sm:inline"
>
{item.label}
</Link>
Expand All @@ -59,19 +61,19 @@ const RootLayout = ({ children }: { children: ReactNode }) => (

<main id="main">{children}</main>

<footer className="mt-12 border-t border-line bg-surface py-5">
<div className="mx-auto grid max-w-[1180px] gap-3 px-3 md:grid-cols-[1.4fr_1fr] md:gap-8">
<footer className="mt-16 border-t border-line bg-surface py-10 sm:mt-24">
<div className="mx-auto grid max-w-[1180px] gap-8 px-4 sm:px-6 md:grid-cols-[1.4fr_1fr] lg:px-8">
<div>
<p className="font-display text-[1.0625rem] font-bold tracking-[-0.02em]">
Atlantic Blue
</p>
<p className="mt-2 text-[0.8125rem]">
<p className="mt-3 text-sm">
<a href={`mailto:${company.email}`} className="text-accent">
{company.email}
</a>
</p>
</div>
<div className="text-[0.8125rem] leading-[1.7] text-dim">
<div className="text-sm leading-relaxed text-dim">
<p>{company.legalName}</p>
<p>
Registered in England and Wales, company number{" "}
Expand Down
104 changes: 43 additions & 61 deletions packages/web/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,104 +2,86 @@ import type { Metadata } from "next"
import Link from "next/link"

import { Button } from "@/components/ui/button"
import { Eyebrow, Heading, Lede, Section, Title } from "@/components/ui/section"
import { servicesInGroup } from "@/lib/services"
import { clients, company } from "@/lib/site"

export const metadata: Metadata = {
alternates: { canonical: "/" },
}

const ServiceList = ({ group }: { group: "specialism" | "practice" }) => (
<ul className="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{servicesInGroup(group).map((service) => (
<li key={service.slug}>
<h3 className="text-lg font-semibold tracking-[-0.01em] sm:text-xl">
<Link href={`/services/${service.slug}`} className="text-ink">
{service.name}
</Link>
</h3>
<p className="mt-2 text-[0.9375rem] text-dim">{service.summary}</p>
</li>
))}
</ul>
)

const HomePage = () => (
<>
<section className="mx-auto max-w-[1180px] px-3 pt-12 pb-8">
<p className="font-mono text-xs uppercase tracking-[0.12em] text-dim">
London software consultancy
</p>
<h1 className="mt-3 max-w-[16ch] text-[clamp(2.4rem,5.2vw,4.2rem)] leading-[1.02] tracking-[-0.035em]">
We build software that cannot afford to break.
</h1>
<p className="mt-3 max-w-[52ch] text-lg text-dim">
<Section className="pt-12 sm:pt-20">
<Eyebrow>London software consultancy</Eyebrow>
<Title className="max-w-[16ch]">We build software that cannot afford to break.</Title>
<Lede>
Nine years inside broadcast and streaming platforms, where a fault is visible to
millions of people at once. We bring that standard to whatever you are building.
</p>
<div className="mt-5 flex flex-wrap gap-2">
</Lede>
<div className="mt-8 flex flex-wrap gap-3">
<Button asChild>
<a href={`mailto:${company.email}`}>Book a call</a>
</Button>
<Button asChild variant="quiet">
<Link href="/services">See what we do</Link>
</Button>
</div>
</section>
</Section>

<section className="mx-auto max-w-[1180px] border-t border-line px-3 py-8">
<p className="font-mono text-xs uppercase tracking-[0.12em] text-dim">The specialism</p>
<h2 className="mt-2 text-[clamp(1.75rem,3vw,2.4rem)] leading-[1.08] tracking-[-0.025em]">
Broadcast and streaming
</h2>
<p className="mt-3 max-w-[60ch] text-dim">
<Section className="border-t border-line">
<Eyebrow>The specialism</Eyebrow>
<Heading className="mt-3">Broadcast and streaming</Heading>
<p className="mt-4 max-w-[60ch] text-dim">
Where we contract most, and the reason the reliability work below is not a claim. A
fault on a streaming platform is visible to millions of people at once, so it gets
found and fixed to a standard most systems never need.
</p>
<ul className="mt-5 grid gap-5 md:grid-cols-3">
{servicesInGroup("specialism").map((service) => (
<li key={service.slug}>
<h3 className="text-xl font-semibold tracking-[-0.01em]">
<Link href={`/services/${service.slug}`} className="text-ink">
{service.name}
</Link>
</h3>
<p className="mt-1 text-[0.9375rem] text-dim">{service.summary}</p>
</li>
))}
</ul>
</section>
<ServiceList group="specialism" />
</Section>

<section className="mx-auto max-w-[1180px] border-t border-line px-3 py-8">
<p className="font-mono text-xs uppercase tracking-[0.12em] text-dim">The practice</p>
<h2 className="mt-2 text-[clamp(1.75rem,3vw,2.4rem)] leading-[1.08] tracking-[-0.025em]">
What we build once we are in the building
</h2>
<ul className="mt-5 grid gap-5 md:grid-cols-3">
{servicesInGroup("practice").map((service) => (
<li key={service.slug}>
<h3 className="text-xl font-semibold tracking-[-0.01em]">
<Link href={`/services/${service.slug}`} className="text-ink">
{service.name}
</Link>
</h3>
<p className="mt-1 text-[0.9375rem] text-dim">{service.summary}</p>
</li>
))}
</ul>
</section>
<Section className="border-t border-line">
<Eyebrow>The practice</Eyebrow>
<Heading className="mt-3">What we build once we are in the building</Heading>
<ServiceList group="practice" />
</Section>

<section className="mx-auto max-w-[1180px] border-t border-line px-3 py-6">
<p className="font-mono text-xs uppercase tracking-[0.12em] text-dim">
Platforms we have worked inside
</p>
<ul className="mt-3 flex flex-wrap gap-x-5 gap-y-2 font-display text-lg font-bold text-dim">
<Section className="border-t border-line py-8 sm:py-10">
<Eyebrow>Platforms we have worked inside</Eyebrow>
<ul className="mt-4 flex flex-wrap gap-x-6 gap-y-2 font-display text-base font-bold text-dim sm:text-lg">
{clients.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
</section>
</Section>

<section className="mx-auto max-w-[1180px] border-t border-line px-3 py-8">
<h2 className="text-[clamp(1.75rem,3vw,2.4rem)] leading-[1.08] tracking-[-0.025em]">
Have something that cannot go down?
</h2>
<p className="mt-3 max-w-[52ch] text-dim">
<Section className="border-t border-line">
<Heading>Have something that cannot go down?</Heading>
<p className="mt-4 max-w-[52ch] text-dim">
Tell us what it is and what is worrying you about it. If it is not something we
should take, we will say so.
</p>
<div className="mt-5">
<div className="mt-8">
<Button asChild>
<a href={`mailto:${company.email}`}>Book a call</a>
</Button>
</div>
</section>
</Section>
</>
)

Expand Down
41 changes: 17 additions & 24 deletions packages/web/src/app/services/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Link from "next/link"
import { notFound } from "next/navigation"

import { Button } from "@/components/ui/button"
import { Eyebrow, Heading, Lede, Section, Title } from "@/components/ui/section"
import { serviceBySlug, services } from "@/lib/services"
import { company } from "@/lib/site"

Expand Down Expand Up @@ -78,47 +79,39 @@ const ServicePage = async ({ params }: Params) => {
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
/>

<section className="mx-auto max-w-[1180px] px-3 pt-12 pb-8">
<p className="font-mono text-xs uppercase tracking-[0.12em] text-dim">
<Section className="pt-12 sm:pt-20">
<Eyebrow>
<Link href="/services" className="text-dim hover:text-ink">
Services
</Link>{" "}
/ {service.name}
</p>
<h1 className="mt-3 max-w-[18ch] text-[clamp(2.4rem,5.2vw,4.2rem)] leading-[1.02] tracking-[-0.035em]">
{service.name}
</h1>
<p className="mt-3 max-w-[58ch] text-lg text-dim">{service.problem}</p>
</section>
</Eyebrow>
<Title className="max-w-[18ch]">{service.name}</Title>
<Lede className="max-w-[58ch]">{service.problem}</Lede>
</Section>

<section className="mx-auto max-w-[1180px] border-t border-line px-3 py-8">
<h2 className="text-[clamp(1.75rem,3vw,2.4rem)] leading-[1.08] tracking-[-0.025em]">
What the engagement is
</h2>
<ol className="mt-5 border-t border-line">
<Section className="border-t border-line">
<Heading>What the engagement is</Heading>
<ol className="mt-8 border-t border-line">
{service.work.map((step, index) => (
<li key={step} className="flex gap-3 border-b border-line py-3">
<li key={step} className="flex gap-4 border-b border-line py-4">
<span className="font-mono text-xs tabular-nums text-accent pt-1">
{String(index + 1).padStart(2, "0")}
</span>
<span className="max-w-[62ch]">{step}</span>
</li>
))}
</ol>
</section>
</Section>

<section className="mx-auto max-w-[1180px] border-t border-line px-3 py-8">
<div className="grid gap-5 border border-line bg-surface p-5 md:grid-cols-2 md:gap-8">
<Section className="border-t border-line">
<div className="grid gap-6 border border-line bg-surface p-5 sm:p-8 md:grid-cols-2">
<div>
<p className="font-mono text-xs uppercase tracking-[0.12em] text-dim">
What you are left with
</p>
<Eyebrow>What you are left with</Eyebrow>
<p className="mt-2 max-w-[46ch]">{service.outcome}</p>
</div>
<div>
<p className="font-mono text-xs uppercase tracking-[0.12em] text-dim">
Typical engagement
</p>
<Eyebrow>Typical engagement</Eyebrow>
<p className="mt-2">{service.typical}</p>
<div className="mt-4">
<Button asChild>
Expand All @@ -127,7 +120,7 @@ const ServicePage = async ({ params }: Params) => {
</div>
</div>
</div>
</section>
</Section>
</>
)
}
Expand Down
36 changes: 15 additions & 21 deletions packages/web/src/app/services/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Metadata } from "next"
import Link from "next/link"

import { Eyebrow, Lede, Section, Title } from "@/components/ui/section"
import { servicesInGroup } from "@/lib/services"

export const metadata: Metadata = {
Expand All @@ -25,39 +26,32 @@ const groups = [

const ServicesPage = () => (
<>
<section className="mx-auto max-w-[1180px] px-3 pt-12 pb-8">
<p className="font-mono text-xs uppercase tracking-[0.12em] text-dim">Services</p>
<h1 className="mt-3 text-[clamp(2.4rem,5.2vw,4.2rem)] leading-[1.02] tracking-[-0.035em]">
What we do
</h1>
<p className="mt-3 max-w-[52ch] text-lg text-dim">
<Section className="pt-12 sm:pt-20">
<Eyebrow>Services</Eyebrow>
<Title>What we do</Title>
<Lede>
One page for each, because the problems are not interchangeable and neither are the
people who have them.
</p>
</section>
</Lede>
</Section>

{groups.map((group) => (
<section
key={group.key}
className="mx-auto max-w-[1180px] border-t border-line px-3 py-8"
>
<p className="font-mono text-xs uppercase tracking-[0.12em] text-dim">
{group.label}
</p>
<p className="mt-2 max-w-[60ch] text-dim">{group.note}</p>
<ul className="mt-5 grid gap-5 md:grid-cols-2">
<Section key={group.key} className="border-t border-line">
<Eyebrow>{group.label}</Eyebrow>
<p className="mt-3 max-w-[60ch] text-dim">{group.note}</p>
<ul className="mt-8 grid gap-6 md:grid-cols-2">
{servicesInGroup(group.key).map((service) => (
<li key={service.slug} className="border border-line bg-surface p-4">
<h2 className="text-xl font-semibold tracking-[-0.01em]">
<li key={service.slug} className="border border-line bg-surface p-5 sm:p-6">
<h2 className="text-lg font-semibold tracking-[-0.01em] sm:text-xl">
<Link href={`/services/${service.slug}`} className="text-ink">
{service.name}
</Link>
</h2>
<p className="mt-2 text-[0.9375rem] text-dim">{service.summary}</p>
<p className="mt-3 text-[0.9375rem] text-dim">{service.summary}</p>
</li>
))}
</ul>
</section>
</Section>
))}
</>
)
Expand Down
48 changes: 48 additions & 0 deletions packages/web/src/components/ui/section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { ComponentProps } from "react"

import { cn } from "@/lib/cn"

/**
* One container, so page padding and rhythm are decided once. Mobile first:
* 16px of padding on a phone, growing at the breakpoints.
*/
export const Section = ({ className, ...props }: ComponentProps<"section">) => (
<section
className={cn(
"mx-auto max-w-[1180px] px-4 py-10 sm:px-6 sm:py-14 lg:px-8 lg:py-16",
className,
)}
{...props}
/>
)

export const Eyebrow = ({ className, ...props }: ComponentProps<"p">) => (
<p
className={cn("font-mono text-xs uppercase tracking-[0.12em] text-dim", className)}
{...props}
/>
)

export const Title = ({ className, ...props }: ComponentProps<"h1">) => (
<h1
className={cn(
"mt-4 text-[clamp(2rem,7vw,4.2rem)] leading-[1.05] tracking-[-0.03em]",
className,
)}
{...props}
/>
)

export const Heading = ({ className, ...props }: ComponentProps<"h2">) => (
<h2
className={cn(
"text-[clamp(1.5rem,4.5vw,2.4rem)] leading-[1.12] tracking-[-0.02em]",
className,
)}
{...props}
/>
)

export const Lede = ({ className, ...props }: ComponentProps<"p">) => (
<p className={cn("mt-4 max-w-[52ch] text-base text-dim sm:text-lg", className)} {...props} />
)
Loading