Lightkeepers
← Back to the working file

The brand system.

The single source of truth. New button system with no trace of the Duolingo slab, three-layer tokens, and every interactive state specified rather than implied. This supersedes the lantern, daylight and hybrid pages.

You were right about the buttons

The old one was amber, with dark bold text, on a rounded rectangle with a coloured bottom edge. That combination is the Duolingo signature. Shrinking the edge from 4px to 2px did not change what it was, it just made it quieter.

Two changes fix it properly. The silhouette becomes a pill, which reads nothing like a game key. And the primary goes dark with amber demoted to an arrow chip, so the lantern colour becomes an accent doing a job rather than the whole button.

The button system

Four roles. All live, all keyboard focusable. Tab through them.

Inside the dark card

The amber flips to the fill

On dark, the night pill would disappear, so the roles invert and the chip goes navy.

Primary, secondary, tertiary on the page, and the on-dark primary.

Every state, specified

Shown live rather than described. Priority when several apply: disabled, then loading, then active, then focus, then hover.

Base appearance
Fill lightens one step, chip grows slightly
2px ring in amber-800, offset 2px
Settles 1px, no bounce
55% opacity, no pointer
Spinner replaces the arrow, button is disabled
Focus rings are real here. 2px ring in --amber-800 with a 2px offset in the page colour, so it reads on both light and dark. Every interactive element gets one. Tab through the buttons above and you will see it.

Tokens, in three layers

Primitive values, then semantic aliases, then component overrides. This is the structure the current codebase is missing, and it is why five competing flat token sets ended up in there.

1. Primitive

Raw values. These change almost never.

#FDF8EE
--cream-50
#F6E2C0
--cream-100
#EFE4D2
--cream-200
#FFFFFF
--white
#1B2942
--navy-700
#131E33
--navy-800
#0E1626
--navy-900
#1B2436
--ink-900
#5A6478
--ink-500
#FFB454
--amber-400
#D9862B
--amber-600
#8C5516
--amber-800

2. Semantic

What each value is for. This layer is what a theme swaps.

Semantic tokenPoints atPurpose
--surface-page--cream-50The page. Always light
--surface-card--whiteRoutine cards
--surface-focal--navy-800The one dark card, the next action
--surface-band--cream-100Tinted section band
--text-primary--ink-900Body and headings on light
--text-secondary--ink-500Supporting text on light
--text-on-focal--cream-50Text inside the dark card
--action-primary--navy-800Primary button fill
--action-accent--amber-400The lantern. Chips, glows, on-dark fills
--action-link--amber-800Amber as text, the only legible amber on cream
--border-subtle--cream-200Hairlines
--focus-ring--amber-800Focus ring on light. 5.8:1, clears the 3:1 bar for UI
--focus-ring-dark--amber-400Focus ring inside the dark card

3. Component

TokenValueNote
--btn-radius999pxPill. The single biggest break from the old slab
--btn-pad15px 32pxPrimary and secondary
--btn-chip36pxThe arrow chip diameter
--card-radius20pxWhite cards
--focal-radius22pxThe dark card
--ring-width2pxFocus ring
--ring-offset2pxGap between element and ring
--tap-min44pxAny target. 56px on a child surface
--tap-gap8pxMinimum gap between adjacent targets

Contrast, measured

Text needs 4.5:1. Non-text UI such as a focus ring needs 3:1. Both thresholds are applied below.

PairingRatioWCAG AA
Body on page14.7:1Pass (needs 4.5:1)
Secondary on page5.6:1Pass (needs 4.5:1)
Text in the dark card15.7:1Pass (needs 4.5:1)
Secondary in dark card8.0:1Pass (needs 4.5:1)
Label on primary button15.7:1Pass (needs 4.5:1)
Arrow on the amber chip9.4:1Pass (needs 4.5:1)
Link text on page5.8:1Pass (needs 4.5:1)
Focus ring on page5.8:1Pass (needs 3:1, UI component)
Focus ring in dark card9.4:1Pass (needs 3:1, UI component)

A real screen

The child home with the new buttons. Icons are SVG, never emoji.

Today

The water cycle, in a jar

About 25 minutes. You'll need a jar, warm water and a plate.

Maths

Two lessons left

Science

Done this week

English

One to catch up

A rule I broke earlier and have now fixed. The card icons on the older spec page were emoji. Emoji render differently on every platform, cannot be recoloured, and carry their own accessibility semantics. They are not icons. Everything here is inline SVG.

The laws

  1. The page is light. Dark is a component, never the canvas.
  2. One dark card per screen, and it is the next action. If everything is dark, nothing is.
  3. Glow lives only inside dark. A halo on cream is invisible, so it is never used there.
  4. Buttons are pills. No bottom edge, no slab, no plastic press. Primary is navy with an amber chip; on dark those invert.
  5. Amber belongs to the lantern. As text it is always --amber-800, because --amber-400 fails contrast on cream.
  6. Every interactive element has all six states and a visible focus ring. No exceptions.
  7. Targets are 44px minimum, 56px on a child surface, with 8px between them.
  8. Icons are SVG. Never emoji.
  9. Motion 150 to 300ms, nothing loops, reduced motion fully honoured.
  10. Praise names the work, progress is distance not score, and nothing commercial appears on a child surface.