Repository navigation
Design Tokens
All of the web app's design tokens live in one file, apps/web/app/globals.css: 23 CSS custom properties on :root hold the values, and a Tailwind CSS 4 @theme inline block turns them into utilities such as bg-background, text-match and rounded-xl. The tokens follow shadcn/ui naming, with three additions for the brand (match, match-soft, highlight) and one value used only by the logo (highlight-deep). There is a single light theme: no dark values, chart colours or sidebar tokens exist. The marketing site keeps its own small token set in site/styles.css, copied from the same values. This page lists every token, its role and the utility it produces. For how they are used, see Visual System.
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@theme inline { /* Tailwind theme variables that point at the :root tokens */ }
:root { /* the token values */ }
@layer base { /* global element styles */ }| Part | Purpose |
|---|---|
@import "tailwindcss" |
Tailwind CSS 4 with its default theme (spacing, type scale, shadows, breakpoints). |
@import "tw-animate-css" |
animate-in, fade-in-0, zoom-in-95 and related utilities used by the dialog and menu. |
@import "shadcn/tailwind.css" |
From the shadcn package: the data-open, data-closed, data-checked, data-unchecked, data-selected, data-disabled, data-active, data-horizontal and data-vertical custom variants, accordion keyframes, and the no-scrollbar, scroll-fade-* and shimmer-* utilities. It defines no colour tokens. |
@theme inline |
Declares Tailwind theme variables. inline makes a utility emit the referenced value directly (background-color: var(--background)) instead of the theme variable, so the utility always follows the current :root value. |
:root |
The source of truth for every value. |
@layer base |
Applies border-border and outline-ring/50 to every element, bg-background text-foreground to body, font-sans to html, and text-wrap: balance to h1 and h2. |
The six colours in the brand guide are app tokens. Several roles share one value.
| Brand colour | Hex | Tokens | Typical utilities |
|---|---|---|---|
Ink |
#1c2a23 |
--foreground, --card-foreground, --popover-foreground, --primary, --secondary-foreground, --accent-foreground
|
text-foreground, bg-primary
|
Paper |
#eef1ec |
--background |
bg-background |
Sheet |
#fafbf8 |
--card, --popover
|
bg-card, bg-popover
|
Marker |
#f3de6e |
--highlight |
bg-highlight |
Marker, twice |
#e2b92a |
--highlight-deep |
none (not in @theme; used as var(--highlight-deep) in the logo) |
Match |
#2f6b4f |
--match, --ring
|
bg-match, text-match, ring-ring
|
Each --color-<name> theme variable produces the full set of Tailwind colour utilities for <name>: bg-, text-, border-, ring-, outline-, fill-, stroke-, divide-, accent-, caret-, decoration-, placeholder-, from-/via-/to- and so on, each accepting an opacity modifier such as /50.
| Swatch | Token | Value | Role | Theme variable | Example utilities |
|---|---|---|---|---|---|
![]() |
--background |
#eef1ec |
Page background (Paper) | --color-background |
bg-background |
![]() |
--foreground |
#1c2a23 |
Default text (Ink) | --color-foreground |
text-foreground, ring-foreground/10, border-foreground
|
![]() |
--card |
#fafbf8 |
Card surface (Sheet) | --color-card |
bg-card |
![]() |
--card-foreground |
#1c2a23 |
Text on cards | --color-card-foreground |
text-card-foreground |
![]() |
--popover |
#fafbf8 |
Dialogs, menus, toasts | --color-popover |
bg-popover |
![]() |
--popover-foreground |
#1c2a23 |
Text on popovers | --color-popover-foreground |
text-popover-foreground |
| Swatch | Token | Value | Role | Theme variable | Example utilities |
|---|---|---|---|---|---|
![]() |
--primary |
#1c2a23 |
Primary button, default badge, checked switch, done wizard step | --color-primary |
bg-primary, hover:bg-primary/80, text-primary
|
![]() |
--primary-foreground |
#f4f6f1 |
Text on primary and on the match badge | --color-primary-foreground |
text-primary-foreground |
![]() |
--secondary |
#e2e7df |
Secondary button and badge | --color-secondary |
bg-secondary |
![]() |
--secondary-foreground |
#1c2a23 |
Text on secondary | --color-secondary-foreground |
text-secondary-foreground |
![]() |
--accent |
#dde6da |
shadcn accent surface; not used by any component today | --color-accent |
bg-accent |
![]() |
--accent-foreground |
#1c2a23 |
Text on accent; not used today | --color-accent-foreground |
text-accent-foreground |
![]() |
--destructive |
#b4432f |
Errors, failed verdicts, destructive button, invalid fields | --color-destructive |
text-destructive, bg-destructive/10, border-destructive
|
There is no --destructive-foreground: the destructive button and badge use text-destructive on a 10% tint of the same colour.
| Swatch | Token | Value | Role | Theme variable | Example utilities |
|---|---|---|---|---|---|
![]() |
--muted |
#e3e8e0 |
Hover rows, notices, skeletons, progress track, active nav item | --color-muted |
bg-muted, bg-muted/50
|
![]() |
--muted-foreground |
#56655c |
Secondary text, placeholders, list markers | --color-muted-foreground |
text-muted-foreground |
![]() |
--border |
#d3dacf |
Default border colour (applied to every element by the base layer), separators | --color-border |
border-border, bg-border, divide-y
|
![]() |
--input |
#c6cfc2 |
Input borders, unchecked switch track | --color-input |
border-input, bg-input
|
![]() |
--ring |
#2f6b4f |
Focus rings and outlines (Match green) | --color-ring |
ring-ring/50, border-ring, outline-ring/50
|
| Swatch | Token | Value | Role | Theme variable | Example utilities |
|---|---|---|---|---|---|
![]() |
--match |
#2f6b4f |
Match verdicts, progress indicator, done checks, checkbox accent | --color-match |
bg-match, text-match, accent-match
|
![]() |
--match-soft |
#dcebdf |
Soft match tint; defined but not used by any component today | --color-match-soft |
bg-match-soft |
![]() |
--highlight |
#f3de6e |
Highlighter yellow for evidence in reasons; the logo check | --color-highlight |
bg-highlight/70 |
![]() |
--highlight-deep |
#e2b92a |
The overlap where the logo's two strokes cross. The CSS comment reads "The highlighter passing twice: only where the logo's two strokes cross." | none | none; read as var(--highlight-deep)
|
Every colour above has one value. globals.css has no .dark selector or prefers-color-scheme block, so there is no dark column to document. See Visual System for what that means for the dark: classes inside the primitives.
| Token | Definition | Resolved | Utility | Used by |
|---|---|---|---|---|
--radius |
0.375rem |
6 px | (base value) | Also passed to Sonner as --border-radius
|
--radius-sm |
calc(var(--radius) * 0.6) |
0.225rem (3.6 px) | rounded-sm |
Focusable section headings |
--radius-md |
calc(var(--radius) * 0.8) |
0.3rem (4.8 px) | rounded-md |
Menu items, skeletons, alert dialog media; caps the small button sizes |
--radius-lg |
var(--radius) |
0.375rem (6 px) | rounded-lg |
Buttons, inputs, menus, notices, ScoringHelp
|
--radius-xl |
calc(var(--radius) * 1.4) |
0.525rem (8.4 px) | rounded-xl |
Cards, alert dialog, home skeletons |
--radius-2xl |
calc(var(--radius) * 1.8) |
0.675rem (10.8 px) | rounded-2xl |
Not used today |
--radius-3xl |
calc(var(--radius) * 2.2) |
0.825rem (13.2 px) | rounded-3xl |
Not used today |
--radius-4xl |
calc(var(--radius) * 2.6) |
0.975rem (15.6 px) | rounded-4xl |
Badges |
rounded-xs, rounded-full and rounded-none keep Tailwind's defaults.
| Token | Value | Utility | Notes |
|---|---|---|---|
--font-schibsted |
Set by next/font on <html>
|
none | Created by Schibsted_Grotesk({ variable: "--font-schibsted", subsets: ["latin"] }) in app/layout.tsx. |
--font-sans |
var(--font-schibsted) |
font-sans |
Applied to <html> by the base layer, so it is the default everywhere. |
--font-heading |
var(--font-schibsted) |
font-heading |
Used by CardTitle and AlertDialogTitle. Same family as font-sans; kept as a separate hook. |
--font-mono keeps Tailwind's default stack.
These are set inside components rather than in globals.css.
| Variable | Set in | Default | Purpose |
|---|---|---|---|
--card-spacing |
card.tsx |
--spacing(4) (1rem); --spacing(3) when size="sm"
|
Card gap and padding. App cards override it with [--card-spacing:--spacing(5)]. |
--normal-bg, --normal-text, --normal-border, --border-radius
|
sonner.tsx (inline style) |
var(--popover), var(--popover-foreground), var(--border), var(--radius)
|
Sonner's toast colours and radius. |
--available-height, --transform-origin
|
Base UI menu positioner | Set at runtime | Menu max height and zoom origin (max-h-(--available-height), origin-(--transform-origin)). |
Checked against the file, these common shadcn token groups do not exist, so their utilities are not available:
- Chart colours (
--chart-1…--chart-5). - Sidebar tokens (
--sidebar,--sidebar-foreground,--sidebar-primary, …). -
--destructive-foreground. - Custom shadow, spacing, breakpoint or font-size tokens. Tailwind's defaults are used for all of them.
apps/web/components.json tells the shadcn CLI how components were generated and where to put new ones.
| Key | Value | Meaning |
|---|---|---|
style |
base-nova |
The shadcn style built on Base UI primitives |
rsc |
true |
Adds "use client" where a component needs it |
tsx |
true |
TypeScript components |
tailwind.config |
"" |
No JavaScript config (Tailwind 4 is configured in CSS) |
tailwind.css |
app/globals.css |
Where tokens live |
tailwind.baseColor |
neutral |
The base palette the CLI started from; the values have since been replaced with the brand's green-greys |
tailwind.cssVariables |
true |
Components use token utilities (bg-primary), not literal colours |
tailwind.prefix |
"" |
No utility prefix |
iconLibrary |
lucide |
Icons come from lucide-react
|
rtl |
false |
No right-to-left variants |
menuColor / menuAccent
|
default / subtle
|
Menu styling presets |
aliases.components |
@/components |
|
aliases.ui |
@/components/ui |
|
aliases.utils |
@/lib/utils |
Resolves to the cn re-export |
aliases.lib |
@/lib |
|
aliases.hooks |
@/hooks |
The folder does not exist yet |
registries |
{} |
No third-party registries |
The static site cannot import the app's CSS, so it repeats the values it needs. Its stylesheet says the tokens "come from the app's theme". It uses plain custom properties with no utility layer.
| Swatch | Token | Value | Role | App equivalent |
|---|---|---|---|---|
![]() |
--paper |
#eef1ec |
Page background | --background |
![]() |
--sheet |
#fafbf8 |
Example-run sheet, outline buttons, command box | --card |
![]() |
--ink |
#1c2a23 |
Text, install band background, the heavy rule at the top of each list | --foreground |
![]() |
--ink-soft |
#56655c |
Secondary text | --muted-foreground |
![]() |
--ink-faint |
#7d8a81 |
Struck-out titles on the wall only (large text, 3.4 : 1 on the sheet) | none |
![]() |
--rule |
#d3dacf |
Hairlines | --border |
![]() |
--rule-strong |
#b7c1b3 |
Button and command borders, wall separators | none |
![]() |
--match |
#2f6b4f |
Links, focus outline, match badge, "checking" title | --match |
![]() |
--marker |
#f3de6e |
Highlighter stroke on matched titles, focus outline on the dark band | --highlight |
![]() |
--on-ink |
#f4f6f1 |
Text on Ink | --primary-foreground |
![]() |
--on-ink-soft |
#b9c4bb |
Secondary text on Ink | none |
| Token | Value | Role |
|---|---|---|
--font |
"Schibsted Grotesk", ui-sans-serif, system-ui, sans-serif |
Body and headings |
--mono |
ui-monospace, "Cascadia Mono", "SFMono-Regular", Menlo, Consolas, monospace |
Install commands |
--step-0 |
0.875rem |
Small text, buttons |
--step-1 |
1.0625rem |
Body, h3
|
--step-2 |
1.3125rem |
Lead, counts, verdict title |
--step-3 |
2.25rem |
h2 |
--step-4 |
3.75rem |
Step numbers |
--gutter |
1rem, 2rem from 48rem |
Side padding |
--max |
72rem |
Content width (the same as the app's max-w-6xl) |
--radius |
6px |
Buttons, command box, screenshots (the same as the app's --radius) |
--section |
clamp(4rem, 3rem + 5vw, 7.5rem) |
Vertical space between sections |
--lh |
1.3 on .wall, 1.55 on .key-list .t
|
Line height used to size the strike and highlighter backgrounds |
--strike, --marker-stroke, --check
|
Gradients and an SVG mask on .t
|
The strike line, the highlighter stroke and the check glyph |
--crop-x, --crop-w, --crop-h
|
Inline on each .shot
|
Crop the screenshots to the app's content column |
The site has no token for Marker, twice; the inline logo in index.html uses the literal #e2b92a. The site sets color-scheme: light.
-
Add the value to
:rootinapps/web/app/globals.css, named after its role rather than its colour (for example--warning, not--amber). If it pairs with text, add the-foregroundpartner as well. -
Expose it to Tailwind by adding a line to
@theme inline, using the namespace that produces the utilities you need:-
--color-warning: var(--warning);givesbg-warning,text-warning,border-warning, … -
--radius-<name>givesrounded-<name>;--font-<name>givesfont-<name>;--shadow-<name>givesshadow-<name>. Skip this step for a value that only CSS or SVG reads withvar(), as--highlight-deepdoes.
-
-
Use the utility in components. Prefer opacity modifiers (
bg-warning/10) to new tint tokens. -
Mirror it on the marketing site if the site needs it: add a matching property to
:rootinsite/styles.css. -
Update the brand guide (
docs/brand/README.md) if it is a brand colour, and this page. -
Check contrast against
--backgroundand--card(4.5 : 1 for body text).
If dark mode is added later, every token here needs a dark value in the same change; see Visual System.
Job Matcher · Website · Report an issue · MIT license
Using Job Matcher
System design
Matching engine
Interface and brand
Engineering
Ink
Paper
Sheet
Marker
Marker, twice
Match










