← Back to Blog
Design··10 min read

Taegeuk — dani.korea leaves DDS

dani.korea no longer follows the dani design system. It now specifies 20px cards, pill buttons, soft elevation, full-bleed photography and Manrope — and takes its two accents straight from the 태극기.

The system itself
Open Taegeuk →

57 screens in both dark and light mode, plus the flow that connects them — every screen in the product, drawn. This article is the release note. That is the design.

Browse the system →

Every other dani product renders DDS: 4px radii, no pills, no shadows, no circles, mono labels in caps, one accent per product. dani.korea used to be one of them, with a navy accent bolted on. On 2026-08-05 that stopped. What replaced it is called Taegeuk, and it is not a DDS variant — it is a separate base system that happens to live in the same company.

01 · Why dani.ko left DDS

Ted, 2026-08-05
“UI overhaul. The UI is too monotone, boring, unimpressive. Users are planning for an exciting visit to Korea.”

He raised five things and three of them were information architecture rather than styling — sections leading with a summary and a checklist, lists grouped and ranked, the trip as the one container that holds everything. Two were about the surface, and the surface is where DDS binds: “the logo color is too close to black,” and “Korean flag has blue and red — I think we should use those exact colors.”

There was no version of that brief DDS could absorb. Its rules — 4px radii, no pills, no shadows, no circles, no motion, mono labels in caps — are the opposite of what was being asked for. dani.ko now specifies 20px cards, pill buttons and tags, soft elevation, full-bleed photography and Manrope. That is a different system, so it was made one.

What this costs

Written down plainly so nobody is surprised mid-refactor. Leaving a design system is not a theme swap; it is a component rewrite.

ThingConsequence
DotCard / DotButton / DotChip / DotListItem / DotSectionHeaderReplaced by DaniKo* equivalents. They are used across all 42 screens.
Deviations justified by “DDS prohibits pills / motion / circles”Moot. Those deviations are struck — the prohibitions no longer apply.
dot_flutter path depStill needed, for dotTypeScaleFor() and the viewport ramp. Not removed, just not used for surface styling.
dot-tokens.yaml § brand_colors.koFixed. Flag Blue — #0047A0 light, #3D7BD9 dark — as of 2026-08-05. The row said #000080 until 2026-08-30 and was itself the stale thing.
What was NOT edited
dot_flutter and shared/design/dot-tokens.yamlare shared with dani.go and every other dani product. Not one of those files was changed to make this happen. dani.ko owns its own theme and its own widgets and stops consuming DDS's visual layer, which is precisely what keeps dani.go's rendering exactly where it was. A product may leave the system; it may not take the system with it.

02 · The accent is the flag

Two accents, taken exactly from the 태극기, each with one job. Blue is structure. Red is either a date or a danger — §03 below is the boundary that keeps those two from blurring.

TokenLightDarkJob
blue#0047A0#0047A0Navigation, primary buttons, progress, structure
on_blue#FFFFFF#FFFFFFText on a blue fill — 8.6:1
red#CD2E3A#CD2E3AA date, or a danger — and nothing else
on_red#FFFFFF#FFFFFFText on a red fill — 5.2:1
blue_text#0047A0#3D7BD9The one lift — thin blue text on dark
black / white#000000#FFFFFFThe trigrams and field of the flag; ink and surface

Note what the first four rows are saying: light and dark are the same hex. Every filled shape is the exact flag colour in both modes — no tuned pair, no dark-mode lift. The single deviation is blue_text, and it exists because it was measured.

PairContrastVerdict
#FFFFFF on #0047A08.6:1Fills are the exact flag blue in both modes
#FFFFFF on #CD2E3A5.2:1Fills are the exact flag red in both modes
#CD2E3A as text on #0D11173.66:1Flag red needs no lift anywhere. Stays exact
#0047A0 as text on #0D11172.41:1Unreadable. #3D7BD9 (4.55:1) is used instead

