← 목록
기타 2026-06-27 34KB 읽기 48분

크라우니 디자인 표준 v1.0

정본 출처: kps.crowny.org 디자인 계약(Design Contract) 작성일: 2026-06-27 적용 대상: 모든 crowny.org 서비스 (cowork 우선 적용)

왜 이 문서가 필요한가

지금 crowny 서비스들은 저마다 다른 색을 쓴다. cowork는 보라·파랑, finance는 골드, kps는 초콜릿+골드다. 처음 방문한 사람은 같은 회사 사이트인지 알기 어렵다.

이 문서는 모든 crowny 서비스가 함께 따를 하나의 디자인 언어를 정한다. kps.crowny.org를 기준으로 삼고, 중학생도 이해할 수 있는 쉬운 표현을 원칙으로 한다.


1. 색 (Color)

1-1. 기본 팔레트 (원시 색상)

이 색들은 그 자체로는 직접 쓰지 않는다. 아래 "이름표 색상"에서 가져다 쓴다.

css:root {
  /* 초콜릿 계열 — 무게감, 신뢰 */
  --choco:       #3B2A1D;   /* 진한 초콜릿 */
  --choco-2:     #2C1E13;   /* 더 진한 초콜릿 */
  --choco-deep:  #1A130D;   /* 가장 진한 초콜릿 (다크모드 배경) */

  /* 크림 계열 — 부드러움, 따뜻함 */
  --cream-50:    #FBF7EE;   /* 가장 밝은 크림 (카드 배경) */
  --cream-100:   #F4EFE2;   /* 기본 배경 */
  --cream-200:   #ECE5D5;   /* 약간 어두운 배경 */
  --cream-300:   #E2D8C4;   /* 구분선, 경계 */

  /* 골드 계열 — 포인트, 액션 */
  --gold:        #B58A4A;   /* 기본 골드 */
  --gold-dim:    #8F6E3A;   /* 어두운 골드 (hover 시) */
  --gold-soft:   #D8C29A;   /* 밝은 골드 (다크모드 강조) */
  --gold-wash:   #EFE4CD;   /* 연한 골드 (배경 강조) */
  --gold-bright: #C9A35A;   /* 생생한 골드 */

  /* 잉크 계열 — 글씨 */
  --ink:         #2B2018;   /* 기본 글씨 색 */
  --ink-soft:    #5C4C3C;   /* 보조 글씨 색 */
  --muted:       #978872;   /* 흐린 글씨 색 */

  /* 상태 색 */
  --success:     #4E8C5A;   /* 성공, 완료 */
  --warning:     #C08842;   /* 경고 */
  --danger:      #B5524A;   /* 오류, 삭제 */
}

1-2. 이름표 색상 (Semantic Tokens) — 실제로 사용하는 색

css:root {
  /* 배경 */
  --bg:           var(--cream-100);   /* 페이지 배경 */
  --bg-soft:      var(--cream-200);   /* 약간 강조된 배경 */
  --surface:      var(--cream-50);    /* 카드 배경 */
  --surface-2:    var(--cream-200);   /* 중첩 카드 배경 */

  /* 글씨 */
  --text:         var(--ink);         /* 제목, 본문 */
  --text-soft:    var(--ink-soft);    /* 보조 설명 */
  --text-muted:   var(--muted);       /* 날짜, 태그 등 흐린 글씨 */

  /* 강조 (액션, 링크) */
  --accent:       var(--gold);
  --accent-dim:   var(--gold-dim);    /* 링크 기본 색 */
  --accent-soft:  rgba(181,138,74,.12); /* 배지 배경 */
  --accent-wash:  var(--gold-wash);
  --on-accent:    #FBF7EE;            /* 골드 버튼 위 글씨 */

  /* 경계선 */
  --border:       rgba(43,32,24,.12);
  --border-strong:rgba(43,32,24,.20);
}

1-3. 다크 모드 (Dark Mode)

두 가지 방식을 모두 지원한다.

방식 A: 시스템 설정 자동 감지 (OS가 다크 모드이면 자동 적용)

css@media (prefers-color-scheme: dark) {
  :root {
    --bg:           #1A130D;
    --bg-soft:      #221810;
    --surface:      #241A12;
    --surface-2:    #2E2117;
    --text:         #F4EFE2;
    --text-soft:    #D8C9B6;
    --text-muted:   #A89A82;
    --accent:       #D8C29A;
    --accent-dim:   #C9A35A;
    --accent-soft:  rgba(216,194,154,.14);
    --accent-wash:  #2E2117;
    --border:       rgba(244,239,226,.12);
    --border-strong:rgba(244,239,226,.22);
    --on-accent:    #1A130D;
    --shadow-sm:    0 1px 2px rgba(0,0,0,.3),0 2px 8px rgba(0,0,0,.28);
    --shadow-md:    0 8px 22px -8px rgba(0,0,0,.5),0 2px 8px rgba(0,0,0,.3);
    --shadow-lg:    0 36px 80px -30px rgba(0,0,0,.7),0 10px 26px -14px rgba(0,0,0,.45);
    --shadow-hi:    inset 0 1px 0 rgba(255,255,255,.06);
  }
}

