Design — Ciketo Next.js
The look comes from a small set of tokens. Change a token and nearly every page, component and state follows, so you rarely need to touch a component.
See everything first
Section titled “See everything first”Run npm run dev and open http://localhost:3000/style-guide. It shows the colours, text styles, the logo, buttons,
the facts, the post card, the accordions, the steps, the ticker, rich text and the form with their names. When you want
to know what a change will affect, look there.

Colours
Section titled “Colours”src/design-system/theme.css:
@theme { --color-ink: #000000; /* text, dark buttons and cards, the footer */ --color-soft: #4b4a4a; /* body text, dates, captions */ --color-grey: #e5e5e5; /* text on dark, lines, form field borders */ --color-orange: #e2652a; /* labels, button hovers, the current page in the menu, step numbers, stars */ --color-background: #f4f0f0; /* the page, form fields, the header once you scroll */}Each name becomes a Tailwind class: bg-ink, text-soft, bg-orange. Swap the hex values for your own palette and
the site changes. Keep enough contrast between text and its background (at least 4.5:1), or the site becomes hard to
read.
Faded colours are opacity modifiers on the same colour, such as bg-ink/70 or text-ink/20: ink/70 is the dark
cover over the Home, Contact and 404 photos, ink/50 the cover of the call to action, ink/20 the divider lines and
placeholders, white/10 the line in the footer. They follow the palette when you change the colour.
A few components animate a colour with Motion, so they write the value out instead of using the token. Change these
too when you change a colour; search the file for the value. The paths start in src/design-system/components/
unless they say otherwise:
| Colour | Also written in |
|---|---|
| Black and white | actions/Button.tsx (the labels, the small button’s fill), patterns/ServiceAccordion.tsx (open and closed cards) |
| Orange | actions/Button.tsx (the small button’s hover, #e2652a), actions/MenuLink.tsx (the current page, rgba(226, 101, 42, 1)) |
| Grey | actions/MenuLink.tsx (the hover fill, rgba(229, 229, 229, …)) |
| Background | src/components/site/Header.tsx (the header’s fill, rgba(244, 240, 240, …); white while the phone menu is open) |
The form’s error state (“Something went wrong”) uses its own red, in forms/SubmitButton.tsx.
The Ciketo logo (the arrow mark and the wordmark) is drawn as SVG paths in
src/design-system/components/brand/Logo.tsx, in the current text colour. That’s why it is black in the header’s white
box, white in the footer, and white on phones over the dark covers of Home, Contact and the 404 page. To use your own:
- As an SVG: replace the path data in
markandwordmarkwith your logo’s paths and set theviewBoxto your artwork’s size. - As an image file: replace the
<svg>with an<Image>of your file. An image keeps its own colours, also over the dark covers.
It is 94 × 18 px everywhere: change h-[18px] w-[94px] in Logo.tsx to fit your proportions. Its label for screen
readers is site.name.
The browser icons are src/app/icon.svg and src/app/apple-icon.png.
The template loads Inter through next/font in src/app/layout.tsx:
const inter = Inter({ variable: "--font-inter", subsets: ["latin"], weight: ["400", "500", "600"] });theme.css makes --font-inter the site font (--font-sans). To use another Google font, import it by name from
next/font/google and keep the variable name:
import { Manrope } from "next/font/google";const inter = Manrope({ variable: "--font-inter", subsets: ["latin"], weight: ["400", "500", "600"] });The three weights are regular text (400), headings, buttons and menu links (500), and the form’s messages and the bold
starts in rich text (600). For a font you have licensed yourself, use next/font/local and point it at the files in
src/app/fonts/. Next.js serves the font from your own domain either way, so there is no request to Google at
runtime.
Text styles
Section titled “Text styles”src/design-system/tokens/text.ts holds the sizes, weights and line heights, named after the design:
display, h1, h2, h3, h4, h5, h6paragraph, small, button, menu, labelEach is a set of Tailwind classes. The headings have the phone size first and the tablet (md:) and desktop (lg:)
sizes after, for example h2: "text-[30px] md:text-[36px] lg:text-[42px] leading-[1.2] font-medium tracking-[-0.03em]".
Paragraphs (16 and 14 px), button (16), menu (14) and label (12) are the same at every size. Section labels are the
label style in capitals, after a small orange square. Change the numbers here rather than in the components, and
headings stay consistent across the site.
Use them as className={text.h2} or combine: className={cn(text.h6, "text-white")}.
Breakpoints
Section titled “Breakpoints”Three sizes, set in theme.css:
| Width | Tailwind prefix | |
|---|---|---|
| Phone | below 810 px | (none) |
| Tablet | 810–1199 px | md: |
| Desktop | 1200 px and up | lg: |
Content is at most 1600 px wide. The side padding is 15 px on phones, 20 px on tablets and 40 px on desktops, and
sections are 60 / 80 / 100 px apart (src/design-system/components/layout/Section.tsx).
Motion
Section titled “Motion”src/design-system/tokens/motion.ts holds the transitions:
| Token | Used for |
|---|---|
spring |
Buttons (the orange sweep, the arrow turning), the header’s colour and the phone menu, the services accordion, the steps, the testimonials, the FAQ |
springSoft |
The plus and minus icons, the menu button’s lines, the zoom of a blog card’s photo |
springMenu |
The grey fill behind a menu link on hover |
appearText, appearStagger, appearBlock |
The Home hero on load: the title word by word, then the text, the buttons, the figures and the lane card rising into place |
Lower a spring’s duration for a snappier feel, or raise bounce for a livelier one. Apart from the Home hero, nothing
animates as it scrolls into view.
| Effect | Where to change it |
|---|---|
| The Home hero appears on load | <TextAppear> and <Appear> in src/components/sections/HomeHeroSection.tsx; a plain element with the same className shows at once |
| The client logos move 20 px a second, 60 px apart | <Ticker> in src/components/sections/ClientsSection.tsx: add speed={30} or gap={80} |
| The Blog shows six posts, then six more as you scroll | Add pageSize={9} to <BlogListSection> in src/app/blog/page.tsx |
| The header is transparent at the top of Home, Contact and the 404 page | useCover() in src/components/site/Header.tsx and data-header-cover on a page’s first section (Pages and sections) |
With “reduce motion” switched on in the visitor’s system, nothing rises, turns or zooms: the Home hero fades in where it stands, the client logos stand still and smooth scrolling is off. Fades and colour changes stay.
Rounded corners, spacing, shadows
Section titled “Rounded corners, spacing, shadows”Ciketo’s corners are 2 px: buttons, form fields, cards, the photos inside sections and the header’s boxes
(rounded-[2px]). The bullets and the squares before labels are square, and there are no drop shadows. Spacing is Tailwind classes on the components
(gap-5, p-5, gap-[50px]). Tailwind’s scale is 4 px per step, so p-5 is 20 px. Change them where you see them;
the style guide shows the result immediately.
Components
Section titled “Components”src/design-system/components/ holds the buttons, the menu links, the logo, the clock, the fact rows, the post card,
the services accordion, the steps, the FAQ, the ticker, rich text, the form fields and the icons. Its
README lists every component next to the design it comes from. The sections that make
up a page are one level up, in src/components/sections/, and are listed in Pages and sections.
The icons are Phosphor shapes stored as path data in
src/design-system/components/icons/paths.ts (arrow-up-right in the buttons, star in the ratings), and
<Icon name="star" /> draws one in the current text colour. To add one:
-
Open the icon on phosphoricons.com and copy the SVG.
-
Take the
d="…"of its<path>. -
Add a line:
"my-icon": "M128,24A104,104,0,1,0,…",
Then use <Icon name="my-icon" className="size-5" />. Paths use a 256 × 256 grid, which is what Phosphor exports.