The lift applies only where blue is thin text or an icon sitting directly on the dark background — the readiness number, section numerals, the active tab label.

The precedent
This is the same failure Dot Navy had, caught before shipping rather than after. #000080 measured 1.31:1 on black, and that liability sat open in TODO.md for two days. #0047A0 is better but still under the 3:1 floor, so it gets the same treatment for the same reason. Do not “fix” blue_text back to #0047A0.

03 · Red has two senses and they never share a shape

Red means a date or a danger. Nothing else, ever. That is a much narrower licence than most systems give their warning colour, and it is narrow on purpose: a red that means everything means nothing, and the whole reason this palette works is that the one red thing on a screen is either the thing you must do this week or the thing that can put you in hospital.

✓ Red is earned by
  • · A date or a time on it — overdue, due-soon, not-yet-filed
  • · A drawn subject that can injure a person
  • · A blocking conflict, which is time-bound by definition
× Red is never
  • · Emphasis
  • · Branding
  • · Expense
  • · A rule you have broken
  • · A destructive action that is neither time-bound nor dangerous
And they never share a shape
Deadline red lives in the chrome — a row border, a tag, a container fill, a line of text. Danger red lives inside a drawn diagram and nowhere else, as the subject of the drawing: the thing that can hurt you. A deadline inside a picture is not red at all; it is a wall, uncoloured, with hatching beyond it. So the two senses cannot appear as the same thing, which is the answer to how a reader tells them apart when both are on screen.

The test is only ever can this injure the reader — not “is this expensive” and not “do people get this wrong a lot”. A 7.1% currency conversion on $1,000 is not red. A missed last train is not red; it is a wall. An overstay fine and entry ban is not red — that is your record and your plans, not your person. An earthquake alert is red.

04 · A cool neutral base, not pure black

The old base was pure #000000 / #F7F7F7. Both are replaced, for two reasons that only show up once photography leads: pure black under a full-bleed image produces a hard seam at every image edge, and a cool neutral sits with flag blue where a warm one fights it.

TokenLightDark
bg#F7F8FA#0D1117
surface#FFFFFF#161B22
surface_2#EEF1F5#1D242E
border#DDE2E9#28313D
text#0E1420#F0F3F7
text_2#54606F#A2AEBD
text_3#8593A3#6E7B8B
blue_soft#E3ECFA#0E1D38
red_soft#FDE7E9#2E1216

blue_soft and red_soft are the container fills behind summary blocks and urgent rows. They are tinted, not tonal-mapped.

Light mode is not an inversion. The two modes carry depth by different means: borders carry it on light, soft elevation carries it on dark. Flipping one to get the other is how an inverted theme ends up with shadows nobody can see.

05 · Manrope and DM Mono

Manrope for everything the user reads. DM Mono for everything the user copies. Chosen 2026-08-05 from four candidates shown side by side; Space Grotesk and Space Mono are retired, and the serif alternative was rejected in the same pass.

TokenSizeWeightFamilyUsage
display34700ManropeScreen headline — “Korea, planned before you fly.”
display_sm27700ManropeTrip name over the hero photo
title25700ManropePlace names on detail
heading18700ManropeCard titles
body14400/600ManropeList rows, task titles
body_sm12.5400ManropeSecondary lines, descriptions
label10.5700ManropeEyebrows and section labels, uppercase, .15em tracking
data12500DM MonoEvery ID, PNR, price, date and confirmation number
amount34700ManropeThe readiness numeral

The rule that caused the rejection

Display weight is capped at 700. Tracking is −0.3px. Leading is 1.16. The rejected proposal used 900 at −1.6px tracking and 0.94 leading, and Ted's note was “font is too bold they look bunched up”. That is not a taste disagreement — the three values compound, and 0.94 leading on a 900 weight makes descenders touch the next line's caps. Do not raise any of the three.

dart
// display — the cap, and all three numbers together
fontSize: 34, fontWeight: FontWeight.w700,
letterSpacing: -0.3, height: 1.16,