방식 B: 수동 토글 버튼으로 전환 (data-theme="dark" 또는 "light")

css[data-theme="dark"] {
  --bg:#1A130D; --bg-soft:#221810; --surface:#241A12; --surface-2:#2E2117;
  --text:#F4EFE2; --text-soft:#D8C9B6; --text-muted:#A89A82;
  --accent:#D8C29A; --accent-dim:#C9A35A;
  --accent-soft:rgba(216,194,154,.14); --accent-wash:#2E2117;
  --border:rgba(244,239,226,.12); --border-strong:rgba(244,239,226,.22);
  --on-accent:#1A130D;
}
[data-theme="light"] {
  --bg:var(--cream-100); --surface:var(--cream-50);
  --text:var(--ink); --accent:var(--gold);
  --border:rgba(43,32,24,.12); --on-accent:#FBF7EE;
}


2. 글씨체 (Typography)

2-1. 폰트 패밀리

html<!-- head에 반드시 포함 -->
<link rel="stylesheet"
  href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
  rel="stylesheet">

css:root {
  --sans:  'Pretendard', system-ui, -apple-system, 'Apple SD Gothic Neo',
           'Segoe UI', 'Noto Sans KR', sans-serif;
  --serif: 'Noto Serif KR', 'Nanum Myeongjo', serif;
  --mono:  'JetBrains Mono', ui-monospace, Menlo, monospace;
}

변수용도
--sans본문, UI 버튼, 레이블
--serif제목(h1~h3), 브랜드명
--mono코드 블록, 명령줄
왜 Pretendard인가: 윈도우 PC에서 '맑은 고딕'으로 렌더링되는 것을 막기 위해 CDN에서 직접 로드한다. font-family 목록에만 있으면 해당 폰트가 없는 컴퓨터에선 적용되지 않는다.

2-2. 글씨 크기 체계

css/* 제목 계열 (serif) */
h1 { font-size: clamp(28px, 5vw, 48px); font-weight: 700; line-height: 1.18; }
h2 { font-size: clamp(22px, 3.5vw, 32px); font-weight: 600; line-height: 1.25; }
h3 { font-size: clamp(17px, 2.5vw, 22px); font-weight: 600; line-height: 1.3; }

/* 본문 계열 (sans) */
.text-lg  { font-size: 17px; line-height: 1.75; }
.text-md  { font-size: 15px; line-height: 1.7; }   /* 기본 */
.text-sm  { font-size: 13px; line-height: 1.65; }
.text-xs  { font-size: 11px; line-height: 1.6; }


3. 간격 (Spacing)

8px 리듬 기반. 이 숫자들만 사용한다. 중간 숫자는 쓰지 않는다.

css:root {
  --s-1:   4px;   /* 아주 작은 내부 여백 */
  --s-2:   8px;   /* 작은 간격 */
  --s-3:  12px;   /* 뱃지 내부 여백 */
  --s-4:  16px;   /* 기본 내부 여백 */
  --s-5:  24px;   /* 카드 내부 여백, 섹션 여백 */
  --s-6:  32px;   /* 섹션 사이 */
  --s-7:  48px;   /* 큰 섹션 사이 */
  --s-8:  64px;   /* 모바일 섹션 */
  --s-9:  96px;   /* 데스크탑 섹션 */
  --s-10:128px;   /* 히어로 섹션 */
}


4. 모서리 둥글기 (Border Radius)

css:root {
  --r-xs:   8px;   /* 작은 뱃지 */
  --r-sm:  12px;   /* 카드 (소형) */
  --r-md:  18px;   /* 카드 (기본) */
  --r-lg:  28px;   /* 대형 카드, 모달 */
  --r-xl:  40px;   /* 큰 배너 */
  --r-pill:999px;  /* 버튼, 태그, 인풋 */
}


5. 그림자 (Shadow)

모두 초콜릿 톤의 따뜻한 그림자다. 파란 그림자는 사용하지 않는다.

