Skip to main content
JTVC

The design system

Every colour, size, radius, shadow and motion curve on this site comes from one token file. This page is the reference, and the place to check a change before it ships.

Colour

Fields, not gradients

Each section owns one field. Text colour follows from the field. Every pairing shown here clears WCAG AAA in both themes, and a build-time check enforces it.

  • Paper --color-paper Default page field
  • Raised --color-raised Muted band, card wells
  • Mint --color-mint Airy band, calm sections
  • Sand --color-sand Warm band, admissions
  • Deep --color-deep Hero and dark bands
  • Slab --color-slab Footer, statement bands
  • Amber --color-amber Primary action, highlight
  • Flame --color-flame Accent mark, focus ring
  • Teal --color-teal Second accent, bullets

Typography

Archivo for voice, Work Sans for reading

Six steps, all fluid. Display and headings are Archivo at a widened optical width. Body copy is Work Sans.

  • Learn a trade

    .jt-display --text-display Hero statements only. One per page.

  • Learn a trade

    .jt-h1 --text-h1 Page titles and section statements.

  • Learn a trade

    .jt-h2 --text-h2 Section headings.

  • Learn a trade

    .jt-h3 --text-h3 Card and sub-section headings.

  • Body copy sits at a comfortable measure and never runs past 68 characters. Long-form content uses the .jt-prose wrapper.

    .jt-lede --text-body

  • Eyebrow label

    .jt-eyebrow --text-meta

Controls

One geometry, every control

Buttons, inputs and selects share a baseline height driven by padding, a single radius, and a 44px minimum target.

Fields

Helper text sits below the control.
Enter a valid email address, e.g. name@example.com.

Patterns

Disclosure and states

Accordions, tabs, and the states a product is judged on.

Accordion

This. The panel animates open on a grid-rows transition, so nothing jumps.

Yes. It is a button with aria-expanded controlling a labelled region.

Tabs

Arrow keys move between tabs. Home and End jump to the ends.

Empty state

Nothing here yet

Empty, loading and error states are designed with the same care as the happy path.

Loading skeleton

Shape

Radius and elevation

  • --radius-ui Every control: buttons, fields, icon buttons, tabs
  • --radius-card Everything that holds content: cards, frames, panels, menus
  • --radius-inset A box nested flush inside a control
  • --radius-pill Chips, dots, rails — things that are a lozenge
  • --shadow-sm
  • --shadow-md
  • --shadow-lg

Motion

Spring, never linear

--ease-spring
cubic-bezier(.22, 1, .36, 1). Used for entrances, hovers, reveals and carousel movement.
--ease-in-out-soft
cubic-bezier(.65, 0, .35, 1). Used for loops such as the loading shimmer.
Reduced motion
Every animation and transition collapses to instant when prefers-reduced-motion: reduce is set, and scroll reveals show immediately.
Apply now