Skip to content

DOL Design System - Core Style Guide

active v1.1Updated

Scope: Tất cả code surfaces - Playground, Wiki, HTML prototypes. Consumer chính: AI agents sinh code Tailwind CSS. File này là entry point duy nhất - đọc file này là đủ để build UI đúng chuẩn DOL.

Product-specific patterns (extends CORE):

Mỗi section trong product files có status:

  • done: Pattern canonical - build đúng theo recipe.
  • draft: Pattern hợp lý nhưng chưa final - dùng được, có thể thay đổi.
  • skeleton: Chưa có pattern - compose từ CORE.md primitives (§4-§9). KHÔNG invent pattern mới.

Khi gặp section skeleton hoặc topic chưa được cover: dùng component recipes (§9) + spacing (§4) + radius (§5) + shadow (§7) để compose. Không tạo convention mới ngoài scope CORE.


Triết lý: Sáng, rõ, premium vừa đủ.

Nguyên tắcÝ nghĩa
Pure White Boundary-lessNền trắng bg-white. Không chia lô section bằng dải xám luân phiên
Depth via border + shadowWhite-on-white bắt buộc border-slate-200. Shadow bổ trợ (xem §7)
Light-firstPage chính nền sáng. Không dark theme (trừ §6.3 exceptions)
Simple firstHierarchy từ spacing + typography, không từ hiệu ứng
One system, many accentsCùng shape language, khác accent theo domain
Reuse before inventDùng pattern có sẵn trước khi tạo biến thể mới
RoleFontWeight mặc định
Heading, DisplayPlus Jakarta Sansfont-bold đến font-black
Body, UI, LabelInterfont-normal đến font-semibold
Quote (editorial only)Noto Seriffont-normal đến font-semibold

Hard rule: Chỉ 2 font chính (Plus Jakarta Sans + Inter). Không thêm font thứ 3 trong bất kỳ surface nào.

IntentClass prefixCanonical (-600)Dùng cho
Brandbg-brand-*#D42525Logo, CTA chính, brand accent
Danger/Errorbg-red-*-Error, delete, dangerous action
Successbg-green-*-Correct, positive, complete
Warningbg-amber-*-Approaching deadline, review needed
Infobg-blue-*-Active state, progress, link
Specialbg-purple-*-Premium, gamification, special feature
  • Canonical shade = -600 (NOT -500 như TW default)
  • bg-brand-* là custom class - KHÔNG dùng bg-red-* cho brand
  • Brand Red ≠ Danger. Brand = CTA/accent. Danger = bg-red-* (error/delete)
  • Semantic aliases: bg-danger-*, bg-success-*, bg-warning-*, bg-info-*, bg-special-*
  • Giảm chrome trước khi thêm component: bỏ box/badge/divider/copy dư trước khi thêm hiệu ứng.
  • 1 shell per function group. Tránh card trong card, box trong box.
  • Utility UI mặc định boundary-light: ưu tiên spacing + alignment trước, surface sau.
  • Toolbar, side rail, icon stack, mini-nav: không dựng dark/tinted panel hoặc box cho từng child nếu layout vẫn đọc rõ khi bỏ lớp đó.
  • Quick actions: 1 hàng ngang. Overflow → affordance “xem thêm”, không bung multi-row.
  • Text chỉ truncate khi vượt viewport width, không cắt theo quota ký tự cố định.
  • Surface rối → bỏ wrapper/copy lặp trước, không siết typography hay nhồi biến thể màu.

TailwindDùng cho
text-slate-900Body paragraph, card title, page title (default cho mọi text chính)
text-slate-700Subtitle, secondary info, metadata
text-slate-600Helper text, dim info, category label
text-slate-500Placeholder, hint, disabled text

Hero heading cần nhấn thêm → text-slate-950. Nhưng text-slate-900 đủ cho hầu hết trường hợp. Không dùng pure text-black. slate-900 là darkest cho body text.

ClassGiá trịKhi nào
text-on-inverse-primary--white-w100Fixed white text/icon trên colored/inverse bg
text-on-inverse-secondary--white-w70Fixed white secondary text trên colored/inverse bg

Khi nào dùng on-inverse vs text-white:

Nền backgroundTextLý do
Colored/inverse bg cần fixed white: bg-brand-600, bg-blue-600, CTA colored surface…text-on-inverse-primary--white-w100
Theme-aware neutral pairing cần đổi theo theme: bg-slate-900, neutral solid, page chrome…text-white--neutral-n00; auto-flip theo palette-remap, không phải fixed white
Light neutral (50-200): bg-slate-100, bg-slate-50text-slate-700 hoặc text-slate-500Nền nhạt → text cần đậm hơn bg để đủ contrast
Light tint (50-400): bg-blue-50, bg-brand-100Dark text (text-slate-* hoặc text-{color}-700)Nền sáng → text tối

Lưu ý contrast (locked 2026-04-25, R23 a11y decision):

Family shadeon-inverse-primary (white) contrastAllowed scope
brand-600, red-600, blue-600, purple-600, rose-600✅ AA normal (≥ 4.5:1)Unrestricted - body text, button labels, badges
success-600 / green-600 / emerald-600⚠️ AA large text only (≥ 3:1, < 4.5:1)Button labels ≥ 14px semibold ONLY. For body/caption → text-{color}-700
warning-600 / amber-600⚠️ AA large text onlyButton labels ≥ 14px semibold ONLY. For body text use text-amber-700
sky-600⚠️ AA large text onlyButton labels ≥ 14px semibold ONLY. Body → text-sky-700
amber-500 / yellow-500❌ Fails even AA large on whiteNever use with white text - use dark text on light amber bg instead

Rule of thumb: if text-size < 14px OR font-weight < semibold → use shade -700 for the 4 flagged families (success, amber, sky, emerald). If text-size ≥ 14px AND semibold (typical button label) → shade -600 + on-inverse-primary OK.

Why locked this way: the 4 families’ -600 shades are visually part of DOL canonical palette; switching to -700 universally would shift brand perception. Restricting to button-label-only context preserves visual identity while meeting WCAG 2.1 AA for reasonable text sizes.

Mỗi status color có 3 usage levels:

LevelPatternSuccessErrorWarningInfo
Dim bgbg-{color}-50bg-green-50bg-red-50bg-amber-50bg-blue-50
Texttext-{color}-600text-green-600text-red-600text-amber-600text-blue-600
Strong bgbg-{color}-600bg-green-600bg-red-600bg-amber-600bg-blue-600
Borderborder-{color}-100border-green-100border-red-100border-amber-100border-blue-100

Bảng màu cố định - apply cho tag, badge, icon, section tint liên quan skill:

SkillTW FamilyTextBg TintStrong Bg
Readingemeraldtext-emerald-600bg-emerald-50bg-emerald-600
Listeningbluetext-blue-600bg-blue-50bg-blue-600
Writingambertext-amber-600bg-amber-50bg-amber-600
Speakingrosetext-rose-600bg-rose-50bg-rose-600
Full/Online Testpurpletext-purple-600bg-purple-50bg-purple-600
AI Featuresskytext-sky-600bg-sky-50bg-sky-600

Speaking dùng rose (NOT brand red). Brand red chỉ cho CTA/logo.

DomainAccent ColorCTA Class
IELTSRed (brand)bg-brand-600
SATCyanbg-cyan-600
TOEICBlue/Navybg-blue-700
COMMOrangebg-orange-600

Accent dùng cho CTA và nhấn owner - không biến cả section thành gradient.

ClassDùng cho
bg-whitePage base, card base
bg-slate-50Subtle tint (tab bar, segmented control)
bg-slate-100Progress track, small icon bg, hover state
border-slate-200Default border for cards/inputs/panels (white-on-white). Hover → border-slate-300. See §8.1.
border-slate-100Lighter divider (section-to-section) hoặc subtle separator. See §8.2.
  • bg-red-* cho brand → bg-brand-*
  • text-white trên vivid bg (500-600) → text-on-inverse-primary
  • text-on-inverse-primary trên bg-slate-900 neutral solid → text-white
  • gray-*, zinc-*, neutral-*slate-*
  • ❌ Hardcode hex trong class names
  • -500 là canonical → DOL canonical = -600
  • ❌ Brand red cho error/danger (brand ≠ danger)
  • ❌ >2 semantic accent colors cùng lúc trong 1 view
  • ❌ Accent color cho body text dài