css:root {
  /* 라이트 모드 */
  --shadow-sm: 0 1px 2px rgba(59,42,29,.06), 0 2px 6px rgba(59,42,29,.05);
  --shadow-md: 0 6px 16px -6px rgba(59,42,29,.14), 0 2px 6px rgba(59,42,29,.06);
  --shadow-lg: 0 30px 70px -28px rgba(59,42,29,.30), 0 8px 20px -12px rgba(59,42,29,.14);
  --shadow-hi: inset 0 1px 0 rgba(255,255,255,.55);  /* 하이라이트 (버튼 안쪽) */
  --glow:      0 0 28px rgba(181,138,74,.22), 0 0 1px rgba(181,138,74,.4);
}


6. 모션 (Motion)

css:root {
  --ease:        cubic-bezier(.22,.61,.36,1);   /* 기본 */
  --ease-emph:   cubic-bezier(.2,0,0,1);        /* 강조 */
  --ease-spring: cubic-bezier(.34,1.56,.64,1);  /* 탄성 */
  --dur-1: 160ms;   /* 빠른 반응 (hover) */
  --dur-2: 240ms;   /* 기본 전환 */
  --dur-3: 360ms;   /* 느린 전환 (팝업) */
}

/* 화면에 들어올 때 자연스럽게 나타나는 애니메이션 */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.reveal.in { opacity: 1; transform: none; }

/* 움직임에 민감한 사용자 배려 */
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1 !important; transform: none !important; transition: none; }
  html { scroll-behavior: auto; }
}


7. 레이아웃 컨테이너

css:root {
  --maxw:        1080px;  /* 기본 최대 너비 */
  --maxw-narrow:  720px;  /* 좁은 레이아웃 (글 읽기용) */
}

.wrap        { max-width: var(--maxw);        margin: 0 auto; padding: 0 var(--s-5); }
.wrap-narrow { max-width: var(--maxw-narrow); margin: 0 auto; padding: 0 var(--s-5); }
section      { padding: var(--s-9) 0; }

@media (max-width: 760px) { section { padding: var(--s-8) 0; } }


8. 컴포넌트 (Components)

8-1. 버튼 (Button)

css/* 기본 버튼 (테두리형) */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 600;
  padding: 11px 20px;
  border-radius: var(--r-pill);
  cursor: pointer;
  border: .5px solid var(--border);
  background: var(--surface);
  color: var(--text-soft);
  transition: all var(--dur-1) var(--ease);
  min-height: 44px;   /* 터치 영역 최소 크기 — 접근성 */
  text-decoration: none;
}
.btn:hover {
  border-color: var(--accent);
  color: var(--accent);
  transform: translateY(-1px);
}

/* 주요 버튼 (골드 채우기) */
.btn--primary {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
  box-shadow: var(--shadow-hi);
}
.btn--primary:hover {
  background: var(--gold-dim);
  color: var(--on-accent);
}

/* 위험 버튼 (빨강) */
.btn--danger {
  background: var(--danger);
  color: #fff;
  border-color: var(--danger);
}

/* 크기 변형 */
.btn--sm { font-size: 12px; padding: 7px 14px; min-height: 36px; }
.btn--lg { font-size: 16px; padding: 14px 28px; min-height: 52px; }

쉬운 라벨 원칙:

  • "부트스트랩" → "자동 시작 설치"
  • "동기화" → "다른 컴퓨터로 복사"
  • "블록체인 커밋" → "변경 내용 저장"

8-2. 카드 (Card)

css/* 기본 카드 */
.card {
  background: var(--surface);
  border: .5px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--s-5);
  box-shadow: var(--shadow-sm);
  transition:
    border-color var(--dur-2) var(--ease),
    transform     var(--dur-2) var(--ease),
    box-shadow    var(--dur-2) var(--ease);
}
.card:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

/* 강조 카드 (히어로 안 등) */
.card--featured {
  border-color: var(--accent);
  background: linear-gradient(135deg, var(--surface), var(--accent-wash));
}

/* 작은 카드 */
.card--sm {
  border-radius: var(--r-sm);
  padding: var(--s-4);
}

8-3. 입력창 (Input)

css.input {
  width: 100%;
  padding: 12px 16px;
  background: var(--surface);
  border: .5px solid var(--border);
  border-radius: var(--r-pill);
  color: var(--text);
  font-family: var(--sans);
  font-size: 14px;
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
  min-height: 44px;  /* 터치 접근성 */
}
.input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.input::placeholder { color: var(--text-muted); }

/* 라벨 */
.input-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-soft);
  margin-bottom: var(--s-2);
}

8-4. 네비게이션 (Nav)

css/* 고정 네비게이션 */
#nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 50;
  transition:
    background    var(--dur-2) var(--ease),
    border-color  var(--dur-2) var(--ease),
    box-shadow    var(--dur-2) var(--ease);
  background: transparent;
  border-bottom: .5px solid transparent;
}
/* 스크롤하면 불투명 배경 */
#nav.scrolled {
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: saturate(150%) blur(12px);
  -webkit-backdrop-filter: saturate(150%) blur(12px);
  border-bottom-color: var(--border);
  box-shadow: var(--shadow-sm);
}

