| name | Ongil (온길) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| description | 멀리 있어도 곁에 있는 것 같은 복약 관리 서비스 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colors |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typography |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rounded |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| spacing |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| components |
|
Creative North Star: "The Caring Distance"
Ongil exists for adult children who need to know, right now, whether their parent took their medication today. This design system bridges that distance emotionally. The moment the app opens, the information lands — and within three seconds, the user should feel the quiet relief of "they're okay."
The aesthetic is grounded in warm certainty. Trust is not built through decoration; it is built through clarity. A single Steadfast Blue used sparingly, a clean Ink neutral palette, a single typeface optimized for mobile, shadows only as functional signals — every decision follows the same principle: information first. Success is when the user forgets they are using an app.
This system explicitly rejects: hospital and pharma UI (white backgrounds with blue icons, clinical institution feel), senior-app patterns (oversized text, primary-color buttons, aggressively simplified UI), SaaS dashboard aesthetics (charts, metrics, data-analysis tool feel), and KakaoTalk/Naver clones (generic Korean platform style, indistinguishable from big-tech apps). Ongil is not a medical device, not a senior-facing app, not a productivity tool. It is a caring family member's tool.
The implementation layer is shadcn/ui primitives (Button, Card, Dialog, Drawer, Sheet) restyled to these tokens via Tailwind CSS v4's @theme inline. The View Transitions API is active for app shell continuity: the header and bottom nav persist visually across navigations. iOS safe area insets protect content from notch and home indicator overlap.
Key Characteristics:
- Single primary action color: Steadfast Blue (oklch(54% 0.21 256)); everything else is Ink Neutral
- Single typeface: Pretendard Variable; mobile-optimized 8-step scale (11px–30px)
- Flat by default; three shadow levels for tappable and floating elements only
- Three-layer surface hierarchy: Card White (100%) → Canvas (99%) → Surface-2 (98.5%)
- 390px max-width mobile layout; spacing rhythm creates visual hierarchy
- Color codes map directly to time-of-day (morning/noon/night) and status (done/caution/danger)
- Seven-level z-index vocabulary for predictable layer stacking
kr-wraputility enforces Korean word-break rules across all paragraph and list text
A single chromatic family (Blue), two functional signal colors (Amber, Red), and a quiet Ink Neutral. Not colorful. That restraint is the source of trust.
- Steadfast Blue (oklch(54% 0.21 256)): Default buttons, links, active state indicators, morning medication time indicator, active navigation icons, selected calendar day background. Appears on ≤10% of any given screen.
- Steadfast Blue Light (oklch(97% 0.015 256)): Secondary button backgrounds, accent backgrounds, hover state fills, active state backgrounds. A diluted echo of Steadfast Blue.
- Steadfast Blue Medium (oklch(94% 0.04 256)): Medication color-coding (blue family) backgrounds, icon container backgrounds.
- Steadfast Blue Deep (oklch(47% 0.2 256)): Brand link color, account switcher text, chevron icon color, medication color-coding (blue) text. The hover state of the primary button.
- Steadfast Blue Deeper (oklch(38% 0.17 256)): Text color on Steadfast Blue Light accent backgrounds (e.g., accent chip labels, accent-foreground).
The Ink scale runs from near-black to near-white, every step tinted toward hue 255. Use the correct layer for the correct surface depth.
- Card White (oklch(100% 0 0)): Card interiors only. Pure white is reserved strictly for card backgrounds — never for page surfaces or app shell.
- Canvas (oklch(99% 0.004 255)): The primary content area. The 390px max-width zone. Faintly cooler than pure white.
- Surface-2 / App Shell (oklch(98.5% 0.006 255)): Page background outside the content zone, header bar background, bottom navigation background. Slightly deeper than Canvas, creating the "lifted paper" effect: content rises off the shell.
- Ink Muted (oklch(96% 0.006 255)): Secondary content backgrounds, muted section fills.
- Ink Border (oklch(91% 0.008 255)): Borders, dividers, input stroke, hairline separators.
- Ink Avatar (oklch(84% 0.008 255)): Avatar and icon container placeholder fills.
- Ink Icon Inactive (oklch(70% 0.007 255)): Inactive bottom navigation tab icons and labels.
- Ink Subtle (oklch(52% 0.01 255)): Placeholders, inactive state text, supplementary information.
- Ink Text (oklch(38% 0.011 255)): Secondary body text, form labels, icon-only action buttons (e.g., notification bell).
- Deep Ink (oklch(18% 0.012 255)): Headings, core body text. Not pure black — a very dark neutral cooled toward hue 255.
- Completion Green (oklch(52% 0.14 155)) / BG (oklch(97% 0.025 155)): Medication taken. The color of relief. The visual implementation of PRODUCT.md's "make completion visible."
- Caution Amber (oklch(78% 0.17 80)) / BG (oklch(97% 0.025 80)): Noon medication time indicator, caution states.
- Alert Red (oklch(53% 0.21 27)) / BG (oklch(97% 0.018 27)): Missed dose alerts, night medication time indicator, destructive actions.
The One Voice Rule. Steadfast Blue appears on ≤10% of any given screen. One button, one status, one link. More than that is already too many. Its rarity is what makes it trustworthy.
The Tinted Neutral Rule. Pure white (oklch(100% 0 0)) is reserved for card backgrounds only. Every page surface uses a neutral cooled toward hue 255. There are three distinct surface levels; use the right one for the right layer.
The Lifted Paper Rule. Canvas (99%) sits inside Surface-2 (98.5%): the content zone is lighter than the app shell. This half-step of contrast creates depth between the content area and its frame without any shadow or border. If you flatten them to the same value, the depth disappears.
Body Font: Pretendard Variable (local variable font, weight range 45–920) Fallback: 'Pretendard', sans-serif
Character: One typeface only. As a variable font, weight transitions are smooth, and it is built for Korean readability. Hierarchy is created through size, weight, and color alone. There is no second typeface.
Eight steps optimized for a 393pt mobile viewport:
- Display (700, 1.875rem/30px, lh 1.2, ls -0.025em): Onboarding screens, the single message of a key screen. Used sparingly.
- Headline (700, 1.4375rem/23px, lh 1.3, ls -0.02em): Page titles, section headers. A 1.625rem/26px variant (same weight and tracking) is available for prominent section headers when the headline-to-display gap is too large.
- Title (600, 1.1875rem/19px, lh 1.4, ls -0.01em): Card titles, important status labels.
- Body (400, 0.9375rem/15px, lh 1.55): Primary body text. Optimized for readability on a 390px mobile viewport.
- Caption (400, 0.8125rem/13px, lh 1.45): Secondary descriptive text, card subtitle text, supplementary metadata below a primary value.
- Label (500, 0.75rem/12px, lh 1.4): Status badges, timestamps, chip text.
- Small Label (400–500, 0.6875rem/11px, lh 1.4): Bottom navigation labels, calendar day-of-week indicators, highly supplementary context text.
The Single Typeface Rule. Pretendard only. Never add a second typeface.
The Negative Tracking Rule. All text at 1.1875rem (19px) and above gets negative letter-spacing: title -0.01em; headline -0.02em; display -0.025em. Prevents large text from feeling loose.
The Korean Wrap Rule. Paragraphs, list items, and definition lists get word-break: keep-all; overflow-wrap: anywhere via the kr-wrap utility class. Korean text must not break mid-word. Apply kr-wrap explicitly rather than relying on browser defaults.
This system is flat by default. The three-layer tonal surface hierarchy (Surface-2 → Canvas → Card White) creates baseline depth without any shadows. Shadows appear only on elements that are physically tappable or floating above the surface — never as decoration.
- shadow-card (
0 1px 4px oklch(16% 0.04 255 / 0.08), 0 0 1px oklch(16% 0.04 255 / 0.06)): Information cards, content containers. Nearly imperceptible separation from the canvas surface. - shadow-raised (
0 4px 16px oklch(16% 0.04 255 / 0.12), 0 1px 4px oklch(16% 0.04 255 / 0.08)): Modals, sheets, drawers. Signals a layer clearly elevated above the background. - shadow-fab (
0 4px 12px oklch(54% 0.21 256 / 0.3)): Floating action buttons, CTA buttons, the bottom nav registration disc, selected calendar day buttons. Carries a Steadfast Blue tint in the shadow to draw attention.
Seven named layers for predictable stacking. Every z-index in the codebase must reference one of these names.
- z-base (0): Default in-flow elements.
- z-raised (10): Slightly elevated in-page elements (popovers, inline tooltips).
- z-dropdown (100): Menus, autocomplete suggestions.
- z-sticky (200): App header, sticky page headers.
- z-overlay (300): Semi-transparent page overlays behind modals.
- z-modal (400): Modal dialogs, full-screen sheets, drawers.
- z-toast (500): Toast notifications. Always top of stack.
@view-transition { navigation: auto } is active globally. Two shell elements carry named transitions: app-header (view-transition-name: app-header) and bottom-nav (view-transition-name: bottom-nav). New component-level transitions must use unique names; these two are reserved.
The Functional Shadow Rule. There are exactly three shadows: shadow-card, shadow-raised, shadow-fab. No arbitrary shadows are added. Do not apply shadow-card to elements that are not cards.
Gently rounded but never soft. Primary is Steadfast Blue alone; everything else steps quietly back.
- Shape: Default rounded-md (0.625rem/10px); CTA uses rounded-2xl (1.25rem/20px)
- Primary: Steadfast Blue background, white text, h-9 (2.25rem), px-4 py-2; transitions to Steadfast Blue Deep on hover
- CTA (full-width Primary): rounded-2xl, h-14 (3.5rem), w-full, shadow-fab, font-bold; one per screen maximum
- Destructive: Alert Red background, white text
- Outline: Ink Border stroke (1px), Canvas background; Steadfast Blue Light background on hover
- Ghost: No background; Steadfast Blue Light background on hover
- Icon: Square h-9 w-9 (2.25rem × 2.25rem), rounded-md; no background by default; used for icon-only actions
- Small (sm): h-8 (2rem), px-3, text-xs, rounded-md; for compact inline actions where h-9 is too tall
- Focus: ring-1 (Steadfast Blue 1px ring), shown on focus-visible only
The basic unit for containing information. Nesting is prohibited.
- Corner Style: rounded-xl (0.75rem/12px)
- Background: oklch(100% 0 0) card white
- Shadow: shadow-card at rest; shadow-raised is for modals and drawers only
- Border: None on the card itself; internal dividers use Ink Border (oklch(91% 0.008 255))
- Internal Padding: p-6 (1.5rem) default; p-4 (1rem) allowed in compact mobile layouts
홈 화면 최상단에 오늘 복약 현황을 요약하는 히어로 카드. 의도된 다크 배경 변형으로, 일반 Card White 규칙의 유일한 예외다. 배경의 어두운 색이 Canvas로부터의 분리를 자체적으로 형성하므로 shadow를 사용하지 않는다.
- Background:
--card-current(Steadfast Blue Deeper:oklch(38% 0.17 256)) — 배경이 Canvas보다 어두워 그림자 없이도 계층이 형성됨 - Primary Text:
--card-current-text(var(--ink-50),oklch(98.5% 0.006 255)) — 메인 숫자 및 상태 접미사 - Muted Text:
--card-current-text-muted(var(--ink-300),oklch(84% 0.008 255)) — 환자명 캡션, 다음 복용 안내 - Progress Track:
--card-current-track(oklch(100% 0 0 / 20%)) — 진행 바 배경 - Progress Fill:
status-done-bright(oklch(79% 0.19 151)) — 완료 수량 표시 - Shadow: 없음 — 다크 배경이 Canvas(99%)로부터의 시각적 분리를 자체 제공
- Corner: rounded-xl (0.75rem); Padding: p-6 (1.5rem)
- Semantic:
<article aria-label="{patientName}님 복약 현황">— 스크린 리더 랜드마크 - 재사용: 약물안전리포트 화면의 "사용중인 약물 N건" 배너(웹·PDF 공통)도 동일한 다크 배경 변형을 사용한다. 홈 히어로 카드 전용이 아니라, Canvas보다 어두운 배경으로 시각적 강조가 필요한 요약형 배너에 공통으로 적용 가능하다.
구조 (위에서 아래):
- 환자명 캡션 —
text-sm text-card-current-text-muted - 복약 수 + 상태 접미사 — Display(text-4xl, 700) + Title(text-xl, 600), 모두
text-card-current-text - 진행 바 —
role="progressbar"witharia-valuenow/min/max/label - 다음 복용 안내 (pending/partial 상태에서만) —
text-sm text-card-current-text-muted
- Style: Ink Border stroke (1px), Canvas background, rounded-md (0.625rem)
- Focus: border-color transitions to Steadfast Blue, ring-1 ring-primary (Steadfast Blue 1px)
- Disabled: opacity-50, pointer-events-none
- Error: Alert Red border + ring
The persistent top navigation bar. Anchored at z-sticky (200), spanning the full viewport width.
- Background: Surface-2 (oklch(98.5% 0.006 255)); visually continuous with the app shell layer
- Border: 1px bottom border in Ink Border; no shadow
- Padding: px-4.5 (1.125rem) horizontal; pt accounts for
env(safe-area-inset-top)+ 1rem; pb-3 (0.75rem) - Account Switcher (left): Avatar circle in Ink Avatar (oklch(84% 0.008 255)); account name in Steadfast Blue Deep; chevron in Steadfast Blue Deep; min-h-[44px] tap target; hover opacity-80
- Notification Bell (right): Bell icon in Ink Text (oklch(38% 0.011 255)); -m-2.5 p-2.5 expands tap target to 44px; hover opacity-80
- View Transition:
view-transition-name: app-header
Five-tab persistent bottom navigation. Anchored to the bottom of the viewport.
- Background: Card white (oklch(100% 0 0)); 1px top border in Ink Border
- Bottom Padding:
max(0.75rem, env(safe-area-inset-bottom))for home indicator clearance on iOS - Tab (default): Icon 26px strokeWidth 1.9; Small Label (0.6875rem) font-semibold; inactive: Ink Icon Inactive; active and hover: Steadfast Blue; transition on color
- Disc CTA (center — 등록하기): Filled circle size-11 (2.75rem), Steadfast Blue background, shadow-fab, white icon 21px strokeWidth 2.4; label in Small Label, Steadfast Blue, font-bold. The only element in the nav that carries shadow-fab.
- Tap Targets: min-h-11 min-w-14 (44px × 56px) for all tabs
- Focus: ring-2 ring-primary on all tab items via focus-visible
- View Transition:
view-transition-name: bottom-nav
A 7-day calendar row for date selection. Implements roving tabindex for keyboard arrow-key navigation.
- Container: Horizontal flex, gap-1.5, px-4, pt-4, pb-2.5
- Day Button (default): flex-1, rounded-xl, 1px border in Ink Border, Card White background; hover: border-primary, Steadfast Blue Light background
- Day Button (today, unselected): ring-1 ring-inset ring-primary/40; day name and date in Steadfast Blue
- Day Button (selected): Steadfast Blue background, border-primary, shadow-fab; all text and dot in white
- Day Name: Small Label (0.6875rem), font-semibold; Ink Subtle → Steadfast Blue (today/hover) → white (selected)
- Date Number: Body size (0.9375rem), font-bold; Deep Ink → Steadfast Blue (today/hover) → white (selected)
- Medication Dot: 4px circle (size-1). Always rendered (prevents layout shift). White when selected; Steadfast Blue when the date has a medication schedule; transparent otherwise.
- Keyboard: ArrowLeft / ArrowRight move selection. Only the selected button has tabIndex=0 (roving tabindex).
- ARIA: role="radiogroup" on container; role="radio" aria-checked on each button; aria-current="date" on today.
The core component for communicating medication status at a glance. Always used as a color + text label pair.
- Done: Completion Green text / Completion Green BG; rounded-full; text-xs; font-medium
- Active (pending): Steadfast Blue text / Steadfast Blue Light background
- Caution: Caution Amber text / Caution BG background
- Danger / Missed: Alert Red text / Alert BG background
Morning (Steadfast Blue) · Noon (Caution Amber) · Night (Alert Red). Color codes distinguish time slots intuitively. Color is never used alone: text labels ("아침", "점심", "저녁") are always displayed alongside (WCAG 2.1 AA).
Color-coding for drug categories: Blue (oklch(47% 0.2 256) / oklch(94% 0.04 256)), Purple (oklch(52% 0.18 290) / oklch(94% 0.04 290)), Orange (oklch(58% 0.18 50) / oklch(95% 0.04 50)). Each color is a paired foreground/background set. Maximum three colors. These carry no medical meaning — they are identifiers only.
- Do use Steadfast Blue (oklch(54% 0.21 256)) on a single primary action per screen. Its rarity is what makes it trustworthy.
- Do represent a completed dose with Completion Green (oklch(52% 0.14 155)) and a missed dose with Alert Red (oklch(53% 0.21 27)). Color codes only work when they are consistent.
- Do build text hierarchy through Pretendard size, weight, and color variation only. There is no second typeface.
- Do use only h-9 (2.25rem) for standard buttons and h-14 (3.5rem) for CTAs. No arbitrary in-between sizes.
- Do choose from shadow-card, shadow-raised, or shadow-fab based on context. These are the only three shadows.
- Do pair every status color with a text label (WCAG 2.1 AA — never communicate meaning through color alone).
- Do apply negative letter-spacing to all text at 1.1875rem (19px) and above.
- Do use
kr-wrapon all paragraph, list, and definition text. Korean must not break mid-word. - Do account for iOS safe area insets: use
env(safe-area-inset-top)in the header andenv(safe-area-inset-bottom)in the bottom nav. - Do assign a unique
view-transition-nameto any element that participates in cross-page transitions. The namesapp-headerandbottom-navare reserved. - Do add new z-index values only by naming them in the seven-level vocabulary; update this spec when a new layer is added.
- Don't recreate hospital or pharma UI with white backgrounds and blue icons. This is an explicitly rejected reference.
- Don't use oversized text or rows of primary-color buttons as in senior-app patterns.
- Don't borrow the aesthetic of SaaS dashboards — charts, metrics, data-analysis tool feel.
- Don't follow the generic Korean platform style of KakaoTalk or Naver. Ongil's quiet warmth is its own.
- Don't nest cards. A card inside a card is always wrong.
- Don't use border-left greater than 1px as a colored accent stripe.
- Don't combine background-clip: text with a gradient. Solid-color text only.
- Don't repeat identically sized cards with icon + heading + description in an endless grid.
- Don't reach for a modal as the first choice. Exhaust inline or progressive disclosure alternatives first.
- Don't use purposeless glassmorphism (blur + translucent cards).
- Don't use z-index values outside the seven-level vocabulary. Undocumented stacking values cause collisions that are painful to debug.