Numbers are always DM Mono. Every ID, PNR, price, date and confirmation number. A passport number, a PNR, a confirmation code and a price are things a person reads character by character or copies into another app, so they get tabular figures. This is not up for restyling.

06 · Pills, 20px radii, soft elevation

The 4px spacing grid survives the move — xs 4 · sm 8 · md 12 · lg 16 · xl 20 · xxl 24, with screen padding 20, card padding 17, card gap 9 and section gap 23. Almost nothing else about the geometry does.

✓ Radii
  • · Cards — 20
  • · Tasks and doc rows — 18
  • · Buttons — 16
  • · Photo tiles — 16–22
  • · Hero — 22
  • · Tags and chips — full pill
  • · Frames — 40
✓ Borders and elevation
  • · Hairline 1px is still the default
  • · 1.5px on secondary buttons
  • · The only 2px is a red urgent border
  • · Elevation light — 0 10px 28px rgba(15,35,70,.10)
  • · Elevation dark — 0 14px 36px rgba(0,0,0,.55)
  • · Used on the frame and on nothing inside it
Say it plainly
This reverses DDS's “no shadows, ever” and “no pills, no circles”. Both were real rules and dani.ko no longer follows them. Pills are now the tag and button shape; the checkbox is a circle.

07 · Photography leads

The original constraint was that place cards are photo-optional by default, with a category glyph as the normal state, because no API provides photographs of ordinary Korean venues. That is still true of the world. It stopped being true of dani.ko on 2026-08-06, when 1,102 photographs from 한국관광공사 포토코리아 came in hand under 공공누리 제1유형 — commercial use and derivatives permitted, attribution required.

So the rule is both, in that order. Where we hold coverage, a real photograph carries the hero — the brief was “show a lot of images on every page we can”, and this is what makes that literally true. Where we do not, a drawn scene carries it.

The drawn scenes are the designed fallback, not a placeholder
Never an empty frame and never a broken-image glyph. Coverage will never be complete, and the fallback is what makes a gap look intentional rather than failed. A drawn scene also renders in airplane mode, on the one day a traveller has no data and it matters most; a photograph not yet on the phone is a grey box. Five scenes in one grammar read as a product where fifty mismatched stock photographs read as a directory.

One exception, and it is a product boundary rather than a visual one: places the user adds have no guaranteed photograph. Those are a different card, not a broken one.

08 · What survives

Leaving a design system is not permission to relitigate everything. These are product rules rather than style, and none of them changed:

English-first naming

Every user-visible name reads English (한국어) — and copy buttons always copy the Korean.

Safe areas

Non-negotiable, and shipped broken twice already, which is exactly why it stays written down.

Provenance on every externally-sourced surface

A richer surface must not manufacture confidence. A photograph never implies we checked the opening hours.

All text selectable

Including the cross-fade transition that exists to protect it.

unknown stays neutral and never red

An honest gap is not an error. A red unknown reads as “you did something wrong” when the thing missing is ours.

Confidence is still not a palette

verified / stale / unknown / blocking remain icon and word, not hue. Exactly one colour is added back:

StateLightDark
verified / done#12855A#4ADE80
everything elseneutralneutral

unknown stays neutral grey with a dashed border. stale carries a date and no colour. blocking uses the flag red, because a blocking conflict is by definition time-bound.

09 · What was not adopted

Taegeuk was one of four proposals and it did not win alone — it absorbed two of the others. Every proposal is kept as reference, with what is worth going back for.

ProposalVerdictWorth revisiting
A · PostcardLayout adopted wholesale into D—
B · CompassNot adoptedFilled tonal containers made status unmissable. Borrow if red-means-deadline proves too subtle
C · PassportReadiness spine adopted into DThe per-shelf colour system, and the passport stamp for completed items
A · LedgerRetiredIts provenance discipline survives in §6.2
B · Passport / C · AtlasRetiredC’s cluster canvas, if S-31 ever gets revisited