.nav-wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 10px var(--s-5);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
}

/* 브랜드 로고 영역 */
.nav-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
  text-decoration: none;
}
.nav-mark {
  width: 32px; height: 32px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--gold), var(--gold-soft));
  color: var(--on-accent);
  font-family: var(--serif);
  font-weight: 700;
  box-shadow: var(--shadow-hi);
}
.nav-name {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 16px;
}

/* 네비 링크 */
.nav-link {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text-soft);
  padding: 7px 12px;
  border-radius: var(--r-pill);
  transition: color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
  text-decoration: none;
}
.nav-link:hover { color: var(--text); background: var(--accent-soft); }

/* 테마 토글 버튼 */
.theme-toggle {
  width: 38px; height: 38px;
  border-radius: var(--r-pill);
  border: .5px solid var(--border);
  background: var(--surface);
  color: var(--text-soft);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.theme-toggle:hover { border-color: var(--accent); color: var(--accent); }
/* 아이콘 전환 */
.theme-toggle .ic-moon { display: none; }
[data-theme="dark"] .theme-toggle .ic-sun  { display: none; }
[data-theme="dark"] .theme-toggle .ic-moon { display: block; }

/* 모바일: 링크 숨기기 */
@media (max-width: 680px) {
  .nav-link:not(.nav-link--cta) { display: none; }
  .nav-name { display: none; }
}

8-5. 뱃지 (Badge)

css/* 기본 뱃지 (골드) */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .03em;
  padding: 4px 11px;
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  color: var(--accent-dim);
  font-family: var(--sans);
}
.badge .dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: var(--glow);
}

/* 상태 뱃지 */
.badge--success { background: rgba(78,140,90,.14);  color: #3a7a4a; }
.badge--warning { background: rgba(192,136,66,.14); color: #8f6e3a; }
.badge--danger  { background: rgba(181,82,74,.14);  color: #8a3a36; }
.badge--muted   { background: var(--bg-soft);       color: var(--text-muted); }

/* 등급 뱃지 (cowork 전용) */
.tier-badge--4  { background: rgba(78,140,90,.14);  color: #3a7a4a; }   /* 완전싱크 */
.tier-badge--3  { background: rgba(181,138,74,.14); color: var(--gold-dim); } /* 정기싱크 */
.tier-badge--2  { background: rgba(192,136,66,.14); color: #8f6e3a; }   /* 선택싱크 */
.tier-badge--1  { background: rgba(181,82,74,.14);  color: #8a3a36; }   /* 로컬보관 */

8-6. 탭 (Tab)

css/* 탭 컨테이너 */
.tabs {
  display: flex;
  gap: 2px;
  padding: var(--s-2);
  background: var(--bg-soft);
  border-radius: var(--r-md);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }

/* 탭 버튼 */
.tab {
  flex: 0 0 auto;
  padding: 8px 16px;
  border-radius: var(--r-sm);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  white-space: nowrap;
  transition: all var(--dur-1) var(--ease);
  border: none;
  background: none;
}
.tab:hover { color: var(--text-soft); background: var(--accent-soft); }
.tab.on    { background: var(--accent); color: var(--on-accent); }

/* 모바일: 하단 고정 탭 바 */
@media (max-width: 640px) {
  .tabs {
    position: fixed;
    bottom: 0; left: 0; right: 0;
    z-index: 50;
    border-top: .5px solid var(--border);
    border-radius: 0;
    padding: 6px 4px;
    justify-content: space-around;
    background: color-mix(in srgb, var(--bg) 95%, transparent);
    backdrop-filter: blur(12px);
  }
  body { padding-bottom: 56px; }
}

8-7. 코드 블록 (Code Block)

css.code-block {
  background: var(--choco-deep);
  border: .5px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--s-4);
  font-family: var(--mono);
  font-size: 13px;
  color: var(--gold-soft);
  white-space: pre-wrap;
  word-break: break-all;
  position: relative;
  line-height: 1.6;
}
[data-theme="light"] .code-block {
  background: var(--choco-2);
  color: var(--gold-wash);
}

/* 복사 버튼 */
.code-block .copy-btn {
  position: absolute;
  top: 8px; right: 8px;
}

8-8. 히어로 섹션 (Hero)

처음 화면에서 사이트를 소개하는 큰 영역이다.

css.hero {
  position: relative;
  min-height: 70vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--s-9) var(--s-5) var(--s-8);
  overflow: hidden;
  background-color: var(--bg);
}
/* 배경 빛 번짐 효과 */
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 72% 56% at 50% 38%, var(--accent-wash) 0%, transparent 70%),
    radial-gradient(ellipse 40% 30% at 50% 50%, var(--gold-soft) 0%, transparent 60%);
  opacity: .38;
  pointer-events: none;
  z-index: 0;
}
/* 배경 점 패턴 (4상 균형 3진 상징) */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle 1.2px at 0 0, var(--accent-dim) 100%, transparent 100%),
    radial-gradient(circle 0.8px at 0 0, var(--gold-dim) 100%, transparent 100%);
  background-size: 36px 36px, 72px 72px;
  background-position: 0 0, 18px 18px;
  opacity: .13;
  pointer-events: none;
  z-index: 0;
}
.hero-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-5);
  max-width: var(--maxw-narrow);
}


