Scenario 2 of 3
A friend cancels plans last minute. What do you say?
You were looking forward to it. They sound stressed.
Design system · v1.0 · 14 November 2026
A calm daily-learning ritual for practical social moments: what to do, what to say, and how to respond with care. Warm canvas, ink text, one orange accent, and a brighter sticker language for the illustration.
Reused from syafiqiskandar30/daily-learning — its DESIGN-SYSTEM.md direction and the token layer in src/styles.css — then extended with the components, the missing primitives, a dark scheme and the contrast fixes recorded at the end.
Four rules decide every screen. They come from the app's own design system, not from taste.
#fffdfa, ink #172236, one orange. Illustrations carry the colour; the interface stays quiet.Semantic names only; a component asks for a role, never a hue. Contrast figures are measured against the canvas #fffdfa unless stated.
Illustration only. These four never appear on text, borders or buttons — the rule that keeps the interface calm while the art stays bright.
One family — the platform rounded stack — two weights, and a size per role. Never a raw size in a component: ask for the role.
| Role | Token | Size | Weight / tracking |
|---|---|---|---|
| Main heading | --type-page-heading | 27–30px | 600 · −0.025em |
| Simple page heading | --type-simple-heading | 28px | 600 |
| Section heading | --type-section-heading | 21px | 600 · −0.02em |
| Lesson title | --type-card-title | 22px | 600 |
| Question | --type-question | 21–23px | 600 · 0.01em |
| Body | --type-body | 15px | 500 · 1.45 |
| Supporting | --type-supporting | 14px | 500 · 1.4 |
| Action label | --type-action | 18px | 600 · 0.01em |
| Metadata | --type-metadata | 12px | 600 · tabular |
| Tab label | --type-tab-label | 11px | 600 · 0.015em |
A calm daily-learning ritual
A friend cancels plans last minute. What do you say?
Body copy sits at 15px with 500 weight — the app never uses 400, because the rounded face thins out.
The 4/8 scale, a 12px surface radius and a 24px lesson-card radius, and three durations — one of them the app's own feedback entrance.
| Token | Value | Use |
|---|---|---|
--radius-surface | 12px | Cards, fields, stats — the nested radius is the outer 12 minus its padding |
--radius-card | 24px | Lesson cards and sheets |
--radius-pill | 999px | Every action, every answer choice |
--motion-press | 120ms | scale(.96) on press |
--motion-quick | 150ms | Hover, focus, colour changes |
--motion-feedback-enter-duration | 380ms | The feedback footer entering, 52px travel |
prefers-reduced-motion. The feedback entrance is the only staged moment in the app.Twenty components, each with the rule that decides when to use it. Live markup sits beside every one — copy it, then change the words, not the tokens.
One filled action per view. Primary carries a word, so it uses action-strong (5.27:1) rather than the orange that measures 3.66:1 with white.
<button class="action-button action-button--primary">Start lesson</button>
Wordmark and a letter avatar, Learn screen only. The avatar is a 44px target even though it draws at 40px.
One card in both lists, whole card clickable, no repeated "View course". Description uses the AA token, not the 3.93:1 original.
Three tabs, icon above label, active item in primary-ink. Fixed to the shell with safe-area padding.
aria-current="page" on the active tab.One arc per scenario: complete in primary, current in mid-peach, upcoming in pale peach. The number is tabular so it does not shift.
<div class="lesson-progress-ring" data-value="40">…</div>
Pill choices, 52px tall. Selection uses fill and border; keyboard focus is a 3px ring. Feedback states are colour and a state attribute.
You were looking forward to it. They sound stressed.
Full-width, same canvas, separated by a hairline. Icon plus two lines: what happened, what to do next.
Lemon surface, gold ink, tabular values. Two per row, never more.
A single word of state. Streak uses the lemon pair; nothing else competes with the primary action.
Visible label, 16px input text (no iOS zoom), error beside the field and phrased as a next step.
Shown on your profile only.
Add the part after the @, like name@example.com.
The three states most products forget: something happened, nothing is here yet, and something is loading.
Streak saved
7 days in a row. Tomorrow's lesson is 5 minutes.
Native <dialog> for anything that needs a decision; a toast for confirmation that needs no reply.
Mono only where the characters matter: keys, identifiers, code. Never for body copy.
--radius-surface: 12px
tabular-nums wherever they change.The assembled lesson screen: header ring, question, choices, feedback footer, tab bar — the whole flow in one 430px shell.
Scenario 2 of 3
You were looking forward to it. They sound stressed.
That asked before assuming
Three contrast failures in the reused tokens, each measured, each with a fix that keeps the app's look. The originals are untouched so existing screens do not shift; the new tokens sit beside them.
#ffffff on #f04b28. Already recorded in the app's own DESIGN-SYSTEM.md. Fix: filled actions use --color-action-strong #c9340f → 5.27:1. The orange stays for rings, marks and illustration.
#77808f on the canvas, used for 13px card copy. Fix: --color-course-description-aa #6d7684 → 4.52:1.
#828b99 on the canvas, used for 14px scenario copy. Fix: --color-lesson-description-aa #6d7685 → 4.52:1.
What a reviewer checks before anything ships.
--color-focus, 3px offset. Never outline: none.