RoleSizeTailwindWeight
Display xl64pxtext-[64px]font-black
Display lg56pxtext-[56px]font-bold to font-black
Display md48pxtext-5xlfont-bold
Display sm40pxtext-[40px]font-bold
Heading 2xl32pxtext-[32px]font-bold
Heading xl28pxtext-[28px]font-bold
Heading lg24pxtext-2xlfont-bold
Heading md20pxtext-xlfont-semibold to font-bold
Heading sm18pxtext-lgfont-semibold
Body lg16pxtext-basefont-normal
Body base14pxtext-smfont-normal
Body sm12pxtext-xsfont-normal
Label12pxtext-xs uppercase tracking-widefont-semibold

Body base (14px / text-sm) là default cho mọi body text.

ContextTailwindKhi nào
Decoration 1-line onlyleading-noneDisplay decoration, không cho content
Heading 1-2 linesleading-snugDefault cho heading
Body dense UIleading-tightTables, chips, compact metadata
Body defaultleading-normalStandard paragraphs (default)
Body reading 3+ linesleading-relaxedArticle, helper text, long copy
ContextSizeWeightLine-Height
Card titletext-lgfont-boldleading-snug
Card descriptiontext-smfont-normalleading-normal
Card metadatatext-xsfont-mediumleading-tight
Section headingtext-2xlfont-boldleading-snug
Page titletext-[28px] to text-[32px]font-boldleading-snug
Hero titletext-[40px] to text-[56px]font-bold to font-blackleading-tight
Button labeltext-smfont-semibold-
Form labeltext-xs uppercase tracking-widefont-semibold-
Helper/error texttext-xs to text-smfont-normalleading-normal
Utility surface (logged-in)text-sm (14px)font-normalleading-normal
  • Body baseline logged-in surfaces: 14px (text-sm). Không upscale lên 15-16px.
  • AI inline headings giữ 14px - hierarchy qua font-weight + spacing.
  • Max 3 font-size levels per card: title → body → label.
  • Heading phải nặng hơn body ≥1 weight level.
  • Paragraph copy ≥14px (never <13px - accessibility).
  • Metric values (%, band, count) được upscale. Topic text giữ body scale.
  • Micro-label có thể uppercase + tracking-wide, nhưng không lạm dụng.

Nguyên tắc: Generous - thoáng hơn mặc định. Spacing tạo hierarchy, không phải dividers.

LevelQuan hệGapVí dụ
A AtomIcon+label, inline elementsgap-1.5 to gap-2 (6-8px)Icon cạnh text trong button
B MoleculeLabel+input, title+subtitlegap-2 to gap-4 (8-16px)Form field group
C OrganismHeader+content, card internalsgap-4 to gap-6 (16-24px)Content stack trong card
D SectionBlock ↔ block, sectionsgap-8 to gap-12 (32-48px)Page-level sections
ContextTailwindGiá trị
Icon+text in buttongap-28px
Related items in groupgap-312px
Card content stackgap-416px
Standard card paddingp-520px
Large card/modal paddingp-624px
Between card groupsgap-6 to gap-824-32px
Page section gapgap-10 to gap-1640-64px
Page padding mobilepx-416px
Page padding tabletpx-624px
Page padding desktoppx-8 to px-1232-48px
Max content widthmax-w-6xl mx-auto1152px
  • Spacing giữa groups > spacing trong group → hierarchy rõ ràng.
  • Padding top/bottom ≈ hoặc > left/right → cân bằng visual.
  • Multiples of 4px. Không dùng arbitrary odd values.
  • Không dùng same spacing cho mọi level.
  • Min 12px (gap-3) giữa unrelated elements.
  • Ưu tiên spacing để phân tách → chỉ dùng divider khi spacing chưa đủ.

Nguyên tắc: Soft-large radius - friendly, modern. Radius tăng tỷ lệ theo element size.

Element HeightTailwindpx
h-6 (24px)rounded-md6px
h-8 (32px)rounded-lg8px
h-9 (36px)rounded-xl12px
h-10 (40px)rounded-xl12px
h-12 (48px)rounded-2xl16px
h-14 (56px)rounded-[20px]20px
h-16 (64px)rounded-3xl24px
TypeTailwindpx
Standard cardrounded-xl12px
Feature/elevated cardrounded-2xl16px
Large section blockrounded-3xl24px
TypeTailwindpx
Tooltip / small popuprounded-lg8px
Dropdown / Popoverrounded-xl12px
Modalrounded-2xl16px
Large modal / Bottom sheetrounded-3xl24px