9. 접근성 (Accessibility)

최소 터치 영역

버튼, 링크, 입력창은 최소 44×44px을 확보한다. 손가락으로 누를 때 잘못 누르는 것을 줄인다.

css.btn, .tab, .input, .nav-link { min-height: 44px; }

포커스 표시

키보드로 탭 이동할 때 현재 위치를 알 수 있게 한다.

css:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}
/* 마우스 클릭 시에는 포커스 링 숨기기 */
:focus:not(:focus-visible) { outline: none; }

색 대비

  • 배경 #F4EFE2 위 글씨 #2B2018: 대비 비율 12.1:1 (WCAG AA 통과)
  • 골드 #B58A4A 위 글씨 #FBF7EE: 대비 비율 4.6:1 (WCAG AA 통과)

스크린 리더 지원

html<!-- 아이콘만 있는 버튼에는 반드시 aria-label 추가 -->
<button class="theme-toggle" aria-label="다크 모드 전환">
  <svg ...></svg>
</button>

<!-- 상태 표시에는 role 추가 -->
<div class="badge badge--success" role="status" aria-live="polite">완료</div>


10. 반응형 (Responsive)

기준점 (Breakpoint)

기준점크기대상
모바일~ 640px스마트폰
태블릿641px ~ 880px태블릿, 소형 노트북
데스크탑881px ~일반 PC, 윈도우 브라우저
css/* 모바일 우선 설계 (작은 화면에서 기본값 정의, 큰 화면에서 확장) */
.svc-grid {
  display: grid;
  grid-template-columns: 1fr;           /* 모바일: 1열 */
  gap: var(--s-3);
}
@media (min-width: 480px) {
  .svc-grid { grid-template-columns: repeat(2, 1fr); }  /* 태블릿: 2열 */
}
@media (min-width: 880px) {
  .svc-grid { grid-template-columns: repeat(3, 1fr); }  /* 데스크탑: 3열 */
}

윈도우 브라우저 주의사항

  1. Clipboard API: navigator.clipboard.writeText()는 HTTPS에서만 작동한다.
HTTP에서는 조용히 실패한다. 반드시 폴백 코드를 함께 넣어야 한다.

javascript// 올바른 복사 함수 — HTTP 폴백 포함
function copyText(text) {
  if (navigator.clipboard && window.isSecureContext) {
    return navigator.clipboard.writeText(text)
      .then(() => showCopied())
      .catch(() => fallbackCopy(text));
  } else {
    fallbackCopy(text);
  }
}
function fallbackCopy(text) {
  const el = document.createElement('textarea');
  el.value = text;
  el.style.cssText = 'position:fixed;opacity:0;top:-100px';
  document.body.appendChild(el);
  el.focus(); el.select();
  try { document.execCommand('copy'); showCopied(); }
  catch (e) { alert('클립보드에 복사하려면 Ctrl+C를 눌러주세요.'); }
  document.body.removeChild(el);
}
function showCopied() { /* "복사됨!" 피드백 표시 */ }

  1. 한글 파일 다운로드: Content-Disposition 헤더는 RFC 5987 방식으로 인코딩해야 한다.
javascript// Node.js 서버에서
const encoded = encodeURIComponent(fileName);
res.setHeader('Content-Disposition',
  `attachment; filename="fallback.zip"; filename*=UTF-8''${encoded}`);

  1. Blob URL 누수: URL.createObjectURL() 후 반드시 URL.revokeObjectURL()을 호출한다.
javascriptconst url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url; a.download = fileName;
document.body.appendChild(a); a.click();
document.body.removeChild(a);
setTimeout(() => URL.revokeObjectURL(url), 1000);  // 1초 후 해제


11. 쉬운 라벨 원칙 (Plain Language)

중학생이 이해할 수 있는 말을 쓴다. 전문 용어는 필요할 때만, 반드시 짧은 설명을 달아야 한다.

