/* ========================================================================== 무월 — 4단계 구현 (히어로 섹션까지) 모든 값은 03-tokens.css 에서 나온다. 하드코딩 금지. ========================================================================== */ *, *::before, *::after { box-sizing: border-box; } html { -webkit-text-size-adjust: 100%; } body { margin: 0; background: var(--surface); color: var(--ink); font-family: var(--font-body); font-size: var(--step-0); line-height: var(--leading-normal); /* 한글 조판 — antipatterns.md §8 */ word-break: keep-all; overflow-wrap: break-word; letter-spacing: 0; /* 한글 본문 음수 자간 금지 */ position: relative; isolation: isolate; } /* 재질: 필름 그레인 최약 (svg-filters.md R1, --grain 0.03) 요소 filter가 아니라 data URI 배경 → 한 번만 래스터화되고 캐시된다 */ body::after { content: ''; position: fixed; inset: 0; pointer-events: none; z-index: 1; opacity: var(--grain); mix-blend-mode: multiply; /* 밝은 배경이므로 overlay 대신 multiply */ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E"); } img, svg { max-width: 100%; height: auto; } .visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; clip-path: inset(50%); overflow: hidden; white-space: nowrap; } .skip { position: absolute; left: var(--space-3); top: var(--space-3); transform: translateY(-200%); z-index: 10; padding: var(--space-2) var(--space-3); background: var(--ink); color: var(--surface); border-radius: var(--radius-interactive); text-decoration: none; transition: transform var(--dur-instant) var(--ease-out); } .skip:focus-visible { transform: translateY(0); } :where(a, button, [tabindex]):focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--radius-interactive); } /* ---- 그리드 -------------------------------------------------------------- layout.md §1 — 하나의 그리드에서 모든 것이 나온다 */ .page-header__inner, .hero__inner { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--pad-inline); } /* ---- 헤더 ---------------------------------------------------------------- */ .page-header { padding-block: var(--space-4); } .page-header__inner { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; } .wordmark { font-family: var(--font-display); font-size: var(--step-2); font-weight: 600; color: var(--ink); text-decoration: none; letter-spacing: -0.01em; /* 한글 디스플레이 허용 범위 */ } .wordmark__han { font-size: var(--step--1); color: var(--ink-muted); margin-inline-start: var(--space-2); letter-spacing: 0; } .nav { display: flex; gap: var(--space-4); margin: 0; padding: 0; list-style: none; font-size: var(--step--1); } .nav a { color: var(--ink-muted); text-decoration: none; padding-block: var(--space-2); /* 터치 타깃 확보 */ display: inline-block; border-bottom: 1px solid transparent; transition: color var(--dur-instant) var(--ease-out), border-color var(--dur-instant) var(--ease-out); } .nav a:hover { color: var(--ink); border-bottom-color: var(--line-strong); } /* ---- 히어로 -------------------------------------------------------------- layout.md §1 "비대칭을 두려워하지 마라" — 좌 5 : 우 7 */ .hero { padding-block: var(--space-7) var(--space-8); } .hero__inner { display: grid; gap: var(--space-6); align-items: start; } /* grid item 기본 min-width:auto 가 표의 최소폭을 그대로 반영해 320px에서 가로 스크롤을 만든다 (하드 게이트 5) */ .hero__inner > * { min-width: 0; } @media (min-width: 60rem) { .hero__inner { grid-template-columns: 5fr 7fr; gap: var(--space-6) var(--space-7); } /* 헤드라인은 두 컬럼을 가로지른다 — 좁은 컬럼에 두면 한글이 5줄로 접힌다 (SKILL.md 카운트 규칙: 히어로 헤드라인 ≤ 2줄) */ .hero__head { grid-column: 1 / -1; } } .hero__head { margin-bottom: var(--space-2); } .eyebrow { margin: 0 0 var(--space-3); font-size: var(--step--1); color: var(--ink-muted); /* 전체 대문자 아님 — antipatterns 최우선 지문 2위 회피 */ } .hero__title { margin: 0; max-width: 20ch; /* 한글 20자 — 데스크톱에서 2줄, 모바일에서 3줄 상한 */ font-family: var(--font-display); font-size: var(--step-5); font-weight: 600; line-height: var(--leading-tight); letter-spacing: -0.015em; /* 대형 헤드라인만. 한글 허용 -0.01~-0.02em */ text-wrap: balance; } .hero__body { margin: 0 0 var(--space-5); max-width: var(--measure); color: var(--ink); } .hero__action { margin: 0 0 var(--space-3); } /* 주 CTA 1개. 페이지에서 유일한 반전 블록 → 회색조에서 가장 어둡다 */ .cta { display: inline-block; padding: var(--space-3) var(--space-5); background: var(--accent); color: var(--accent-ink); border-radius: var(--radius-interactive); text-decoration: none; font-weight: 600; min-height: 44px; /* 터치 타깃 */ transition: background-color var(--dur-instant) var(--ease-out); } .cta:hover { background: var(--ink); } .hero__note { margin: 0; font-size: var(--step--1); color: var(--ink-muted); max-width: var(--measure); } /* ---- 프로파일 표 ---------------------------------------------------------- */ .profile__title { margin: 0 0 var(--space-3); font-size: var(--step--1); font-weight: 400; color: var(--ink-muted); } /* 좁은 폭에서는 표만 스스로 스크롤한다. 페이지 본문은 넘치지 않는다 */ .profile__scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; } .profile { width: 100%; min-width: 20rem; border-collapse: collapse; font-variant-numeric: tabular-nums; background: var(--surface-raised); border-radius: var(--radius-container); overflow: hidden; } .profile th, .profile td { padding: var(--space-3); text-align: right; border-bottom: 1px solid var(--line); font-weight: 400; vertical-align: baseline; } .profile thead th { font-size: var(--step--1); color: var(--ink-muted); border-bottom-color: var(--line-strong); } .profile tbody tr:last-child th, .profile tbody tr:last-child td { border-bottom: 0; } .profile__name { text-align: left; } .profile__origin { display: block; } .profile__lot { display: block; font-size: var(--step--1); color: var(--ink-muted); } .profile__date { white-space: nowrap; } .num[data-pending] { color: var(--ink-muted); } .profile__legend { margin: var(--space-3) 0 0; font-size: var(--step--1); color: var(--ink-muted); max-width: var(--measure); } /* ---- 모션 ---------------------------------------------------------------- R3: Codrops scroll-driven animation. JS 0바이트. 이중 게이팅 — reduced-motion 안에 @supports. 기본 상태는 visible. 지원 안 하면 아무 일도 일어나지 않는다. (antipatterns §5 "reveal 실패 시 opacity:0 잔존" 회피) */ @media (prefers-reduced-motion: no-preference) { @supports (animation-timeline: view()) { @keyframes rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } .reveal { animation: rise var(--dur-slow) var(--ease-out) both; animation-timeline: view(); animation-range: entry 0% entry 40%; } } }