한달품 데모 브랜드 — 가상 산후조리원 테마

데모 브랜드 테마 규약(cc-flutter:demo-brand-theme R1~R7)의 저장소 정본이다. 설계 초안은 cocode#1275 (docs/projects/postpartum-crm-demo/brand.md)이고, 구현은 cocode#1276 이다. 앱 이름 · 조직 같은 정체성 값은 identity.yaml 이 가진다(이 문서에 적지 않는다).

어디에 있나

무엇 파일
브랜드 결정(7축) — 유일한 곳 package/resources/lib/src/theme/postpartum_brand.dart(PostpartumBrand)
플랫폼 테마(앱 · 콘솔 · 위젯북 · 골든이 같은 것을 쓴다) package/resources/lib/src/theme/app_theme.dart(AppTheme.light/dark · 키오스크 kioskLight/kioskDark)
실제 슬롯 값 · 대비 시험(이 문서의 표가 이 시험과 같아야 한다) package/resources/test/app_theme_test.dart
위젯북 「브랜드 토큰」 페이지(R7) package/postpartum_ui/widgetbook/lib/src/brand_tokens_use_case.dart
웹 첫 프레임 전 배경(pre-boot) AppTheme.scaffoldBackgroundOf → app/*/web/index.html(생성물 — app/app 의 UPDATE_PRE_BOOT=1 flutter test test/web/pre_boot_test.dart)
모노그램 「품」(앱 안) package/postpartum_ui/lib/src/brand/brand_mark.dart(BrandMark — 사이드바 머리 · 로그인 C-00 왼쪽 패널은 inverted)
웹 아이콘 · 파비콘 · manifest 아이콘 python3 tool/brand/build_web_icons.py → app/app/web/icons/Icon-{192,512}.png(둥근 사각) · Icon-maskable-*(꽉 찬 면, 글자는 안전 영역 안) · app/{app,console,app_widgetbook}/web/favicon.png
Pages 랜딩 · 문서 사이트 색 tool/pages/landing.py · tool/pages/docs/bin/build_docs.dart 의 CSS 변수(아래 표의 surface · onSurface · onSurfaceVariant · outlineVariant · primary)
키오스크(자가 입력 앱) 테마 app/app/lib/src/app.dart 가 AppTheme.kioskLight/kioskDark — 바탕은 콘솔과 같다(pre-boot 하나)

화면 코드는 PostpartumBrand 를 읽지 않는다 — context.theme.colorScheme.* · Text 체인(Text('…').titleSmall.onSurfaceVariant) · CoreColor.token(CoreColors.*) 만 쓴다. 원시 Color(0x…) · Colors.* · BorderRadius.circular · BoxShadow 는 쓰지 않는다.

성격과 근거

색

시드(HSL)와 중립 hue — coui PrimitiveColors.generate → 표준 매핑(CoreSemanticMappingSet.standard):

PrimitiveColors.generate(
  primaryHSL: (h: 282, s: .30, l: .42),   // 라벤더 자두 — 주 행동 · 선택 · 진행
  secondaryHSL: (h: 30, s: .40, l: .42),  // 카라멜 — 컨테이너 면 · 보조 강조
  tertiaryHSL: (h: 152, s: .24, l: .36),  // 세이지 — 분류 태그 · 장식
  successHSL: (h: 142, s: .52, l: .32),
  infoHSL: (h: 212, s: .54, l: .38),
  warningHSL: (h: 42, s: .70, l: .38),
  errorHSL: (h: 6, s: .65, l: .40),
  neutralHue: 282,
)
기준 거리
상태색 — 정보 212 · 오류 6 · 경고 42 · 성공 142 70° 이상(가장 가까운 정보 212 와 70°)
같은 의료 패밀리 — 동물병원 174 · 치과 244 · 방문요양 314 32° 이상
다른 데모 — 15 · 22 · 190 · 193 · 230 · 250 32° 이상

고대비 매핑은 쓰지 않는다 — 라이트 주색이 거의 검정(OKLCH L 26%)이 되어 브랜드 성격이 사라진다. 표준 매핑으로 대비 감사를 통과한다(아래).

실제 슬롯 값(59)

coui_core coui_core-v0.159.0(루트 dependency_overrides)에서 AppTheme.core(b).colorScheme.resolved(b).toMap() 으로 뽑았다. 설계 초안(coui_core 0.159.0 기준)의 표와 값이 모두 같다.

슬롯 라이트 다크
primary #784B8B #BE9FCC
on-primary #FDFCFD #2F1D36
primary-container #EEE6F1 #36223F
on-primary-container #2F1D36 #EEE6F1
secondary #966B40 #D3B598
on-secondary #FDFCFD #3A2A19
secondary-container #F3EBE4 #44311D
on-secondary-container #3A2A19 #F3EBE4
tertiary #46725D #9BC2B0
on-tertiary #FDFCFD #1F332A
tertiary-container #E6F0EB #23392F
on-tertiary-container #1F332A #E6F0EB
error #A83124 #E48C82
on-error #FDFCFD #44140F
error-container #F8E1DE #4F1711
on-error-container #44140F #F8E1DE
error-strong #4F1711 #F8E1DE
focus-ring #784B8B #BE9FCC
primary-hover #4E305A #E2D4E8
primary-pressed #36223F #EEE6F1
secondary-hover #61452A #EBDED1
secondary-pressed #44311D #F3EBE4
error-pressed #6E2017 #F3CCC7
success #277C46 #7ED69E
on-success #FDFCFD #133D23
success-container #DFF5E7 #154427
on-success-container #133D23 #DFF5E7
warning #A57C1D #E8C77A
on-warning #1A181B #46350C
warning-container #F9F1DD #503C0E
on-warning-container #46350C #F9F1DD
info #2D5D95 #87AEDB
on-info #FDFCFD #13283F
info-container #E0EAF6 #162D48
on-info-container #13283F #E0EAF6
surface #FDFCFD #1A181B
on-surface #1A181B #FDFCFD
on-surface-variant #504D51 #C5C3C6
placeholder #676468 #B1AEB2
surface-tint #784B8B #BE9FCC
surface-dim #F3F2F3 #000000
surface-bright #FDFCFD #3C383D
surface-container-lowest #FDFCFD #000000
surface-container-low #F3F2F3 #1A181B
surface-container #E6E4E7 #2A272B
surface-container-high #D7D5D7 #3C383D
surface-container-highest #C5C3C6 #504D51
outline #676468 #B1AEB2
outline-variant #C5C3C6 #676468
inverse-surface #1A181B #FDFCFD
inverse-on-surface #FDFCFD #1A181B
inverse-primary #BE9FCC #4E305A
shadow #000000 #FFFFFF
surface-highlight #FFFFFF #B1AEB2
scrim #000000 #000000
disabled-content #817D82 #817D82
disabled-container #E6E4E7 #2A272B
disabled-outline #C5C3C6 #504D51

대비 측정(WCAG AA)

CoreContrast.auditScheme(coui_core 0.159.0)를 라이트 · 다크 모두 돌린 결과다 — 시험이 실패 0건을 단정한다. 라이트: 0 of 24 pairs fail · 다크: 0 of 24 pairs fail.

쌍(전경 on 배경) 기준 라이트 다크
onSurface on surface aaNormalText ≥4.5 17.24:1 ✓ 17.24:1 ✓
onSurfaceVariant on surface aaNormalText ≥4.5 8.14:1 ✓ 10.08:1 ✓
onSurface on surfaceContainer aaNormalText ≥4.5 13.96:1 ✓ 14.41:1 ✓
onSurfaceVariant on surfaceContainer aaNormalText ≥4.5 6.59:1 ✓ 8.43:1 ✓
placeholder on surface aaNormalText ≥4.5 5.70:1 ✓ 8.04:1 ✓
primaryText on surface aaNormalText ≥4.5 14.08:1 ✓ 12.45:1 ✓
primaryTextLarge on surface aaLargeText ≥3.0 14.08:1 ✓ 7.58:1 ✓
error on surface aaNormalText ≥4.5 6.56:1 ✓ 7.03:1 ✓
onPrimary on primary aaNormalText ≥4.5 6.46:1 ✓ 6.68:1 ✓
onPrimaryContainer on primaryContainer aaNormalText ≥4.5 12.76:1 ✓ 11.82:1 ✓
onSecondary on secondary aaNormalText ≥4.5 4.59:1 ✓ 7.10:1 ✓
onSecondaryContainer on secondaryContainer aaNormalText ≥4.5 11.68:1 ✓ 10.46:1 ✓
onTertiary on tertiary aaNormalText ≥4.5 5.36:1 ✓ 6.86:1 ✓
onTertiaryContainer on tertiaryContainer aaNormalText ≥4.5 11.52:1 ✓ 10.62:1 ✓
onError on error aaNormalText ≥4.5 6.56:1 ✓ 6.19:1 ✓
onErrorContainer on errorContainer aaNormalText ≥4.5 12.43:1 ✓ 11.49:1 ✓
onSuccess on success aaNormalText ≥4.5 5.06:1 ✓ 6.98:1 ✓
onSuccessContainer on successContainer aaNormalText ≥4.5 10.67:1 ✓ 9.72:1 ✓
onWarning on warning aaNormalText ≥4.5 4.62:1 ✓ 7.26:1 ✓
onWarningContainer on warningContainer aaNormalText ≥4.5 10.51:1 ✓ 9.36:1 ✓
onInfo on info aaNormalText ≥4.5 6.60:1 ✓ 6.49:1 ✓
onInfoContainer on infoContainer aaNormalText ≥4.5 12.31:1 ✓ 11.49:1 ✓
inverseOnSurface on inverseSurface aaNormalText ≥4.5 17.24:1 ✓ 17.24:1 ✓
outline on surface nonText ≥3.0 5.70:1 ✓ 8.04:1 ✓

감사 밖이지만 공용 위젯(package/postpartum_ui)이 더 쓰는 쌍 — 같은 시험이 CoreContrast.meets 로 단정한다:

테마 쌍 기준 비율
라이트 onSurfaceVariant on surfaceContainerLow(모의 안내 글자) 4.5 7.46:1 ✓
라이트 primary on surfaceContainerLow(모의 안내 아이콘) 3.0 5.92:1 ✓
라이트 primary on surface(KPI 아이콘) 3.0 6.46:1 ✓
라이트 outline on surfaceContainer(중립 상태 칩 점) 3.0 4.62:1 ✓
다크 onSurfaceVariant on surfaceContainerLow 4.5 10.08:1 ✓
다크 primary on surfaceContainerLow 3.0 7.58:1 ✓
다크 primary on surface 3.0 7.58:1 ✓
다크 outline on surfaceContainer 3.0 6.72:1 ✓

(이 표의 비율은 WCAG 2.x 공식으로 계산했고, 통과 여부는 시험이 coui 대비 API 로 다시 확인한다.)

상태(성공 · 경고 · 오류)는 색만으로 구분하지 않는다 — 상태 칩 · 상태 화면은 늘 문구(와 아이콘)를 함께 둔다.

7축 결정

축 선택 구현 이유
색 위 시드 · 표준 매핑 · neutralHue 282 PostpartumBrand.brand · core() 상태색과 거리, 포근한 중립 회색
타이포 CoreTypography.coui 17역할, 헤드라인 3종 semibold core().typography 표 스캔 · 차분한 위계. 본문 글꼴은 Pretendard(번들), 그 밖 글자는 LocaleFallback(웹 전역 폴백 Roboto 자리 — tool/fonts)
형태 카드 radius12 · 버튼 radius10 · 입력 radius8 · 배지/칩 radius9999 · 다이얼로그 radius12, 테두리 outlineVariant stroke1 CoreComponentTheme(card · button · textField · badge · chip · dialog) 업무 화면 밀도에 맞는 중간 반경, 상태 칩은 알약형
간격 · 밀도 카드 안쪽 space16, 버튼 높이 48 · 입력 최소 높이 48 · 달력 칸 48, 콘솔은 보통 밀도 · 자가 입력은 여유 밀도 같은 컴포넌트 테마 터치 48dp × scaling(R-4) — 태블릿 사용이 많다
효과 카드는 surface + outlineVariant 1px · 평면(elevation none), 다이얼로그 · 시트만 그림자 sm, 기본 포커스 링 card · dialog 테마 배경 회색 카드 금지(card-surface-tokens)
모션 카드 · 버튼 전환 CoreDuration.normal(테마), 끌어 옮기기(칸반 · 객실 보드)는 CoreDuration.fast(기능 화면 몫), 동작 줄이기 존중(coui) card · button 테마 직접 조작은 즉시, 전환은 차분하게
아이콘 Lucide — 콘솔 20 · 자가 입력 24, onSurfaceVariant / primary PostpartumBrand.console · kiosk(AppTheme.light/dark · kioskLight/kioskDark) 밀도 · 접근성. coui 묶음 밖 아이콘은 AppIcons(tool/icons)가 싣는다

탭 소리(tapSoundEnabled)는 끈다 — 하루 종일 쓰는 콘솔이다.

배율(scaling)

AppTheme 은 AdaptiveScaling 을 걸지 않는다 — coui 0.157 부터 휴대폰 기본 배율이 1 이고, 같은 커널 세대의 데모(vet · daycare)도 걸지 않는다. 터치 타깃은 컴포넌트 높이(48)로 지키고(시험: 기본 배율에서 버튼 ≥ 48, 명시 배율 1.25 에서 ≥ 60), 레이아웃 시험은 testScaleInvariant(scaling 1.25 × textScaler 1.0 · 1.15 · 1.3 · 2.0)로 더 엄격한 조건을 본다.

실존 브랜드 모방 여부