기존 표현바꿀 표현
티어드 블록체인 세팅 이관등급별 설정 파일 동기화
부트스트랩자동 설치 시작
블록체인 노드 기여 커밋내 작업 변경 내용 저장
블록체인 싱크 체인변경 기록 확인
오너 피드관리자 알림판
croworker함께 작업하는 사람
싱크동기화 (설명 없이는 "복사해 맞추기")
티어1 ~ 티어41단계 ~ 4단계 (처음엔 "접근 등급" 설명 필요)
게스트방문자 (로그인 없이)
아이디아이디 (OK — 모두 아는 말)

12. cowork 적용 가이드

12-1. portal.html / index.html 교체할 CSS 변수 블록

기존의 보라 계열 변수를 초콜릿+골드 계열로 모두 교체한다.

css/* ── 기존 (삭제) ── */
:root {
  --bg:#0a0a0f; --sf:#12121a; --sf2:#181824; --bd:#1e1e2e;
  --ac:#7c5bf5; --ac2:#5b8bf5;
  --tx:#e0e0e8; --dim:#666680;
  --gn:#3ddc84; --og:#f5a623; --rd:#f55b5b;
}

/* ── 새 크라우니 표준 (교체) ── */
:root {
  /* 팔레트 */
  --choco:#3B2A1D; --choco-2:#2C1E13; --choco-deep:#1A130D;
  --cream-50:#FBF7EE; --cream-100:#F4EFE2; --cream-200:#ECE5D5;
  --gold:#B58A4A; --gold-dim:#8F6E3A; --gold-soft:#D8C29A;
  --gold-wash:#EFE4CD; --gold-bright:#C9A35A;
  --ink:#2B2018; --ink-soft:#5C4C3C; --muted:#978872;

  /* 이름표 (라이트 모드 기본) */
  --bg:var(--cream-100); --bg-soft:var(--cream-200);
  --surface:var(--cream-50); --surface-2:var(--cream-200);
  --text:var(--ink); --text-soft:var(--ink-soft); --text-muted:var(--muted);
  --accent:var(--gold); --accent-dim:var(--gold-dim);
  --accent-soft:rgba(181,138,74,.12); --accent-wash:var(--gold-wash);
  --on-accent:#FBF7EE;
  --border:rgba(43,32,24,.12); --border-strong:rgba(43,32,24,.20);

  /* 상태 */
  --success:#4E8C5A; --warning:#C08842; --danger:#B5524A;

  /* 그림자 */
  --shadow-sm:0 1px 2px rgba(59,42,29,.06),0 2px 6px rgba(59,42,29,.05);
  --shadow-md:0 6px 16px -6px rgba(59,42,29,.14),0 2px 6px rgba(59,42,29,.06);
  --shadow-hi:inset 0 1px 0 rgba(255,255,255,.55);
  --glow:0 0 28px rgba(181,138,74,.22),0 0 1px rgba(181,138,74,.4);

  /* 반경 */
  --r-xs:8px; --r-sm:12px; --r-md:18px; --r-lg:28px; --r-pill:999px;

  /* 모션 */
  --ease:cubic-bezier(.22,.61,.36,1); --dur-1:160ms; --dur-2:240ms;

  /* 간격 */
  --s-2:8px; --s-3:12px; --s-4:16px; --s-5:24px;

  /* 폰트 */
  --sans:'Pretendard',system-ui,-apple-system,'Apple SD Gothic Neo','Segoe UI',sans-serif;
  --serif:'Noto Serif KR',serif;
  --mono:'JetBrains Mono',ui-monospace,monospace;
}

/* 다크 모드 */
@media (prefers-color-scheme:dark) { :root {
  --bg:#1A130D; --bg-soft:#221810; --surface:#241A12; --surface-2:#2E2117;
  --text:#F4EFE2; --text-soft:#D8C9B6; --text-muted:#A89A82;
  --accent:#D8C29A; --accent-dim:#C9A35A;
  --accent-soft:rgba(216,194,154,.14); --accent-wash:#2E2117;
  --border:rgba(244,239,226,.12); --border-strong:rgba(244,239,226,.22);
  --on-accent:#1A130D;
  --shadow-sm:0 1px 2px rgba(0,0,0,.3),0 2px 8px rgba(0,0,0,.28);
  --shadow-md:0 8px 22px -8px rgba(0,0,0,.5),0 2px 8px rgba(0,0,0,.3);
  --shadow-hi:inset 0 1px 0 rgba(255,255,255,.06);
}}
[data-theme="dark"] {
  --bg:#1A130D; --bg-soft:#221810; --surface:#241A12; --surface-2:#2E2117;
  --text:#F4EFE2; --text-soft:#D8C9B6; --text-muted:#A89A82;
  --accent:#D8C29A; --accent-dim:#C9A35A;
  --accent-soft:rgba(216,194,154,.14); --accent-wash:#2E2117;
  --border:rgba(244,239,226,.12); --border-strong:rgba(244,239,226,.22);
  --on-accent:#1A130D;
}

