--- name: taylor-atelier description: 테일러의 "아틀리에" 디자인 철학을 웹 아티팩트에 적용하는 스킬. 딥 포레스트 그린, 우드톤, 인디고 블루의 차분한 색감과 공예적 정교함으로 단순 HTML부터 복잡한 React 앱까지 모던하면서 따뜻한 UI 생성. 한국어 타이포그래피 지원 포함. --- # Atelier Design Protocol: Taylor's Bespoke Web Craft System ## 1. 철학 & 핵심 지침 **페르소나:** `Atelier_Craftsperson` **목표:** 장인의 작업실(Atelier)처럼 모든 웹 요소를 정교하게 다룬다. 기성품 같은 템플릿 디자인을 배제하고, 브랜드의 진정성과 따뜻함이 담긴 비스포크(Bespoke) 경험을 만든다. 화려함이 아닌 공예적 완성도로 방문자에게 깊은 인상을 남긴다. **세 가지 핵심 원칙:** 1. **공예적 정교함** - 버튼 하나, 여백 하나에도 의도가 담겨야 한다 2. **비스포크 경험** - 브랜드의 이야기를 담는 고유한 인터페이스 3. **지속 가능한 설계** - 유행이 지나도 가치를 잃지 않는 구조 --- ## 2. 절대 금지 패턴 (Anti-Patterns) 다음 요소가 코드에 포함되면 아틀리에 품질 기준에 미달한다: - **금지 폰트:** Inter, Roboto, Arial, Open Sans. 본고딕(HCR체)만 한국어에 사용하지 않는다 - **금지 색상 조합:** 원색 배경(강렬한 파랑/빨강/초록), 형광색, 순수 흰색 + 순수 검정 단독 사용 - **금지 레이아웃:** Bootstrap식 대칭 3열 그리드, 무거운 drop shadow(`rgba(0,0,0,0.3)` 이상), 여백 없는 꽉 찬 레이아웃 - **금지 모션:** `linear` 또는 `ease-in-out` 트랜지션, 즉각적 상태 변경(보간 없음) - **금지 텍스트:** "혁신적인", "세계 최고의", "압도적인" 등 과장된 카피. 진정성 있는 구체적 언어 사용 - **금지 패턴:** 빈 `catch` 블록, `any` 타입, `console.log` 미제거 --- ## 3. 컬러 시스템 (Atelier Palette) ### 라이트 모드 ```css :root { /* === 기반 색상 (Foundation) === */ --atelier-bg-primary: #F7F5F0; /* 크림 캔버스 */ --atelier-bg-secondary: #EFEBE4; /* 따뜻한 리넨 */ --atelier-bg-elevated: #FFFFFF; /* 순백 카드 */ --atelier-bg-sunken: #E8E3D8; /* 음각 배경 */ /* === 포레스트 그린 계열 === */ --atelier-green-900: #1A2E1A; /* 딥 포레스트 (주요 텍스트/강조) */ --atelier-green-700: #2D4A2D; /* 포레스트 (CTA 배경) */ --atelier-green-500: #4A7A4A; /* 미드 그린 (버튼 호버) */ --atelier-green-300: #8AB58A; /* 소프트 그린 (태그, 뱃지) */ --atelier-green-100: #E8F0E8; /* 페일 그린 (배경 틴트) */ /* === 우드톤 계열 === */ --atelier-wood-900: #3D2B1A; /* 다크 마호가니 */ --atelier-wood-700: #6B4A2A; /* 월넛 (서브 헤딩 강조) */ --atelier-wood-500: #9A6B42; /* 오크 (아이콘, 구분선) */ --atelier-wood-300: #C4A07A; /* 버치 (장식 요소) */ --atelier-wood-100: #F0E8DC; /* 페일 우드 (카드 배경) */ /* === 인디고 블루 계열 === */ --atelier-indigo-900: #1A1A3D; /* 딥 인디고 */ --atelier-indigo-700: #2D2D6B; /* 인디고 (링크, 인터랙션) */ --atelier-indigo-500: #4A4A9A; /* 미드 인디고 (호버 상태) */ --atelier-indigo-300: #7A7AC4; /* 소프트 인디고 (비활성) */ --atelier-indigo-100: #E8E8F5; /* 페일 인디고 (배경 틴트) */ /* === 텍스트 === */ --atelier-text-primary: #2A2018; /* 주요 텍스트 (순수 검정 대신) */ --atelier-text-secondary: #6B5D4A; /* 부가 텍스트 */ --atelier-text-muted: #9B8E7E; /* 비활성/힌트 텍스트 */ --atelier-text-inverse: #F7F5F0; /* 어두운 배경 위 텍스트 */ /* === 경계선 === */ --atelier-border-strong: rgba(42, 32, 24, 0.15); --atelier-border-subtle: rgba(42, 32, 24, 0.08); --atelier-border-ghost: rgba(42, 32, 24, 0.04); /* === 그림자 === */ --atelier-shadow-sm: 0 1px 3px rgba(42, 32, 24, 0.08), 0 1px 2px rgba(42, 32, 24, 0.04); --atelier-shadow-md: 0 4px 12px rgba(42, 32, 24, 0.10), 0 2px 4px rgba(42, 32, 24, 0.06); --atelier-shadow-lg: 0 12px 32px rgba(42, 32, 24, 0.12), 0 4px 8px rgba(42, 32, 24, 0.06); --atelier-shadow-warm: 0 8px 24px rgba(107, 74, 42, 0.15); /* 우드톤 그림자 */ } ``` ### 다크 모드 ```css [data-theme="dark"], .dark { --atelier-bg-primary: #151210; --atelier-bg-secondary: #1E1A16; --atelier-bg-elevated: #252018; --atelier-bg-sunken: #0E0C0A; --atelier-green-900: #A8C8A8; --atelier-green-700: #7AAA7A; --atelier-green-500: #5A8A5A; --atelier-green-300: #3A6A3A; --atelier-green-100: #1A2E1A; --atelier-wood-900: #D4B896; --atelier-wood-700: #B89070; --atelier-wood-500: #8A6442; --atelier-wood-300: #5A3E24; --atelier-wood-100: #2A1E12; --atelier-indigo-900: #A8A8D4; --atelier-indigo-700: #7A7AAA; --atelier-indigo-500: #5A5A8A; --atelier-indigo-300: #3A3A6A; --atelier-indigo-100: #1A1A3A; --atelier-text-primary: #EDE8E0; --atelier-text-secondary: #B8A890; --atelier-text-muted: #7A6E60; --atelier-text-inverse: #2A2018; --atelier-border-strong: rgba(237, 232, 224, 0.15); --atelier-border-subtle: rgba(237, 232, 224, 0.08); --atelier-border-ghost: rgba(237, 232, 224, 0.04); --atelier-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); --atelier-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.35); --atelier-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.4); --atelier-shadow-warm: 0 8px 24px rgba(0, 0, 0, 0.4); } ``` ### Tailwind 설정 (tailwind.config 통합 시) ```javascript // tailwind.config.js module.exports = { darkMode: 'class', theme: { extend: { colors: { atelier: { bg: { primary: 'var(--atelier-bg-primary)', secondary: 'var(--atelier-bg-secondary)', elevated: 'var(--atelier-bg-elevated)' }, green: { 900: '#1A2E1A', 700: '#2D4A2D', 500: '#4A7A4A', 300: '#8AB58A', 100: '#E8F0E8' }, wood: { 900: '#3D2B1A', 700: '#6B4A2A', 500: '#9A6B42', 300: '#C4A07A', 100: '#F0E8DC' }, indigo: { 900: '#1A1A3D', 700: '#2D2D6B', 500: '#4A4A9A', 300: '#7A7AC4', 100: '#E8E8F5' }, text: { primary: 'var(--atelier-text-primary)', secondary: 'var(--atelier-text-secondary)', muted: 'var(--atelier-text-muted)' }, } }, fontFamily: { 'atelier-display': ['Playfair Display', 'Cormorant Garamond', 'Noto Serif KR', 'serif'], 'atelier-body': ['DM Sans', 'Pretendard', 'Noto Sans KR', 'sans-serif'], 'atelier-mono': ['JetBrains Mono', 'Fira Code', 'monospace'], }, transitionTimingFunction: { 'atelier': 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 'atelier-spring': 'cubic-bezier(0.34, 1.56, 0.64, 1)', 'atelier-silk': 'cubic-bezier(0.16, 1, 0.3, 1)', } } } } ``` --- ## 4. 타이포그래피 시스템 (한국어 지원) ```css /* === 폰트 임포트 === */ @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,600;0,700;1,400;1,600&family=DM+Sans:wght@300;400;500;600&family=Noto+Serif+KR:wght@400;600;700&family=Noto+Sans+KR:wght@300;400;500;600&display=swap'); /* === 타이포그래피 스케일 === */ :root { /* 영문 디스플레이: Playfair Display (serif, 장인적 느낌) */ --font-display: 'Playfair Display', 'Noto Serif KR', Georgia, serif; /* 본문/UI: DM Sans (기하학적 산세리프, 현대적) */ --font-body: 'DM Sans', 'Noto Sans KR', 'Apple SD Gothic Neo', sans-serif; /* 코드/메타: JetBrains Mono */ --font-mono: 'JetBrains Mono', 'Fira Code', monospace; /* 스케일 */ --text-xs: clamp(0.75rem, 1vw, 0.8125rem); --text-sm: clamp(0.875rem, 1.2vw, 0.9375rem); --text-base: clamp(1rem, 1.5vw, 1.0625rem); --text-lg: clamp(1.125rem, 1.8vw, 1.25rem); --text-xl: clamp(1.25rem, 2vw, 1.5rem); --text-2xl: clamp(1.5rem, 2.5vw, 2rem); --text-3xl: clamp(1.875rem, 3.5vw, 2.5rem); --text-4xl: clamp(2.25rem, 5vw, 3.5rem); --text-5xl: clamp(3rem, 7vw, 5rem); /* 자간/행간 */ --tracking-display: -0.02em; /* 대형 제목 */ --tracking-heading: -0.01em; /* 소형 제목 */ --tracking-body: 0; /* 본문 */ --tracking-wide: 0.05em; /* 태그, 레이블 */ --tracking-wider: 0.1em; /* 이니셜, 강조 레이블 */ --leading-tight: 1.1; --leading-snug: 1.35; --leading-normal: 1.6; --leading-relaxed: 1.75; } /* 한국어 최적화: 단어 분리 방지 */ h1, h2, h3, .atelier-heading { word-break: keep-all; overflow-wrap: break-word; } ``` ### 타이포그래피 계층 규칙 | 역할 | 폰트 | 크기 | 두께 | 자간 | |------|------|------|------|------| | Display (영문 히어로) | Playfair Display | `--text-5xl` | 700 | `-0.02em` | | Display (한국어 히어로) | Noto Serif KR | `--text-4xl` | 700 | `-0.01em` | | H1 섹션 제목 | Playfair Display / Noto Serif KR | `--text-3xl` | 600 | `-0.015em` | | H2 하위 제목 | DM Sans / Noto Sans KR | `--text-2xl` | 600 | `-0.01em` | | H3 카드 제목 | DM Sans / Noto Sans KR | `--text-xl` | 500 | `0` | | Body 본문 | DM Sans / Noto Sans KR | `--text-base` | 400 | `0` | | Caption / 태그 | DM Sans / Noto Sans KR | `--text-sm` | 400-500 | `0.05em` | | Eyebrow 레이블 | DM Sans | `--text-xs` | 600 | `0.1em` | --- ## 5. 컴포넌트 명세 ### A. 헤더 & 네비게이션 ```html
``` ```css .atelier-nav { position: fixed; top: 1.5rem; left: 50%; transform: translateX(-50%); background: rgba(247, 245, 240, 0.85); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--atelier-border-strong); border-radius: 9999px; padding: 0.5rem 1.5rem; box-shadow: var(--atelier-shadow-md); z-index: 100; width: max-content; max-width: calc(100vw - 2rem); } .dark .atelier-nav { background: rgba(30, 26, 22, 0.85); } .atelier-nav-link { color: var(--atelier-text-secondary); font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500; letter-spacing: var(--tracking-wide); text-decoration: none; padding: 0.375rem 0.75rem; border-radius: 9999px; transition: all 400ms cubic-bezier(0.16, 1, 0.3, 1); } .atelier-nav-link:hover { color: var(--atelier-green-700); background: var(--atelier-green-100); } ``` --- ### B. 히어로 섹션 + CTAs ```css .atelier-hero { min-height: 100dvh; /* iOS Safari 뷰포트 점프 방지 */ display: grid; place-items: center; padding: 8rem 2rem 4rem; background-color: var(--atelier-bg-primary); position: relative; overflow: hidden; } /* 배경 질감: 미세한 노이즈 오버레이 */ .atelier-hero::before { content: ''; position: fixed; inset: 0; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.03'/%3E%3C/svg%3E"); pointer-events: none; z-index: 1; opacity: 0.4; } /* 배경 앰비언트 그라디언트 */ .atelier-hero-ambient { position: absolute; width: 60vw; height: 60vw; border-radius: 50%; background: radial-gradient(circle, rgba(74, 122, 74, 0.08) 0%, transparent 70%); top: -20%; right: -10%; pointer-events: none; animation: atelier-drift 25s ease-in-out infinite; } @keyframes atelier-drift { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(-2%, 3%); } } /* 히어로 제목 */ .atelier-hero-title { font-family: var(--font-display); font-size: var(--text-5xl); font-weight: 700; letter-spacing: var(--tracking-display); line-height: var(--leading-tight); color: var(--atelier-green-900); word-break: keep-all; } /* Eyebrow 레이블 */ .atelier-eyebrow { display: inline-flex; align-items: center; gap: 0.5rem; font-family: var(--font-body); font-size: var(--text-xs); font-weight: 600; letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--atelier-wood-700); background: var(--atelier-wood-100); border: 1px solid var(--atelier-border-strong); border-radius: 9999px; padding: 0.375rem 1rem; margin-bottom: 1.5rem; } /* CTA 버튼 시스템 */ .atelier-btn-primary { display: inline-flex; align-items: center; gap: 0.75rem; font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500; color: var(--atelier-text-inverse); background: var(--atelier-green-700); border: 1px solid var(--atelier-green-700); border-radius: 9999px; padding: 0.75rem 1.75rem; text-decoration: none; transition: all 400ms cubic-bezier(0.16, 1, 0.3, 1); position: relative; overflow: hidden; } .atelier-btn-primary:hover { background: var(--atelier-green-500); transform: translateY(-1px); box-shadow: var(--atelier-shadow-warm); } .atelier-btn-primary:active { transform: translateY(0) scale(0.98); } /* 버튼 내 아이콘 래퍼 (Button-in-Button 패턴) */ .atelier-btn-icon { display: inline-flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; border-radius: 50%; background: rgba(255, 255, 255, 0.15); transition: transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1); } .atelier-btn-primary:hover .atelier-btn-icon { transform: translate(2px, -1px) scale(1.1); } .atelier-btn-secondary { display: inline-flex; align-items: center; gap: 0.75rem; font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500; color: var(--atelier-text-primary); background: transparent; border: 1px solid var(--atelier-border-strong); border-radius: 9999px; padding: 0.75rem 1.75rem; text-decoration: none; transition: all 400ms cubic-bezier(0.16, 1, 0.3, 1); } .atelier-btn-secondary:hover { background: var(--atelier-bg-secondary); border-color: var(--atelier-wood-300); transform: translateY(-1px); } ``` --- ### C. 카드 그리드 ```css /* 중첩 베젤 카드 (공예품처럼 물리적 깊이감) */ .atelier-card-shell { background: var(--atelier-bg-secondary); border: 1px solid var(--atelier-border-subtle); border-radius: 1.5rem; padding: 0.375rem; box-shadow: var(--atelier-shadow-sm); } .atelier-card-core { background: var(--atelier-bg-elevated); border-radius: calc(1.5rem - 0.375rem); padding: 1.75rem; box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.8); transition: box-shadow 400ms cubic-bezier(0.16, 1, 0.3, 1); } .atelier-card-shell:hover .atelier-card-core { box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.8), var(--atelier-shadow-md); } /* 비대칭 그리드 레이아웃 */ .atelier-card-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 1.25rem; } /* 다양한 크기 조합 (예시) */ .atelier-card-featured { grid-column: span 8; } .atelier-card-side { grid-column: span 4; } .atelier-card-wide { grid-column: span 6; } .atelier-card-normal { grid-column: span 4; } @media (max-width: 768px) { .atelier-card-featured, .atelier-card-side, .atelier-card-wide, .atelier-card-normal { grid-column: span 12; } } /* 카드 이미지 래퍼 */ .atelier-card-image { aspect-ratio: 4/3; border-radius: calc(1.5rem - 0.375rem - 0.25rem); overflow: hidden; background: var(--atelier-bg-secondary); margin: -1.75rem -1.75rem 1.75rem; } .atelier-card-image img { width: 100%; height: 100%; object-fit: cover; transition: transform 700ms cubic-bezier(0.16, 1, 0.3, 1); filter: saturate(0.9); } .atelier-card-shell:hover .atelier-card-image img { transform: scale(1.04); filter: saturate(1); } /* 카드 태그 */ .atelier-tag { display: inline-flex; align-items: center; font-family: var(--font-body); font-size: var(--text-xs); font-weight: 600; letter-spacing: var(--tracking-wide); text-transform: uppercase; padding: 0.25rem 0.75rem; border-radius: 9999px; border: 1px solid; } .atelier-tag-green { color: var(--atelier-green-700); background: var(--atelier-green-100); border-color: var(--atelier-green-300); } .atelier-tag-wood { color: var(--atelier-wood-700); background: var(--atelier-wood-100); border-color: var(--atelier-wood-300); } .atelier-tag-indigo { color: var(--atelier-indigo-700); background: var(--atelier-indigo-100); border-color: var(--atelier-indigo-300); } ``` --- ### D. 폼 + 입력 컴포넌트 ```css /* 아틀리에 폼 필드 */ .atelier-field { display: flex; flex-direction: column; gap: 0.5rem; } .atelier-label { font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500; color: var(--atelier-text-secondary); letter-spacing: var(--tracking-wide); } .atelier-input, .atelier-textarea { font-family: var(--font-body); font-size: var(--text-base); color: var(--atelier-text-primary); background: var(--atelier-bg-elevated); border: 1px solid var(--atelier-border-strong); border-radius: 0.75rem; padding: 0.75rem 1rem; outline: none; transition: all 350ms cubic-bezier(0.16, 1, 0.3, 1); box-shadow: inset 0 1px 2px rgba(42, 32, 24, 0.04); } .atelier-input:focus, .atelier-textarea:focus { border-color: var(--atelier-green-500); box-shadow: 0 0 0 3px var(--atelier-green-100), inset 0 1px 2px rgba(42, 32, 24, 0.04); } .atelier-input::placeholder, .atelier-textarea::placeholder { color: var(--atelier-text-muted); } /* 폼 레이아웃 */ .atelier-form { background: var(--atelier-bg-secondary); border: 1px solid var(--atelier-border-subtle); border-radius: 1.5rem; padding: 2.5rem; box-shadow: var(--atelier-shadow-md); } ``` --- ### E. 푸터 ```css .atelier-footer { background: var(--atelier-green-900); color: var(--atelier-text-inverse); padding: 4rem 2rem 2rem; } .atelier-footer-brand { font-family: var(--font-display); font-size: var(--text-2xl); font-style: italic; color: var(--atelier-wood-300); margin-bottom: 0.5rem; } .atelier-footer-tagline { font-family: var(--font-body); font-size: var(--text-sm); color: rgba(247, 245, 240, 0.5); letter-spacing: var(--tracking-wide); } .atelier-footer-divider { border: none; border-top: 1px solid rgba(247, 245, 240, 0.1); margin: 2rem 0; } .atelier-footer-link { color: rgba(247, 245, 240, 0.6); text-decoration: none; font-size: var(--text-sm); transition: color 300ms ease; } .atelier-footer-link:hover { color: var(--atelier-wood-300); } ``` --- ## 6. 인터랙션 & 애니메이션 시스템 ### A. 호버 실크 트랜지션 모든 인터랙티브 요소에 적용되는 기본 트랜지션: ```css /* 기본 실크 트랜지션: 마찰감 있는 부드러운 감속 */ .atelier-interactive { transition: all 400ms cubic-bezier(0.16, 1, 0.3, 1); } /* 스프링 트랜지션: 약간의 오버슈트로 생동감 */ .atelier-spring { transition: all 500ms cubic-bezier(0.34, 1.56, 0.64, 1); } /* 섬세한 트랜지션: 미세한 UI 변화에 */ .atelier-subtle { transition: all 250ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } ``` ### B. 스크롤 페이드-인 (IntersectionObserver) ```javascript // 아틀리에 스크롤 진입 애니메이션 // window.addEventListener('scroll') 절대 금지 - 지속적 리플로우 발생 function initAtelierScrollReveal() { const elements = document.querySelectorAll('[data-atelier-reveal]'); const observer = new IntersectionObserver( (entries) => { entries.forEach((entry, index) => { if (entry.isIntersecting) { // 스태거 딜레이: CSS 변수로 전달 const stagger = entry.target.dataset.stagger || 0; setTimeout(() => { entry.target.classList.add('atelier-revealed'); }, stagger * 80); observer.unobserve(entry.target); } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' } ); elements.forEach(el => observer.observe(el)); } ``` ```css /* 진입 전 상태 */ [data-atelier-reveal] { opacity: 0; transform: translateY(1.5rem); filter: blur(4px); transition: opacity 700ms cubic-bezier(0.16, 1, 0.3, 1), transform 700ms cubic-bezier(0.16, 1, 0.3, 1), filter 700ms cubic-bezier(0.16, 1, 0.3, 1); } /* 진입 후 상태 */ [data-atelier-reveal].atelier-revealed { opacity: 1; transform: translateY(0); filter: blur(0); } ``` ### C. 스켈레톤 로딩 ```css /* 아틀리에 스켈레톤: 차가운 회색 대신 따뜻한 우드톤 계열 */ @keyframes atelier-shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } } .atelier-skeleton { background: linear-gradient( 90deg, var(--atelier-bg-secondary) 25%, var(--atelier-wood-100) 50%, var(--atelier-bg-secondary) 75% ); background-size: 200% 100%; animation: atelier-shimmer 1.8s ease-in-out infinite; border-radius: 0.5rem; } .dark .atelier-skeleton { background: linear-gradient( 90deg, #252018 25%, #3A2E20 50%, #252018 75% ); background-size: 200% 100%; } /* 스켈레톤 카드 */ .atelier-skeleton-card { display: flex; flex-direction: column; gap: 0.75rem; padding: 1.75rem; background: var(--atelier-bg-elevated); border: 1px solid var(--atelier-border-subtle); border-radius: 1.25rem; } .atelier-skeleton-image { height: 12rem; } .atelier-skeleton-title { height: 1.5rem; width: 70%; } .atelier-skeleton-text { height: 1rem; } .atelier-skeleton-text-sm { height: 0.875rem; width: 50%; } ``` ### D. 마이크로 인터랙션 ```css /* 버튼 활성화 (물리적 눌림) */ .atelier-btn-primary:active, .atelier-btn-secondary:active { transform: scale(0.97); transition-duration: 100ms; } /* 아이콘 회전 (아코디언, 드롭다운) */ .atelier-chevron { transition: transform 350ms cubic-bezier(0.34, 1.56, 0.64, 1); } .atelier-open .atelier-chevron { transform: rotate(180deg); } /* 링크 밑줄 드로우 효과 */ .atelier-link { position: relative; color: var(--atelier-indigo-700); text-decoration: none; } .atelier-link::after { content: ''; position: absolute; bottom: -1px; left: 0; width: 0; height: 1px; background: var(--atelier-indigo-700); transition: width 350ms cubic-bezier(0.16, 1, 0.3, 1); } .atelier-link:hover::after { width: 100%; } /* 포커스 링: 접근성 준수 */ :focus-visible { outline: 2px solid var(--atelier-green-500); outline-offset: 3px; border-radius: 0.25rem; } ``` --- ## 7. 접근성 & WCAG 준수 ```css /* 고대비 모드 지원 */ @media (prefers-contrast: high) { :root { --atelier-border-strong: rgba(42, 32, 24, 0.4); --atelier-text-secondary: var(--atelier-text-primary); } } /* 모션 감소 선호 사용자 */ @media (prefers-reduced-motion: reduce) { [data-atelier-reveal] { opacity: 1; transform: none; filter: none; transition: none; } .atelier-skeleton { animation: none; background: var(--atelier-bg-secondary); } .atelier-hero-ambient { animation: none; } * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; } } ``` **WCAG 기준 체크리스트:** - 모든 텍스트 콘트라스트 비율 4.5:1 이상 (`--atelier-text-primary` on `--atelier-bg-primary`: ~8:1) - 대형 텍스트(18px+) 콘트라스트 비율 3:1 이상 - 모든 인터랙티브 요소에 `:focus-visible` 스타일 적용 - `aria-label`, `alt`, `role` 속성 누락 없음 - 키보드 네비게이션 완전 지원 --- ## 8. 성능 가이드라인 ``` GPU 안전 애니메이션 규칙: [O] transform, opacity만 애니메이션 [X] top, left, width, height, background-color (레이아웃 트리거) backdrop-blur 제한: [O] fixed/sticky 요소 (네비, 오버레이)에만 사용 [X] 스크롤 컨테이너, 대형 콘텐츠 영역에 사용 금지 will-change 사용: [O] 실제 애니메이션 중인 요소에만, 완료 후 제거 [X] 모든 카드/섹션에 선제적으로 적용 금지 이미지 최적화: - WebP/AVIF 형식 우선 - loading="lazy" 기본 적용 - 이미지에 filter: saturate(0.9) 기본 (따뜻하고 절제된 느낌) ``` --- ## 9. 실행 프로토콜 코드 작성 시 아래 순서를 따른다: 1. **[진단]** 코드베이스 분석 → HTML/CSS 순수 모드 vs Tailwind/React 모드 자동 판별 2. **[기반]** CSS 변수 시스템 및 폰트 임포트 설정 3. **[레이아웃]** 섹션 간 여백 최소 `py-24` 확보, 숨쉬는 공간 확보 4. **[타이포]** Playfair Display/Noto Serif KR 제목 + DM Sans/Noto Sans KR 본문 계층 적용 5. **[카드]** 중첩 베젤(Shell + Core) 구조로 모든 주요 카드 구성 6. **[모션]** 커스텀 cubic-bezier 트랜지션, 스크롤 진입 애니메이션 적용 7. **[접근성]** focus-visible, aria 속성, prefers-reduced-motion 확인 8. **[검수]** 아래 체크리스트 통과 후 최종 출력 --- ## 10. 최종 검수 체크리스트 ``` [ ] 금지 폰트(Inter, Roboto, Arial) 미사용 [ ] 컬러 시스템 변수(--atelier-*)로 색상 정의 [ ] 다크 모드 변수 적용 확인 [ ] 섹션 여백 최소 py-24 (6rem) 확보 [ ] 모든 제목에 Playfair Display 또는 Noto Serif KR 적용 [ ] 중첩 베젤 패턴(Shell + Core) 카드에 적용 [ ] 모든 트랜지션에 cubic-bezier 커스텀 이징 사용 [ ] 스크롤 진입: IntersectionObserver 사용, window.scroll 금지 [ ] 애니메이션: transform/opacity만 사용 [ ] backdrop-blur: fixed/sticky 요소에만 적용 [ ] prefers-reduced-motion 미디어쿼리 처리 [ ] focus-visible 스타일 적용 [ ] 이미지에 filter: saturate(0.9) 기본 적용 [ ] 한국어 텍스트에 word-break: keep-all 적용 [ ] 전체 분위기: "장인이 만든 따뜻하고 모던한 공간" 느낌 ```