rounded-full chỉ dùng cho: chip, capsule tag, status pill, avatar, circle control. KHÔNG rounded-full cho card, modal, input, button thường. Micro-badge / data cell nhỏ có thể dùng corner sắc hơn (e.g., rounded-md).


LevelBackgroundDepthDùng cho
1 - Pagebg-whiteFlat, boundary-lessNền page, không chia lô
2 - Cardbg-white + border + shadowNổi nhẹCard, panel, dropdown
3 - EmphasisBadge, glow, icon tile, accentNhấn nhẹStatus badge, progress
4 - HeroLayout + typography + accent blockVisual focusHero section (NOT dark slab)

Hero logged-in nổi nhờ layout + typography + accent + image tint nhẹ, không phải dark slab.

ContextClassKhi nào
Page basebg-whiteDefault cho mọi page
Tab bar / segmented controlbg-slate-50Subtle tint, boundary nhẹ
Floating tab (sticky, scroll)bg-white/70 backdrop-blur-xlGlass effect
Progress track, icon bg, hoverbg-slate-100Small element backgrounds

KHÔNG dùng bg-slate-100 cho tab/segmented containers → quá đậm, vi phạm boundary-less. KHÔNG chia section bằng dải bg-slate-50 / bg-[#f8fafc] luân phiên → phá boundary-less principle.

6.3 Dark Exceptions (chỉ 3 trường hợp)

Section titled “6.3 Dark Exceptions (chỉ 3 trường hợp)”
Cho phépVí dụ
BackdropOverlay, scrim, modal dimmer
Media frameVideo area, image lightbox
Utility floating UIAI helper panel nhỏ, dev tooling

KHÔNG biến hero, stats card, content block thành dark surface. KHÔNG mix section sáng/tối kiểu 2 themes trong cùng page.

Wireframe là layout structure, không tuân thủ boundary-less:

  • Border: border border-slate-200 (solid, rõ ràng)
  • Background: bg-slate-50/30 (tint nhẹ, phân biệt với UI mode)
  • Annotation: bg-blue-50 border border-blue-200

Tailwind shadow utilities are remapped to DOL neutral shadow tone in consuming projects. Use the familiar Tailwind class; the mapping layer gives it DOL depth.

TailwindDS sourceKhi dùng
shadow-sm / shadowshadow-neutral/to-bot/1Card nhẹ, input group, white-on-white surface
shadow-mdshadow-neutral/to-bot/2Dropdown nhỏ, sticky nhẹ, popover nhẹ
shadow-lgshadow-neutral/to-bot/3Hover card, raised panel
shadow-xlshadow-neutral/to-bot/4Modal, sheet, prominent overlay
shadow-2xlshadow-neutral/to-bot/5Hero floating, coachmark, rare premium emphasis

Card đứng riêng (dashboard, feature card) - hover tăng border + shadow:

Default: border border-slate-200 shadow-sm
Hover: hover:border-slate-300 hover:shadow-lg
Always: transition-all duration-300

Card trong list/grid - hover chỉ đổi background, KHÔNG thêm border/shadow:

Hover: hover:bg-slate-50
  • Khi card cha đổi bg hover → BỎ HẲN hover:border-* ở cha và group-hover:shadow-* ở icon con.
  • Background tint đã đủ phân tách visual.

Khi card thuộc domain/skill cụ thể, shadow tint theo accent (opacity giữ trong tier):

DomainTailwind
Blue/Infoshadow-lg shadow-info-600/10
Brandshadow-lg shadow-brand-600/10
Successshadow-lg shadow-success-600/10
  • KHÔNG shadow-xl, shadow-2xl cho card default → quá đậm. Dùng shadow-sm.
  • Max 2 elevation levels per view.
  • Shadow transition luôn kèm transition-all duration-300 (card lớn: duration-500).
  • Colored shadow chỉ khi có intent rõ ràng (brand/AI/skill accent).
  • Border + shadow kết hợp: border border-slate-200 shadow-sm.

Khi element bg-white nằm trên white surface:

  • Bắt buộc border border-slate-200.
  • Shadow là bổ trợ, không thay thế border.
  • Rule: Border là nền tảng, shadow là gia vị.
  1. Spacing trước divider - phân tách bằng khoảng trống trước. Nếu spacing đủ rõ hierarchy → không cần divider.
  2. Khi cần divider: border-slate-200 (standard) hoặc border-slate-100 (nhẹ, tinh tế).
  3. KHÔNG border-slate-50 hoặc divide-slate-50 trên nền trắng → ~1% contrast, invisible.
  4. Card CTA area: KHÔNG border-t tách CTA. Dùng pt-6 spacing thay thế.
  5. border-slate-50 chỉ OK khi surface background đã tối hơn white (e.g., trên bg-slate-100).

<div class="bg-white border border-slate-200 rounded-xl p-5
shadow-sm
hover:border-slate-300 hover:shadow-lg
transition-all duration-300">
<h3 class="text-lg font-bold text-slate-900">Title</h3>
<p class="mt-3 text-sm text-slate-600">Description</p>
</div>
<button class="bg-brand-600 text-on-inverse-primary hover:bg-brand-700
rounded-lg px-4 py-2.5 text-sm font-semibold
transition-colors">
Label
</button>
<button class="bg-white text-slate-700 border border-slate-200
hover:bg-slate-50
rounded-lg px-4 py-2.5 text-sm font-semibold
transition-colors">
Label
</button>
<button class="bg-blue-600 text-on-inverse-primary hover:bg-blue-700
rounded-lg px-4 py-2.5 text-sm font-semibold
transition-colors">
Label
</button>
<input class="w-full border border-slate-200 bg-white text-slate-900
placeholder:text-slate-500
focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20
rounded-lg px-3 py-2.5 text-sm"
placeholder="Placeholder text" />

Error state:

<input class="w-full border border-red-500 bg-red-50 text-red-900
focus:ring-2 focus:ring-red-500/20
rounded-lg px-3 py-2.5 text-sm" />
<!-- Status badge -->
<span class="bg-green-50 text-green-600 px-2.5 py-1 rounded-full text-xs font-medium">
Active
</span>
<!-- Skill tag -->
<span class="bg-emerald-50 text-emerald-600 px-2.5 py-1 rounded-full text-xs font-medium">
Reading
</span>
<!-- Error -->
<div class="bg-red-50 border border-red-200 text-red-700 p-4 rounded-xl text-sm">
Error message here.
</div>
<!-- Warning -->
<div class="bg-amber-50 border border-amber-200 text-amber-800 p-4 rounded-xl text-sm">
Warning message here.
</div>
<!-- Success -->
<div class="bg-green-50 border border-green-200 text-green-700 p-4 rounded-xl text-sm">
Success message here.
</div>
<!-- Info -->
<div class="bg-blue-50 border border-blue-200 text-blue-700 p-4 rounded-xl text-sm">
Info message here.
</div>
<div class="fixed inset-0 bg-black/50 flex items-center justify-center p-4">
<div class="bg-white rounded-2xl shadow-xl
p-6 max-w-lg w-full">
<h2 class="text-xl font-bold text-slate-900">Modal Title</h2>
<p class="mt-3 text-sm text-slate-600">Content goes here.</p>
<div class="mt-6 flex gap-3 justify-end">
<button class="bg-white text-slate-700 border border-slate-200
hover:bg-slate-50 rounded-lg px-4 py-2.5 text-sm font-semibold">
Cancel
</button>
<button class="bg-brand-600 text-on-inverse-primary hover:bg-brand-700
rounded-lg px-4 py-2.5 text-sm font-semibold">
Confirm
</button>
</div>
</div>
</div>
<div class="bg-white border border-slate-200 rounded-xl
shadow-md p-1.5 min-w-[200px]">
<button class="w-full text-left px-3 py-2 text-sm text-slate-700
hover:bg-slate-50 rounded-lg transition-colors">
Option 1
</button>
<button class="w-full text-left px-3 py-2 text-sm text-slate-700
hover:bg-slate-50 rounded-lg transition-colors">
Option 2
</button>
</div>
<header class="bg-brand-600 text-on-inverse-primary p-6">
<h1 class="text-xl font-bold">Title</h1>
<p class="text-on-inverse-secondary text-sm">Subtitle</p>
</header>

Khi button không có visible label (icon-only - toolbar segmented control, view-mode switcher, filter pill icon), BẮT BUỘC có cả title (tooltip) lẫn aria-label (screen reader). Cả hai dùng cùng một string, static, không nội suy động.

<!-- Standalone icon button -->
<button type="button"
title="Grid view"
aria-label="Grid view"
class="inline-flex items-center justify-center
h-8 w-8 rounded-lg border border-slate-200
text-slate-600 hover:bg-slate-50 hover:border-slate-300
transition-colors">
<svg class="h-4 w-4" aria-hidden="true"></svg>
</button>

Rules:

  • title text = aria-label text (consistency cho keyboard + mouse user).
  • Icon SVG: aria-hidden="true" (parent button đã announce, tránh double-announce).
  • Hit target tối thiểu h-8 w-8 (32×32px) - không nhỏ hơn cho touch.
  • Khi build segmented/toggle icon group: primitive (ToggleGroupItem) PHẢI accept + forward title prop, internally set aria-label từ cùng giá trị.
  • Anti-pattern: icon-only button KHÔNG có aria-label → screen reader đọc “button” trống; user mới gặp tooltip cũng không có hint.

  • Hover/focus: transition-colors duration-200 (button) hoặc transition-all duration-300 (card).
  • Large card / feature block: duration-500.
  • Motion phải ngắn, có mục đích: hover lift, reveal, dropdown, state transition.
  • Nếu interaction vẫn rõ khi bỏ animation → giữ animation. Nếu không → bỏ.
  • Avoid: hiệu ứng phô diễn trên logged-in surfaces.
  • Layout transitions: 150-300ms ease-out. Không instant.
  • Loading state: skeleton, spinner, hoặc “Đang tải…” - không để blank.

🛑 Match-and-refuse (per DIRECTION §10): nếu code bạn sắp emit khớp một row dưới, STOP - rewrite element approach từ đầu, không chỉ swap value. CORE §11 = universal quick-ref; xem DIRECTION §10 cho 10 named slop patterns + WHY.

📐 Named pattern exceptions: một số rule (đặc biệt core-11-layout row 04 “Card trong card”) có named pattern exceptions - pattern dùng nesting INTENTIONALLY với different treatment per tier (e.g., Constellation Block 3-tier). Trước khi refuse nesting/composition, check ../pattern-registry.md để xem có named pattern exception không.

<dol_anti_pattern scope=“core-11-layout”>

ID❌ Không làm✅ Thay bằng
01Content >1280px không max-widthmax-w-6xl mx-auto hoặc max-w-7xl
02Page padding <16px mobileMin px-4 mobile, px-6 tablet, px-8 desktop
03Sections không gapgap-10+ giữa page sections
04Card trong card, box trong box1 shell per function group
05Grid quá đều, không focal pointCho phép 1-2 elements lớn/prominent hơn
06Content chia lô xám/trắng luân phiênbg-white boundary-less

</dol_anti_pattern>

<dol_anti_pattern scope=“core-11-color”>

ID❌ Không làm✅ Thay bằng
01Brand red cho error/dangerBrand red = CTA/accent. Danger = bg-red-*
02>2 accent colors cùng lúc1 brand + 1 status per context
03White card trên white bg không borderborder-slate-200 bắt buộc
04Blue cho mọi thứ prominentBlue = progress/info/active/link. Prominent = brand
05Gradient full pageHero/header only. Body neutral

</dol_anti_pattern>

<dol_anti_pattern scope=“core-11-typography”>

ID❌ Không làm✅ Thay bằng
01>3 font sizes trong 1 cardMax 3: title → body → label
02Body <13pxMin 14px (text-sm)
03Heading cùng weight với bodyHeading nặng hơn ≥1 level
04>4 text colors per viewStick to semantic roles: primary/secondary/dim/placeholder
05Mixed-language drift trong copyVietnamese nhất quán cho affordances

</dol_anti_pattern>

<dol_anti_pattern scope=“core-11-spacing-depth”>

ID❌ Không làm✅ Thay bằng
01Shadow quá đậm (shadow-xl/shadow-2xl cho card default)shadow-sm default, max 2 levels per view
02Padding 4 phía khác nhau bất đối xứngMultiple of 4px. Top/bottom ≈ left/right
03<8px giữa unrelated elementsMin 12px (gap-3) giữa unrelated
04Divider thay spacingSpacing trước, divider nếu thật sự cần

</dol_anti_pattern>

<dol_anti_pattern scope=“core-11-interaction”>

ID❌ Không làm✅ Thay bằng
01Button không hover/focus stateMin hover brightness hoặc bg change
02Click target <32pxMin 36px interactive, 44px primary actions
03Loading state blankSkeleton hoặc loading indicator
04Card hover thêm border + shadow + bg cùng lúcStandalone: border + shadow. List item: bg only
05Icon con bung shadow khi card cha hoverChỉ card cha thay đổi - con giữ nguyên

</dol_anti_pattern>

Tailwind v4 hỗ trợ @theme, arbitrary values, và custom-property shorthand. Các rule dưới đây là DOL workspace convention để giữ codebase deterministic - không phải giới hạn kỹ thuật của TW.

<dol_anti_pattern scope=“core-11-tailwind”>

ID❌ Không làm✅ Thay bằngLý do
01Dynamic class: `bg-${color}-600`Static class đầy đủ: bg-blue-600. Map prop sang static stringsTW scan tĩnh, class động bị tree-shake
02bg-(--token) hoặc var(--token) trong classStandard Tailwind numeric: bg-brand-600Anti-drift: giữ single naming convention
03gray-*, zinc-*, neutral-*slate-*DOL dùng slate family duy nhất
04Hardcode hex trong class namesDùng Tailwind palette classesConsistency + dark mode support

</dol_anti_pattern>


Khi build cho DOL Kid domain, override các rule sau. Mọi rule khác trong CORE.md giữ nguyên.

AspectGeneral DOLKID Override
Heading fontPlus Jakarta SansQuicksand
Body fontInterQuicksand
Visual feelProfessional-warmCute but calm, playful but not noisy
Content densityStandard1 objective, 1 message, 1 CTA per screen
Spacing microgap-2 (8px)gap-2 (8px) - same
Spacing componentgap-3 to gap-4gap-3 to gap-4 (12-16px)
Spacing card paddingp-5 to p-6p-5 to p-6 (20-24px)
Spacing sectiongap-6 to gap-8gap-6 to gap-8 (24-32px)
Color paletteGM (General Mode)KM (Kid Mode) - 12 families remapped

KID color mapping: xem DOL-DS-token/docs/tailwind-color-guideline.md §KM. Radius, shadow, border, surface hierarchy → giữ nguyên theo CORE.md.


Khi cần tra cứu chi tiết hơn CORE.md:

TopicFileRepo
AI agent entry for code UI task (router + hard rules + self-check)../ai-entry/CODE-UI.mdDS-Token
Color mapping đầy đủ (18 families)../../docs/tailwind-color-guideline.mdDS-Token
Color system rules (34 rules)../../docs/color-system-rules.mdDS-Token
AI color quick-ref (mapping table + safe/unsafe classes)../../docs/ai-color-context.mdDS-Token
Design philosophy + cross-topic anti-patterns../ds-guideline/DIRECTION.mdDS-Token
Named composition patterns (cross-product)../pattern-registry.mdDS-Token
Typography design intent../ds-guideline/typography.mdDS-Token
Color design intent../ds-guideline/color.mdDS-Token
Radius design intent../ds-guideline/radius.mdDS-Token
Spacing design intent../ds-guideline/spacing.mdDS-Token
Shadow/Effects + style layer precedence../ds-guideline/shadow.mdDS-Token
KID basic guideline../kid/Design System Guideline/KID_DS_Basic_Guideline.mdDS-Token

CORE.md đã distill toàn bộ actionable rules từ các file trên. Chỉ tra deep reference khi cần hiểu tại sao một rule tồn tại hoặc edge cases phức tạp.

Cho AI agent: nếu task là build/modify UI code, start tại ../ai-entry/CODE-UI.md (router + safety-net rules) thay vì đọc CORE.md full ngay.