12-2. head에 추가할 폰트 링크

html<!-- 기존 head에 추가 -->
<link rel="stylesheet"
  href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@400;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
  rel="stylesheet">
<meta name="theme-color" content="#F4EFE2" media="(prefers-color-scheme:light)">
<meta name="theme-color" content="#1A130D" media="(prefers-color-scheme:dark)">

12-3. portal.html 수정 우선순위 (감사 결과 반영)

[높음] http:// 하드코딩 수정 (portal.html:263-266)

javascript// 기존 (문제) — http 하드코딩
function renderBoot(host) {
  const mac = `curl -s http://${host}/setup | bash -s -- ${tok} 4`;
  const win = `irm http://${host}/setup.ps1 | iex ; cowork-setup ${tok} 4`;
  ...
}

// 수정 — protocol 자동 감지
function renderBoot(host) {
  const proto = (host.includes(':') || location.protocol === 'http:') ? 'http' : 'https';
  const baseUrl = `${proto}://${host.replace(/:\d+$/, '')}`;
  const mac = `curl -s ${baseUrl}/setup | bash -s -- ${tok} 4`;
  const win = `irm ${baseUrl}/setup.ps1 | iex ; cowork-setup ${tok} 4`;
  ...
}

[높음] index.html 하드코딩 URL 수정 (index.html:199,202)

html<!-- 기존 (문제) -->
<code>curl -o cowork-cli.sh cowork.crowny.org:9720/cli</code>

<!-- 수정 -->
<code>curl -o cowork-cli.sh https://cowork.crowny.org/cli</code>

[높음] Clipboard 폴백 추가 (portal.html:370)

javascript// 기존 (문제) — 오류 처리 없음
function copyEl(id) {
  const t = h(id).textContent.replace('복사','').trim();
  navigator.clipboard.writeText(t);
}

// 수정 — HTTP 폴백 + 피드백 포함
function copyEl(id) {
  const t = h(id).textContent.replace('복사','').trim();
  if (navigator.clipboard && window.isSecureContext) {
    navigator.clipboard.writeText(t)
      .then(() => showCopyFeedback(id))
      .catch(() => fallbackCopy(t, id));
  } else {
    fallbackCopy(t, id);
  }
}
function fallbackCopy(text, id) {
  const el = document.createElement('textarea');
  el.value = text;
  el.style.cssText = 'position:fixed;opacity:0;top:-100px;left:-100px';
  document.body.appendChild(el);
  el.focus(); el.select();
  try { document.execCommand('copy'); showCopyFeedback(id); }
  catch(e) { alert('복사 단축키: Ctrl+C (Windows) / Cmd+C (Mac)'); }
  document.body.removeChild(el);
}
function showCopyFeedback(id) {
  const btn = h(id).querySelector('.cp');
  if (!btn) return;
  const orig = btn.textContent;
  btn.textContent = '복사됨!';
  btn.style.background = 'var(--success)';
  setTimeout(() => { btn.textContent = orig; btn.style.background = ''; }, 1500);
}

[중간] Blob URL 누수 수정 (portal.html:253-255)

javascript// 기존 (문제) — revokeObjectURL 없음
function pull(tier) {
  ...fetch(...).then(b => b.blob()).then(blob => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = '...'; a.click();
    // URL 해제 없음 → 누수
  });
}

// 수정
.then(blob => {
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url; a.download = getFileName(res) || 'bundle.tar.gz';
  document.body.appendChild(a); a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 1000);
})

// 파일명 파싱 (RFC 5987 지원)
function getFileName(res) {
  const cd = res.headers.get('content-disposition') || '';
  const utf8 = cd.match(/filename\*=UTF-8''([^;]+)/);
  if (utf8) return decodeURIComponent(utf8[1]);
  const plain = cd.match(/filename="?([^";]+)"?/);
  return plain ? plain[1] : null;
}

12-4. 테마 토글 버튼 추가

portal.html과 index.html 헤더에 다크/라이트 전환 버튼을 추가한다.

html<!-- 헤더 오른쪽에 추가 -->
<button class="theme-toggle" onclick="toggleTheme()" aria-label="다크/라이트 모드 전환">
  <svg class="ic-sun" width="18" height="18" viewBox="0 0 24 24" fill="none"
       stroke="currentColor" stroke-width="2">
    <circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/>
    <line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
    <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
    <line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/>
    <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
    <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
  </svg>
  <svg class="ic-moon" width="18" height="18" viewBox="0 0 24 24" fill="none"
       stroke="currentColor" stroke-width="2">
    <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
  </svg>
</button>

<script>
function toggleTheme() {
  const root = document.documentElement;
  const cur = root.getAttribute('data-theme') ||
    (matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light');
  const next = cur === 'dark' ? 'light' : 'dark';
  root.setAttribute('data-theme', next);
  localStorage.setItem('crowny-theme', next);
}
// 저장된 테마 복원
(function(){
  const saved = localStorage.getItem('crowny-theme');
  if (saved) document.documentElement.setAttribute('data-theme', saved);
})();
</script>

12-5. 히어로 섹션 추가 (index.html)

처음 방문한 사람이 사이트가 무엇인지 바로 알 수 있도록 히어로 섹션을 추가한다.

html<!-- 탭 메뉴 위에 삽입 -->
<section class="hero" id="hero">
  <div class="hero-inner">
    <span class="badge">
      <span class="dot"></span>
      크라우니 협업 도구
    </span>
    <h1 style="font-family:var(--serif); font-size:clamp(26px,5vw,42px); color:var(--text);">
      여러 컴퓨터에서<br>같은 도구로 같이 일한다
    </h1>
    <p style="color:var(--text-soft); font-size:16px; max-width:48ch; line-height:1.75;">
      한선씨 컴파일러, 크라우니 스킬, 설정 파일을<br>
      로그인 하나로 다른 컴퓨터에 그대로 옮긴다.
    </p>
    <div style="display:flex; gap:12px; flex-wrap:wrap; justify-content:center;">
      <a href="/portal" class="btn btn--primary">로그인해서 시작하기</a>
      <a href="/안내" class="btn">자세히 알아보기</a>
    </div>
  </div>
</section>

12-6. 전문 용어 → 쉬운 말로 교체

[portal.html footer] "티어드 블록체인 세팅 이관"
→ "등급별 설정 파일 동기화"

[portal.html 카드 제목] "부트스트랩"
→ "새 컴퓨터에 자동 설치하기"

[portal.html] "블록체인 노드 & 기여 커밋"
→ "작업 변경 내용 저장하기"

[portal.html] "블록체인 싱크 체인"
→ "변경 기록 확인"

[portal.html] "오너 피드"
→ "관리자 알림판"

[index.html] "croworker"
→ "함께 일하는 사람"


13. 체크리스트 (적용 완료 확인용)

새 페이지를 만들거나 기존 페이지를 고칠 때 아래 항목을 확인한다.

색/폰트

  • --ac:#7c5bf5 같은 보라 계열 변수 없음
  • Pretendard CDN <link> 있음
  • Noto Serif KR CDN <link> 있음
  • JetBrains Mono CDN <link> 있음
  • 제목에 var(--serif) 사용

기능

  • HTTPS에서 clipboard API 작동 확인
  • HTTP(로컬)에서 clipboard 폴백 확인
  • Blob URL revokeObjectURL 호출 있음
  • 한글 파일명 다운로드 RFC 5987 인코딩

접근성

  • 모든 버튼/링크 최소 44×44px
  • 아이콘 버튼에 aria-label 있음
  • 포커스 링 보임 (:focus-visible)
  • 텍스트 색 대비 4.5:1 이상

반응형

  • 모바일(640px 이하) 화면 확인
  • 탭이 모바일에서 하단 고정 확인
  • 가로 스크롤 없음

콘텐츠

  • 전문 용어에 쉬운 설명 달림
  • 첫 화면에서 사이트 목적 파악 가능
  • 다크/라이트 모드 토글 버튼 있음

14. 관련 파일

파일위치역할
KPS 정본 CSS/Users/ef/crowny-services/public/kps/index.html (L30~220)디자인 토큰 원본
기존 디자인 라이브러리/Users/ef/crowny-design/크라우니디자인.한선한선씨 버전
기존 CSS/Users/ef/crowny-design/크라우니표준.css정적 CSS
cowork portal/Users/ef/crowny-cowork/public/portal.html수정 대상
cowork index/Users/ef/crowny-cowork/public/index.html수정 대상
UX 감사/Users/ef/CrownyDoc/projects/2026-06-27-cowork-감사-UX.md문제 목록
백엔드 감사/Users/ef/CrownyDoc/projects/2026-06-27-cowork-감사-백엔드.md문제 목록
한선씨 감사/Users/ef/CrownyDoc/projects/2026-06-27-cowork-감사-한선씨셀코어.md문제 목록

이 문서는 크라우니 디자인 표준 v1.0 정본이다. 변경 시 이 파일을 먼저 수정하고 관련 서비스에 반영한다.