feat(site): rework 19 marketing showcases for composition diversity
Some checks are pending
ci / build (push) Waiting to run

Measured convergence before: split hero 13/19, top-bar nav 19/19,
one-line notice footer 14/19, body Pretendard 17/21, 10 similarity
pairs above 0.78. Each showcase got a pre-assigned hero family, nav
form, footer form, type pair, background, accent hue, radius, motion
grammar and material from outputs/rework-2026-10-06/plan.md; direction
cards and the chosen reason are recorded in every design.md.

After: 0 similarity warnings, 19 distinct display faces, 7 hero
families, 5 nav forms, 5 footer forms, no scroll reveals, 5 showcases
with SVG filter materials. Example contact values replace bracket
placeholders under the existing fictional-brand notices. Thumbnails,
OG images, card copy and three e2e assertions updated; dead CSS in
dure-enrollment and hannam-jari removed; similarity.mjs learns the new
font families.
This commit is contained in:
Yun Chan 2026-10-06 16:55:50 +09:00
parent 88c11682b1
commit 8e3cdb0d3b
296 changed files with 19131 additions and 17538 deletions

View file

@ -1,17 +1,143 @@
# 향연
# design.md — 향연 (hyang-incense)
연기 세로 사진과 주변 여백을 유지한다. 히어로 사진의 이중 액자를 제거해 사진면과 기록면을 직접 맞대고, 숙성 장부와 아카이브 목록은 라벨·값이 같은 기준선에서 읽히게 조정한다. 본문은 17px 이상과 42rem 이하의 폭을 쓴다.
## 진행 상태
| 판단 축 | 적용 | 한계 |
| --- | --- | --- |
| 구도 | Hofmann의 면과 여백 관계를 참고해 사진 주위의 불필요한 액자 여백을 줄였다. | 이 참고가 모든 전시형 페이지의 최적 해법은 아니다. |
| 타입 | Ruder를 참고해 장부의 라벨·값과 본문의 역할을 분리했다. | 읽기 속도나 이해도 향상을 주장하지 않는다. |
| 색 | Albers를 참고해 따뜻한 바탕과 적갈색 동작색의 역할 경계를 유지했다. | 대비 수치는 브라우저 검증으로 재확인한다. |
- 0 현행 감사 완료 (2026-10-06) · 1 레퍼런스 R1·R3 실측, R2 부분 · 2 카드 3장, A 선택(위임) · 3 토큰 확정 · 4 구현 완료 · 5 감사 통과 · 6 이 문서.
- 다음 작업은 "검증" 절의 미검증 목록부터 본다.
토큰은 `--surface`, `--ink`, `--accent`, `--step-0`, `--space-*`를 사용한다. 로컬 MaruBuri 400/600은 `styles/fonts.css`, Pretendard는 기존 CDN을 유지한다. 가상 기록·예시 가격·기존 앵커는 바꾸지 않았다.
## 브리프
## 2026-09-12 현재 검증 기록
```
무엇을: 삼청동 자연 침향 전문점 "향연"의 한 장짜리 소개 페이지 리디자인 (쇼케이스, 가상 브랜드)
누구에게: 침향을 사려는 손님. 기록(입고 연도·산지·수지 함량)과 가격을 읽고 시향 방문 시간을 확인한다
제약: 정적 HTML/CSS, JS 없음 · 기존 사실·수치·이미지 2장 유지 · 기본 언어 ko-KR(기존 로컬라이제이션)
· 배정값(outputs/rework-2026-10-06/plan.md hyang-incense 행)이 브리프 제약
```
- `verify-final` 18개 묶음은 16개가 즉시 통과했다. 전체 묶음의 invariant·visual 검사는 Gaon·Dure를 대상으로 하며, 나머지 2개는 수정 뒤 release 독립 재실행에서 ALL PASS·ALL MATCH였다.
- root는 28개 모바일, 21개 데스크톱, 7개 하위 경로와 30개 앱 상태를 직접 검토해 수용했다. stress 112건은 hard failure 0이며, 가로 넘침 4건은 targeted fix 뒤 390px 재측정에서 0이다.
- 이 기록은 렌더·계약 범위의 현재 결과다. 모든 폭·키보드 경로·인쇄 등 개별 기능을 완전 재실행했다는 뜻이 아니며, 참여자 과업 효과도 미측정이다.
확정 슬롯(기존 파일 + 배정표, 사용자 위임): 목표 행동 하나 = 시향 방문 안내 읽기. 톤 = 조용하고 사실적. 화면 1개(index.html).
## 미확정
- 가격·수지 함량·연도는 기존 쇼케이스의 예시값이다(실제 값 아님). 푸터 고지 한 줄이 범위를 소유한다.
- 매장 주소·전화는 기존 페이지에도 없어 싣지 않았다(지어내지 않는다).
## 레퍼런스
| 슬롯 | 출처 | 실측(2026-10-06, Playwright 1440×900) | 가져온 것 |
|---|---|---|---|
| R1 구조 | APFR 제품 페이지 https://www.apothekefragrance.com/products/incense-sticks/ | body 배경 rgb(238,228,212) 단색. 제품 누끼 507×507이 x=467, y=152 중앙. 제목은 좌상단 작게, 행동 "Shop Now →" 하나가 우상단(y=162). 설명 문단은 제품 아래 y≈740, 폭 500 | 제품 단독 히어로의 실제 비례: 제품 가운데, 글은 작게 가장자리, 행동 하나 우상단 |
| R1' 격자 | APFR https://www.apothekefragrance.com/products/ | 누끼 256×256 타일, 이름 16px 아래 | 누끼 + 단색 배경 처리의 실제 사례 |
| R2 톤 | hibi https://hibi-jp.com/ | 배경 rgb(220,221,221) 무채 밝음, `<nav>` 없음(로고 + 스토어 버튼 + 텍스트 링크 행), 본문 Noto Serif KR | 내비 없는 브랜드 바(브랜드 + 행동) |
| R3 디테일 | svg-filters.md R5(잉크) + motion-parallax.md §9 | feTurbulence→feDisplacementMap→blur, 최상단 요소는 `scroll(root block)` | 연기 재질과 스크롤 구동 마스크 |
| 미검증 | 큰 워드마크 한 줄 푸터의 실제 사례 — studiofreight.com·lusion.co·oimu-seoul.com을 열었으나 해당 형태가 아니었다. soohyang.com은 도메인 판매 페이지 | layout.md §2-d 표를 근거로 썼다 |
## 방향
**지문**: 제품 단독(돌 받침 위 향 한 자루 누끼, 단색 배경, 연기가 위로) · Gowun Batang / Noto Sans KR · 바탕 #e6e1ea 회보라 · 강조 #b62752(LCh 10.7°) · radius 2px · 흐름 제품 → 절편 누끼 + 글 → 기록 표 + 가격 목록 → 시향 안내 → 워드마크 푸터 · 내비 없음(브랜드 + 행동 링크 하나) · 푸터 큰 워드마크 한 줄 + 고지 · 이미지 CSS 누끼 2장(multiply + 타원 마스크), 캡션 아래 가운데 · 모션 scroll-driven 연기 마스크 이동 1곳, 감소 모션은 정지.
**컨셉**: 침향을 찾는 손님이 돌 받침에 꽂힌 향 한 자루와 연기를 보고, 입고 연도·수지 함량 기록을 읽은 뒤 시향 시간을 확인한다.
**프리셋**: quiet-commerce 지배(사양이 설득하는 B2C) + 재질 축만 svg-filters 잉크 레시피(연기). 유리·그레인은 쓰지 않는다.
**표현 리스크**: 연기 SVG 필터(feTurbulence+feDisplacementMap) — 제품이 "타고 있는 향"임을 보이는 과업 근거. 검증: 필터 끈 캡처(`final-filter-off-hero.png`)에서도 S자 선으로 성립, 글자에는 필터를 걸지 않음.
**카드(배정 제약 안, 위임으로 A 선택)**
```
A. 돌 위의 한 자루 B. 포스터 한 장 C. 절편이 먼저
+------------------------+ +------------------------+ +------------------------+
| 향연 시향 방문 → | | 향연 사실 셋 시향 → | | 향연 시향 방문 → |
| (연기) | | (연기) | | [침향 절편 누끼 전폭] |
| [향+돌 누끼] | | [향+돌 누끼] | | |
| 자연 침향 사실 셋 | | 자 연 침 향 (전폭 하단)| | 자연 침향 절편 180,000원|
+------------------------+ +------------------------+ +------------------------+
| 절편 누끼 + 글 | | 기록 표(먼저) | | 가격·기록(합침) |
| 기록 표 + 가격 목록 | | 절편 누끼 + 글 | | 절편 설명 |
| 시향 안내 | | 가격 목록 · 시향 안내 | | 시향 안내(향로 + 연기) |
| [향연 워드마크] | | [향연 워드마크] | | [향연 워드마크] |
+------------------------+ +------------------------+ +------------------------+
```
| 항목 | A. 돌 위의 한 자루 | B. 포스터 한 장 | C. 절편이 먼저 |
|---|---|---|---|
| 한 줄 컨셉 | 손님이 타는 향 한 자루를 보고 기록을 읽은 뒤 시향 시간을 확인한다 | 손님이 전폭 표제가 받치는 제품 포스터를 보고 기록 표부터 읽는다 | 손님이 실제 판매 상품(절편)의 생김새와 가격을 먼저 보고 시향에서 향로를 본다 |
| 타입 페어 | Gowun Batang 144px / Noto Sans KR 17px(8.5배) | Gowun Batang 전폭 자간 벌림 / Noto Sans KR | Gowun Batang 96px / Noto Sans KR |
| 색 | #e6e1ea / #2a2530 / #b62752(링크·행동·숙성 중) | 같음, 표제 뒤 #ddd7e2 띠 | 같음 |
| 모션 | 연기 마스크 스크롤 이동 | 같음 | 시향 섹션에서만 연기 |
| 레퍼런스 | R1 APFR(제품 중앙·행동 우상단·설명 아래), R2 hibi | R1 APFR | R1' APFR 격자 |
| 히어로 첫 문장 | "자연 침향" + 사실 셋(삼청동 2001년부터 / 기록을 적어 팝니다 / 시향 요일·횟수) | "자연 침향" + 사실 셋을 위로 | "자연 침향 절편" + "2001년 입고, 수지 64.2%, 10g, 180,000원" |
| 포기하는 것 | 첫 화면에 가격이 없다 | 전폭 표제는 390에서 세 줄이 되어 "한 줄 큰 낱말" 배정을 깬다 | 배정된 "향·향로"와 연기 모션이 첫 화면에서 빠진다 |
**고른 이유(위임)**: A — 배정이 "향·향로 누끼 + scroll-driven 연기"이고 R1 APFR이 제품 중앙·행동 우상단·설명 아래 구조를 실측으로 보여 줬다. B는 390에서 한 줄 표제 배정을 깨고, C는 연기·향로를 첫 화면에서 잃는다.
**반사실 점검**: 고유 요소 — 돌 받침 위 향 사진 자체, "삼청동, 2001년부터", 연기. 같은 업종 치환(다른 침향 가게): h1 "자연 침향"은 살아남지만 사진·사실 셋·연기 출발점이 바뀌어야 한다. 다른 업종(세무사무소): 제품 단독 히어로·연기·기록 표가 전부 쓸모없다 → 통과. 페이지 수렴 6축 대조(05 계측 군집): 섹션 흐름·글 묶음(라벨 없음·한 줄·사실 목록·버튼 없음)·내비(없음)·푸터(워드마크)·이미지(누끼)·모션(스크롤 마스크) 전부 다름.
**보존 자산**: 상호 향연, 사실·수치 전부(2001·2012·2024, 64.2/51.8/47.3%, 가격 3종, 시향 시간·인원), 이미지 2장, 앵커 id `wood`·`aging`·`collection`·`visit`·`main`, 스킵 링크, 가상 고지 1회.
## 토큰과 예산
값은 `styles/tokens.css`. 역할: 바탕 회보라 2단계(표 패널만 raised), 먹 2단계, 불씨 1 + 짙은 불씨(hover·작은 글자). 강조 hue는 similarity.mjs의 CIELAB LCh 기준 10.7°(sRGB HSL로는 338°) — 배정표의 각도가 그 도구 기준이라 맞췄다. radius 2px는 표 패널 한 곳.
폰트: Gowun Batang은 표제·워드마크·연도·상품명·가격의 59자만 `text=`로 싣는다(11KB). 글자를 바꾸면 outputs/rework-2026-10-06/hyang-incense.md "폰트 서브셋" 절의 스크립트로 `text=` 목록을 다시 만든다. Noto Sans KR 400 한 웨이트(123KB, 13슬라이스). 웨이트는 패밀리당 하나 — 굵기 대신 색·크기로 구분한다.
| 예산(tokens §5) | 기본 | 실측(1440, 2026-10-06) |
|---|---|---|
| JS | 150KB | 0 |
| 첫 화면 전송량 | 1MB | ≈165KB(CSS 14 + 폰트 134 + smoke.webp 14.5) |
| 폰트 | 100KB(데모 200KB) | **134KB — 기본 초과, 데모 범위 안.** 한글 고딕 한 웨이트가 123KB라 100KB 아래로는 본문 서체를 시스템 고딕으로 바꿔야 한다 |
| LCP | 2.5초 | 로컬 416ms, LCP 요소 h1 |
| 애니메이션 속성 | transform·opacity 우선 | `mask-position`(main-thread) 1곳, 요소 400×450px, 스크롤 0~40vh 구간만. 필터는 정적 |
## 이펙트와 폴백
- 연기: SVG 필터 2개(wisp: turbulence 0.005/0.011 → displacement 46 → blur 1.3 / haze: 0.006/0.012 → 70 → blur 11), 정적. 스크롤 구동은 CSS `mask-position`을 `scroll(root block)` 타임라인으로 30%→100%. `@supports` 가드 안에 초기 상태. 미지원(Firefox)·감소 모션: 55%에서 정지. 필터 미지원: S자 선 + 띠(캡처 `final-filter-off-hero.png`).
- 누끼: 원본이 사진이라 CSS로 대체 — 히어로는 `background-size 281.25%`로 돌·향 부분만 확대 크롭 + `mix-blend-mode: multiply` + `saturate(.55) brightness(1.13)` + 타원 마스크(실측 잔차: 크림 배경이 바탕 대비 1~4/255). 절편은 같은 처리, 타원 45%×46%. 블렌드는 마스크를 가진 상자에 건다(마스크가 격리 그룹을 만들어 img에 걸면 블렌드가 죽는다 — 실측).
- 전부 끄면: 사진 2장이 크림 배경 직사각형으로 보이고 연기는 선이 된다. 글·표·목록·행동은 그대로다.
## 하지 않기로 한 것
- 상단 바·sticky·backdrop-filter(한 장, 섹션 4, 행동 하나 — layout §2-c "내비 없음").
- 스크롤 리빌·스태거(배정에 없음). `.reveal` 잔재 11곳 삭제.
- 가운뎃점 메타 문자열, 영문 라벨, 표제 위 라벨, 히어로 버튼(행동은 브랜드 바의 링크 하나).
- 로컬 MaruBuri woff2 2개(900KB)·fonts.css·LICENSE.html — 배정 서체가 바뀌어 죽은 자산.
- 새 이미지 생성(brief). 연기는 사진이 아니라 SVG 재질로 만들었다.
- 가격을 히어로에 두는 것(카드 C) — 배정 "향·향로"와 충돌.
## 검증
검증 줄: html-validate 0 errors · stylelint 0 · no-hanja PASS 3파일 · showcase-audit PASS 6/6(320·390·768·1440·1920·2560) · design-gate 충족 13 / 미검증 0 / 실패 0(꺼짐 3: static·visual·webkit) · similarity 최대 쌍 0.50(font-foundry), 2026-10-06.
자동 검사와 별도 시각 평가(critique §2-1, 약한 축부터). 캡처는 세션 스크래치 `hyang/shots/` (`final-1440-first.png`, `final-390-first.png`, `final-*-full.png`, `final-*-gray-first.png`, `final-*-rm-*`, `final-*-nofx-*`, `final-filter-off-hero.png`, `final-smoke-reveal.png`, `final-320/768/1920/2560-*`).
| 축 | 점수 | 근거 | 다음 행동 |
|---|---|---|---|
| R3 묶음·정렬 | 1 | 1440 시작선 x=140(워드마크·h1·섹션), 916(사실 목록·시향 dl) 둘 + 가운데 정렬(제품·절편 캡션). 캡션의 가운데 정렬이 네 번째 선 후보 | 캡션을 왼쪽 선에 붙일지 검토 |
| R7 카피 목소리 | 1 | h1 "자연 침향"만으로는 경쟁사 치환이 성립한다. 사실 셋·표·방문 안내가 치환을 깬다. 지문 grep 0건, 은유 0 | h1에 고유 재료를 넣으면 "한 줄 큰 낱말" 배정과 충돌 — 유지 |
| R9 디테일 | 1 | 숫자 열 tabular 정렬 확인, 반복 항목 간격 동일. 200% OS 확대는 1.3×(게이트)까지만 실측 | 실기기 200% 확인 |
| R1 첫인상 | 2 | `final-1440-first.png` 3초 문장: "향연이라는 삼청동 가게가 기록을 적어 자연 침향을 팔고 시향을 받는다" — 컨셉의 명사·동사와 일치. 390도 같음. 반례: "왜 좋은가"는 사실 셋을 읽어야 나온다 | |
| R2 위계 | 2 | `final-1440-gray-first.png` 시선 돌·향 → h1 → 연기/사실. 의도와 같음. 크기·색·여백으로 구분. 반례: 찾지 못함 | |
| R4 타이포 | 2 | 웨이트 400만 실어 합성 볼드 없음, h1 1줄(320·390·768·1440·1920·2560 + 1.3×), 본문 36em, 자간 -0.02em에서 닿는 쌍 없음(1440·390 확대 확인). 반례: Gowun Batang 서브셋 밖 글자는 Noto Serif KR 폴백 | |
| R5 여백 | 2 | 히어로 100svh ↔ 섹션 space-8, 푸터 워드마크 20rem의 스케일 극단. 반례: 섹션 간격이 전부 같다(의도: 네 섹션이 같은 무게) | |
| R6 이미지 | 2 | 두 장 모두 누끼 처리로 같은 바탕 위에 있고 역할이 적혀 있다(히어로=타는 향, 절편=실물 단면). 390 첫 화면에 제품이 있다. 반례: 돌 크롭은 원본 300px을 1.3~2.8배 확대해 가장자리가 부드럽다 | |
| R8 구분성 | 2 | 고유 요소 셋(돌 위 향 사진, "삼청동, 2001년부터", 연기). 수렴 5축: 구도·표제 서체·eyebrow(없음)·CTA(링크 하나)·캡션(가운데) 중 같은 것 ≤1. similarity 최대 0.50 | |
| R10 모바일 | 2 | `final-390-first.png`에 브랜드·제품·h1·행동 링크 네 요소. 순서를 세로로 다시 편집(제품 → 표제 → 사실). 반례: 행동이 상단 링크라 첫 화면 아래쪽에는 없다 | |
합계 17/20, 통과선 충족(0점 없음, R1·R8 2점, 70% 이상).
대비 실측(#e6e1ea 위): 본문 #2a2530 11.6:1 · 보조 #5a5361 5.74:1 · 링크 #b62752 4.80:1 · "숙성 중" #8f1f40 on #ddd7e2 6.01:1. 어두운 배경·그라디언트 위 텍스트 없음. 게이트 대비 검사 51요소 AA 통과.
키보드: Tab 순서 스킵 링크 → 시향 방문 안내 → 끝(인터랙티브 요소 2개). 감소 모션: `mask-position 55%` 고정, animation none(실측).
미검증: 실기기 INP·field CWV, WebKit(게이트 webkit=false), Firefox(스크롤 타임라인 미지원 — 정지 상태만 코드로 확인), 스크린리더 실청취(role="img" + aria-label은 axe 통과), forced-colors, OS 200% 확대.
## 피드백 기록 · 보존 목록
- 피드백 없음(위임 작업).
- 보존: 상호·사실·수치·이미지 2장·앵커 id·스킵 링크·고지 1회.
## 변경 기록
- 2026-10-06 · 전면 리디자인(plan.md 배정) · 분할 히어로 → 제품 단독, 상단 바 → 내비 없음, 고지 푸터 → 워드마크 푸터, MaruBuri/Pretendard/웜 페이퍼/적갈 → Gowun Batang/Noto Sans KR/회보라/불씨, `.reveal` 11곳 삭제, 로컬 MaruBuri 삭제, 연기 SVG 재질 + 스크롤 마스크 추가. 숙성 기록과 판매 목록을 한 섹션으로 합쳐 섹션 4개.
- 2026-10-02 · 레드팀 06 · 히어로 본문을 면책 문구에서 브랜드 문장으로, "예시" 13회 → 1회(푸터 소유), 장부 넓은 컨테이너 예외 제거.
- 2026-10-02 · 카피 기준(copy-criteria.md) · h1 "연기는 흩어지고 향기만 머뭅니다" → "연도별로 기록한 자연 침향", "~가 아니라 ~다" 대구 제거, "입목" → "입고", 상태 "열매·침향 절편" → "판매 중", 상품명 "백단 침 향·침향 인엽" → "백단 선향·침향 칩".
- 2026-09 · 초판(quiet-luxury 프리셋, 분할 히어로, MaruBuri + Pretendard).

View file

@ -3,122 +3,172 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>향연 · 자연 침향 아카이브</title>
<title>향연 — 삼청동 자연 침향 전문점</title>
<meta
name="description"
content="연기는 흩어지고 향기만 머뭅니다. 자연 침향목의 수지 함량과 숙성 연도를 기록으로 남기는 향 아카이브. 서울 삼청동."
content="서울 삼청동의 가상 침향 전문점 향연. 2001년부터 들여온 자연 침향의 산지, 수지 함량, 입고 연도를 적어 절편과 선향을 팔고, 화요일부터 토요일 하루 세 번 시향 방문을 받습니다."
/>
<meta property="og:title" content="향연 · 자연 침향 아카이브" />
<meta property="og:description" content="수지 함량과 숙성 연도를 기록으로 남기는 침향 아카이브." />
<meta property="og:title" content="향연 — 삼청동 자연 침향 전문점" />
<meta property="og:description" content="산지, 수지 함량, 입고 연도를 적어 파는 자연 침향과 시향 방문 안내." />
<meta property="og:type" content="website" />
<meta name="theme-color" content="#F6F2E9" />
<meta property="og:image" content="https://designpaca.chanpaca.net/work/hyang-incense/assets/smoke.webp" />
<meta property="og:image:alt" content="검은 돌 받침에 꽂힌 침향 한 자루에서 연기가 오르는 모습" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="theme-color" content="#e6e1ea" />
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<!-- Gowun Batang은 표제·워드마크·연도·상품명·가격에만 쓰므로 text= 로 그 글자(59자)만 싣는다.
(풀 패밀리는 168KB, 서브셋은 수 KB — tokens §5 폰트 예산.) 표제·상품명 글자를 바꾸면
design.md "토큰과 예산"의 명령으로 text= 를 다시 만든다. -->
<link
rel="stylesheet"
href="./styles/fonts.css?v=20260912all"
href="https://fonts.googleapis.com/css2?family=Gowun+Batang&text=%2C0124689%EA%B0%80%EA%B5%B3%EA%B8%88%EA%B9%81%EB%82%98%EB%82%9C%EB%85%84%EB%8A%94%EB%8B%88%EB%8B%A4%EB%8B%A8%EB%90%9C%EB%93%A4%EB%9E%98%EB%A3%A8%EB%AC%B4%EB%B0%B1%EB%B2%88%EB%B6%80%EC%82%B4%EC%83%81%EC%83%9D%EC%84%A0%EC%84%B8%EC%88%98%EC%8A%B5%EC%8B%9C%EC%96%B4%EC%97%90%EC%97%B0%EC%98%A4%EC%99%94%EC%9A%94%EC%9B%90%EC%9D%80%EC%9D%BC%EC%9E%85%EC%9E%88%EC%9E%90%EC%9E%A5%EC%A0%88%EC%A7%80%EC%B2%98%EC%B9%A8%EC%B9%A9%ED%84%B0%ED%86%A0%ED%8E%B8%ED%95%98%ED%96%A5%ED%99%94&display=swap"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css"
href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR&display=swap"
/>
<link rel="stylesheet" href="./styles/main.css?v=20260912all" />
<link rel="stylesheet" href="./styles/main.css?v=20261006" />
<!-- 히어로 누끼는 CSS 배경으로 오리므로(요소 넘침 없이 확대 크롭) LCP용 preload를 둔다(images §3-c). -->
<link rel="preload" as="image" href="./assets/smoke.webp" fetchpriority="high" />
<link
rel="icon"
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23F6F2E9'/%3E%3Cpath d='M16 6c0 3 0 5 0 7m0 4c0 3 2 3 2 5m-2 2c0 2-2 3-2 5' fill='none' stroke='%237C3B24' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E"
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23e6e1ea'/%3E%3Cpath d='M16 7c-2 3 2 5 0 8s2 5 0 8' fill='none' stroke='%236f6678' stroke-width='1.4' stroke-linecap='round'/%3E%3Ccircle cx='16' cy='24' r='1.6' fill='%23b62752'/%3E%3Cellipse cx='16' cy='27' rx='7' ry='2.4' fill='%232a2530'/%3E%3C/svg%3E"
/>
</head>
<body>
<a class="skip" href="#main">본문으로 건너뛰기</a>
<header class="site-head">
<div class="wrap head-inner">
<a class="wordmark" href="#main">향연</a>
<nav class="nav" aria-label="섹션">
<a href="#wood">향목</a>
<a href="#aging">숙성</a>
<a href="#collection">아카이브</a>
<a href="#visit">방문</a>
</nav>
<!-- 연기 재질. 글자에는 걸지 않는다 — 히어로의 .smoke 한 곳만 쓴다(svg-filters §2·§6). -->
<svg class="defs" aria-hidden="true" focusable="false">
<defs>
<filter id="smoke-wisp" x="-120%" y="-15%" width="340%" height="130%" color-interpolation-filters="sRGB">
<feTurbulence type="fractalNoise" baseFrequency="0.005 0.011" numOctaves="3" seed="11" result="n" />
<feDisplacementMap in="SourceGraphic" in2="n" scale="46" xChannelSelector="R" yChannelSelector="G" result="d" />
<feGaussianBlur in="d" stdDeviation="1.3" />
</filter>
<filter id="smoke-haze" x="-160%" y="-20%" width="420%" height="140%" color-interpolation-filters="sRGB">
<feTurbulence type="fractalNoise" baseFrequency="0.006 0.012" numOctaves="3" seed="4" result="n" />
<feDisplacementMap in="SourceGraphic" in2="n" scale="70" xChannelSelector="R" yChannelSelector="G" result="d" />
<feGaussianBlur in="d" stdDeviation="11" />
</filter>
<linearGradient id="smoke-fade" x1="0" y1="1" x2="0" y2="0">
<stop offset="0" stop-color="#fff" />
<stop offset="0.55" stop-color="#fff" stop-opacity="0.7" />
<stop offset="1" stop-color="#fff" stop-opacity="0" />
</linearGradient>
<!-- 마스크 영역을 경로 bbox보다 넓게 잡는다 — 기본 -10%~120%면 블러로 번진 연기가 세로로 잘린다. -->
<mask id="smoke-mask" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox" x="-1.5" y="-0.1" width="4" height="1.2">
<rect x="-1.5" y="-0.1" width="4" height="1.2" fill="url(#smoke-fade)" />
</mask>
</defs>
</svg>
<header class="brand-bar">
<div class="wrap bar-inner">
<p class="wordmark">향연</p>
<a class="action" href="#visit">시향 방문 안내</a>
</div>
</header>
<main id="main">
<section class="hero" aria-labelledby="hero-h">
<div class="wrap hero-grid">
<div class="hero-text">
<p class="hero-kicker reveal">가상 향 아카이브 · 기록 형식 예시</p>
<h1 id="hero-h" class="reveal" style="--delay: 80ms">
연기는 흩어지고<br />향기만 머뭅니다
</h1>
<p class="lead reveal" style="--delay: 160ms">
향연은 향의 산지·숙성·연소 정보를 어떻게 기록할 수 있는지 보여 주는
가상 아카이브입니다. 아래 상품·가격·방문 정보는 판매나 예약을 위한
정보가 아니라 기록 형식의 예시입니다.
</p>
<div class="hero-actions reveal" style="--delay: 220ms">
<a class="btn" href="#collection">기록 구성 보기</a>
</div>
<div class="stage">
<figure class="product">
<div class="smoke" aria-hidden="true">
<svg class="smoke-svg" viewBox="0 0 200 720" preserveAspectRatio="xMidYMax meet">
<g mask="url(#smoke-mask)">
<path
class="smoke-cloud"
d="M92 430 C 150 360 150 260 118 200 S 64 100 96 0"
fill="none"
stroke="currentColor"
stroke-width="54"
stroke-linecap="round"
filter="url(#smoke-haze)"
/>
<path
class="smoke-haze"
d="M100 673 C 102 600 60 540 86 450 S 156 310 120 220 S 62 100 96 0"
fill="none"
stroke="currentColor"
stroke-width="20"
stroke-linecap="round"
filter="url(#smoke-haze)"
/>
<path
class="smoke-wisp"
d="M100 673 C 102 600 60 540 86 450 S 156 310 120 220 S 62 100 96 0"
fill="none"
stroke="currentColor"
stroke-width="2.6"
stroke-linecap="round"
filter="url(#smoke-wisp)"
/>
</g>
</svg>
</div>
<div
class="cut"
role="img"
aria-label="검은 돌 받침에 꽂힌 침향 한 자루"
></div>
</figure>
</div>
<figure class="hero-photo reveal" style="--delay: 120ms">
<img
src="./assets/smoke.webp"
alt="밝은 배경의 검은 받침대에서 한 줄기 침향 연기가 곧게 피어오르는 모습"
width="900"
height="1200"
loading="eager"
fetchpriority="high"
/>
<figcaption>침향 연출 이미지 · 가상 아카이브</figcaption>
</figure>
<h1 id="hero-h">자연 침향</h1>
<ul class="facts">
<li>삼청동, 2001년부터</li>
<li>입고 연도와 산지, 수지 함량을 적어 팝니다</li>
<li>시향은 화요일부터 토요일, 하루 세 번</li>
</ul>
</div>
</section>
<section id="wood" class="section" aria-labelledby="wood-h">
<div class="wrap two">
<figure class="two-photo reveal">
<img
src="./assets/agarwood.webp"
alt="자연 침향 단면 — 짙은 수지 결과 하얀 목질이 함께 보이는 절편"
width="1100"
height="825"
loading="lazy"
/>
<figcaption>자연 침향 단면 · 수지와 목질</figcaption>
<figure class="slab">
<div class="slab-cut">
<img
src="./assets/agarwood.webp"
alt="자연 침향 절편의 단면. 짙은 수지 결과 밝은 목질이 함께 보인다"
width="1100"
height="825"
loading="lazy"
decoding="async"
/>
</div>
<figcaption>자연 침향 단면. 검은 부분이 수지, 밝은 부분이 목질입니다.</figcaption>
</figure>
<div class="two-text">
<h2 id="wood-h">병든 나무만이<br />이 향을 가집니다</h2>
<h2 id="wood-h">침향은 상처 난 나무에 수지가 굳어 생깁니다</h2>
<p>
침향은 나무의 향이 아니라 나무의 상처입니다. 상처 입은 나무가 스스로를
아무려기 위해 분비한 수지가 오랜 세월 굳은 것 — 그래서 심은 나무에서는
얻을 수 없고, 자연에서 쓰러진 나무에서만 길어 올립니다.
침향나무는 상처를 입으면 스스로를 지키려고 수지를 내놓습니다. 이 수지가 오랜 세월
나무 속에서 굳은 것이 침향입니다. 심은 나무에서는 얻기 어려워서, 향연은 자연에서
쓰러진 나무에서 거둔 침향만 들여옵니다.
</p>
<p class="muted">
이 섹션은 산지·수지 함량·숙성 상태를 함께 기록하는 방식을 설명합니다.
특정 목재의 매입 기준이나 실제 아카이브 운영 정책을 뜻하지 않습니다.
수지가 많을수록 절편은 무겁고 검으며, 물에 넣으면 가라앉습니다. 그래서 향연은
무게보다 수지 함량을 먼저 적습니다.
</p>
</div>
</div>
</section>
<section id="aging" class="section band" aria-labelledby="aging-h">
<section id="aging" class="section record" aria-labelledby="aging-h">
<div class="wrap">
<div class="aging-head">
<h2 id="aging-h">숙성 기록 예시</h2>
<p class="muted">
들여온 해와 수지 함량, 상태를 한 줄에서 읽는 기록 형식입니다. 아래
연도·산지·수지 함량은 실제 측정이나 재고를 뜻하지 않습니다.
</p>
<div class="record-head">
<h2 id="aging-h">가장 오래된 절편은 2001년에 들어왔습니다</h2>
<p class="muted">들여온 해와 산지, 수지 함량, 지금 상태를 한 줄에 적습니다.</p>
</div>
<div class="table-wrap reveal">
<div class="table-wrap">
<table>
<caption class="sr-only">
숙성 기록 예시 — 입목 연도, 산지, 수지 함량, 상태
</caption>
<caption class="sr-only">숙성 기록 — 입고 연도, 산지, 수지 함량, 상태</caption>
<thead>
<tr>
<th scope="col">입목</th>
<th scope="col">입고</th>
<th scope="col">산지</th>
<th scope="col" class="num">수지 함량</th>
<th scope="col">상태</th>
@ -129,87 +179,85 @@
<th scope="row">2001년</th>
<td>베트남 카호아</td>
<td class="num">64.2%</td>
<td>열매 · 상태 예시</td>
<td>판매 중</td>
</tr>
<tr>
<th scope="row">2012년</th>
<td>인도네시아 리아우</td>
<td class="num">51.8%</td>
<td>침향 절편 · 상태 예시</td>
<td>판매 중</td>
</tr>
<tr>
<th scope="row">2024년</th>
<td>캄보디아 프놈펜 인근</td>
<td class="num">47.3%</td>
<td>숙성 중 · 상태 예시</td>
<td class="is-aging">숙성 중</td>
</tr>
</tbody>
</table>
</div>
<p class="aging-note muted">
수지 함량과 상태 표기는 기록 형식을 설명하기 위한 예시 값입니다.
</p>
</div>
</section>
<section id="collection" class="section" aria-labelledby="collection-h">
<div class="wrap">
<h2 id="collection-h">기록으로 살펴보는 구성</h2>
<h3 id="collection" class="collection-h">지금 살 수 있는 향은 세 가지입니다</h3>
<ol class="collection">
<li class="item reveal">
<li class="item">
<div class="item-text">
<h3>자연 침향 절편</h3>
<p>2001년 입목 · 수지 64.2% · 10g</p>
<p class="item-name">자연 침향 절편</p>
<p>2001년 입고, 수지 64.2%, 10g</p>
</div>
<p class="item-price">예시 180,000원</p>
<p class="item-price">180,000원</p>
</li>
<li class="item reveal" style="--delay: 80ms">
<li class="item">
<div class="item-text">
<h3>백단 침 향</h3>
<p>인도 마이소르 노목 · 20g · 연소 45분</p>
<p class="item-name">백단 선향</p>
<p>인도 마이소르산 노목, 20g, 한 개비 45분</p>
</div>
<p class="item-price">예시 42,000원</p>
<p class="item-price">42,000원</p>
</li>
<li class="item reveal" style="--delay: 160ms">
<li class="item">
<div class="item-text">
<h3>침향 인엽</h3>
<p>리아우산 · 2012년 입목 · 3g</p>
<p class="item-name">침향 칩</p>
<p>인도네시아 리아우산, 2012년 입고, 3g</p>
</div>
<p class="item-price">예시 96,000원</p>
<p class="item-price">96,000원</p>
</li>
</ol>
<p class="muted collection-note">
이 목록은 상품명·단위·가격을 기록하는 방식을 보여 줍니다. 실제 상품 판매,
향 시향, 예약 또는 방문을 제공하지 않습니다.
</p>
</div>
</section>
<section id="visit" class="section visit" aria-labelledby="visit-h">
<div class="wrap visit-grid">
<div>
<h2 id="visit-h">방문 정보 예시</h2>
<address>
가상 아카이브 안내<br />
실제 장소와 방문 경로를 제공하지 않습니다.
</address>
</div>
<div class="visit-info">
<dl>
<div>
<dt>방문 시간 예시</dt>
<dd>화–토 · 11:00, 14:00, 16:00 회당 50분</dd>
</div>
<div>
<dt>예약</dt>
<dd>실제 예약 및 문의를 받지 않습니다.</dd>
</div>
</dl>
</div>
<p class="visit-mark">향연</p>
<h2 id="visit-h">시향은 화요일부터 토요일, 하루 세 번입니다</h2>
<dl class="visit-info">
<div>
<dt>시간</dt>
<dd>11시, 14시, 16시. 회당 50분</dd>
</div>
<div>
<dt>인원</dt>
<dd>회당 최대 4명</dd>
</div>
<div>
<dt>방식</dt>
<dd>절편을 직접 데워 향을 맡아 봅니다</dd>
</div>
<div>
<dt>예약</dt>
<dd>가상 매장이라 예약과 문의를 받지 않습니다</dd>
</div>
</dl>
</div>
</section>
</main>
<!-- 페이지 범위의 가상 고지는 푸터 한 곳이 소유한다(trustworthy-showcases §4-b). -->
<footer class="site-foot">
<div class="wrap">
<p class="foot-mark">향연</p>
<p class="foot-line">
<span>삼청동 자연 침향 전문점</span>
<span>향연은 가상 브랜드 쇼케이스입니다. 기록과 가격, 방문 정보는 예시이며 실제 판매나 시향, 예약을 제공하지 않습니다.</span>
</p>
</div>
</footer>
</body>
</html>

View file

@ -1,7 +1,7 @@
@import url("./tokens.css?v=20260912all");
@import url("./tokens.css?v=20261006");
/* ==========================================================================
향연 — quiet-luxury. 밝은 편집면 위의 기록.
향연 — 회보라 바탕 위의 향 한 자루. 토큰은 tokens.css 한 곳에만 있다.
========================================================================== */
*,
@ -17,6 +17,7 @@ html {
-webkit-text-size-adjust: 100%;
scroll-behavior: smooth;
background: var(--surface);
font-synthesis-style: none;
}
@media (prefers-reduced-motion: reduce) {
html {
@ -31,30 +32,44 @@ body {
font-size: var(--step-0);
line-height: var(--leading-normal);
-webkit-font-smoothing: antialiased;
overflow-x: clip;
}
/* 한글 조판 정본(typography §6-5) */
:lang(ko) {
word-break: keep-all;
overflow-wrap: anywhere;
line-break: strict;
}
:lang(ko) :is(em, i, cite, dfn, var, address) {
font-style: normal;
}
:lang(ko) a {
text-underline-position: under;
}
:where(h1, h2, h3) {
font-family: var(--font-display);
font-weight: 500;
font-weight: 400;
line-height: var(--leading-tight);
letter-spacing: -0.005em;
word-break: keep-all;
overflow-wrap: break-word;
text-wrap: balance;
}
h1 {
font-size: var(--step-3);
letter-spacing: -0.02em;
line-height: 1.1;
white-space: nowrap; /* 한 줄 큰 낱말 — 줄 수를 맞추려고 문구를 바꾸지 않는다 */
}
h2 {
font-size: var(--step-2);
line-height: 1.3;
}
h3 {
font-size: var(--step-1);
line-height: 1.3;
}
:where(p, li, dd, dt, th, td, address, figcaption) {
word-break: keep-all;
overflow-wrap: break-word;
:where(p, li, dd, dt, th, td, figcaption) {
line-height: var(--leading-normal);
text-wrap: pretty;
}
@ -65,15 +80,6 @@ h3 {
a {
color: inherit;
}
.link {
color: var(--accent);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color var(--dur-quick) var(--ease-soft);
}
.link:hover {
border-color: var(--accent);
}
:focus-visible {
outline: 2px solid var(--accent);
@ -101,194 +107,230 @@ a {
clip: rect(0 0 0 0);
white-space: nowrap;
}
.defs {
position: absolute;
width: 0;
height: 0;
overflow: hidden;
}
.wrap {
width: min(100% - 2 * var(--pad-inline), var(--container));
margin-inline: auto;
}
/* ── 헤더 ─────────────────────────────────────────────────────────────── */
/* ── 브랜드 표기와 행동 하나 — 내비는 없다(layout §2-c). 고정하지 않고 흐리지 않는다. ── */
.site-head {
position: sticky;
top: 0;
z-index: 50;
background: color-mix(in srgb, var(--surface) 90%, transparent);
backdrop-filter: blur(6px);
border-bottom: 1px solid var(--line);
.brand-bar {
position: relative;
z-index: 2;
}
.head-inner {
.bar-inner {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--space-4);
padding-block: var(--space-3);
padding-block: var(--space-4);
}
.wordmark {
font-family: var(--font-display);
font-size: var(--step-1);
font-weight: 600;
text-decoration: none;
}
.wordmark .han {
color: var(--ink-muted);
font-weight: 400;
font-size: var(--step-0);
margin-left: var(--space-1);
font-size: var(--step-1);
line-height: 1.2;
white-space: nowrap;
}
.nav {
display: flex;
flex-wrap: wrap;
gap: clamp(var(--space-3), 2vw, var(--space-5));
font-size: var(--step--1);
}
.nav a {
text-decoration: none;
color: var(--ink-muted);
padding-block: 2px;
border-bottom: 1px solid transparent;
transition: color var(--dur-quick) var(--ease-soft),
border-color var(--dur-quick) var(--ease-soft);
}
.nav a:hover {
color: var(--ink);
border-color: var(--accent);
}
/* ── 히어로 ───────────────────────────────────────────────────────────── */
.hero {
display: grid;
align-items: center;
min-block-size: min(46rem, calc(100svh - 4rem));
padding-block: var(--space-6);
border-bottom: 1px solid var(--line);
}
.hero-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(16rem, 28rem);
gap: clamp(var(--space-5), 6vw, var(--space-8));
align-items: center;
}
.hero-grid > *,
.two > *,
.visit-grid > * {
min-width: 0;
}
.hero-text {
max-width: 38rem;
padding-block: var(--space-4);
}
.hero-kicker {
font-size: var(--step--1);
color: var(--ink-muted);
letter-spacing: 0.14em;
margin-bottom: var(--space-5);
}
.lead {
max-width: 42rem;
}
.hero-text .lead {
margin-top: var(--space-5);
}
.hero-actions {
margin-top: var(--space-6);
}
.btn {
.action {
display: inline-flex;
align-items: center;
min-height: 44px;
border: 1px solid var(--ink);
color: var(--ink);
text-decoration: none;
padding: 0.8rem 2rem;
border-radius: var(--radius);
transition: background var(--dur-quick) var(--ease-soft),
color var(--dur-quick) var(--ease-soft);
padding-inline: var(--space-2);
color: var(--accent);
text-decoration: underline;
text-underline-offset: 0.35em;
text-decoration-thickness: 1px;
transition: color var(--dur-quick) var(--ease-soft);
}
.btn:hover {
background: var(--ink);
color: var(--surface);
.action:hover {
color: var(--accent-deep);
text-decoration-thickness: 2px;
}
.hero-photo {
/* ── 히어로 — 제품 단독. 돌 받침 위 향 한 자루가 가운데, 글은 아래 한 줄과 사실 셋. ── */
.hero {
min-block-size: calc(100svh - 5.5rem);
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: var(--space-2);
width: min(100%, 28rem);
justify-self: end;
align-items: start;
}
.hero-photo img {
display: block;
width: 100%;
aspect-ratio: 3 / 4;
height: auto;
object-fit: cover;
border-radius: var(--radius);
.hero-grid {
display: grid;
grid-template-columns: minmax(0, auto) minmax(14rem, 24rem);
grid-template-areas:
"stage stage"
"title facts";
grid-template-rows: minmax(0, 1fr) auto;
align-items: end;
column-gap: var(--space-6);
row-gap: var(--space-5);
padding-block: var(--space-3) var(--space-6);
}
.hero-photo figcaption {
font-size: var(--step--1);
color: var(--ink-muted);
letter-spacing: 0.06em;
.stage {
grid-area: stage;
display: grid;
justify-items: center;
align-items: end;
min-block-size: 22rem;
}
.product {
position: relative;
width: min(100%, clamp(14rem, 12rem + 14vw, 25rem));
}
/* ── 섹션 공통 ────────────────────────────────────────────────────────── */
/* 누끼 대체 — 원본이 사진이라 CSS로 오린다(agent-brief): 돌·향 자리만 잘라 내고
multiply + 채도·명도 보정으로 크림 배경을 회보라에 녹인 뒤, 타원 마스크로 테두리를 지운다. */
.cut {
position: relative;
aspect-ratio: 320 / 196;
background-image: url("../assets/smoke.webp");
background-size: 281.25% auto; /* 900 / 320 */
background-position: 50% 87.05%; /* 원본의 왼쪽 290px, 위 874px(향 끝 바로 위)부터 보인다 */
background-repeat: no-repeat;
mask-image: radial-gradient(ellipse 58% 62% at 50% 56%, #000 48%, transparent 100%);
mix-blend-mode: multiply; /* 마스크가 격리 그룹을 만들므로 블렌드는 마스크를 가진 상자에 건다 */
filter: saturate(0.55) brightness(1.13) contrast(1.04);
}
/* 연기 — 향 끝(그림의 윗변에서 8% 아래, 가로 48%)에서 올라간다. 필터는 이 SVG 안에서만 돈다. */
.smoke {
position: absolute;
left: 0;
right: 0;
bottom: 80%; /* 향 끝은 그림 높이의 92%. 경로 시작점(SVG 673/720)이 그 자리에 온다 */
height: 185%;
color: var(--smoke);
pointer-events: none;
mask-image: linear-gradient(to bottom, transparent 0%, transparent 22%, #000 50%, #000 100%);
mask-size: 100% 200%;
mask-position: 0 var(--smoke-rest);
mask-repeat: no-repeat;
}
.smoke-svg {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
overflow: visible;
translate: -1.5% 0; /* 향 끝이 그림 가로 48.4%에 있다 */
}
.smoke-cloud {
opacity: 0.16;
}
.smoke-haze {
opacity: 0.3;
}
.smoke-wisp {
opacity: 0.9;
}
/* 스크롤에 따라 마스크가 내려가며 연기가 더 높이 드러난다. 최상단 요소라 view()가 아니라
scroll(root)을 쓴다(motion-parallax §9). 초기 상태는 가드 안에 둔다. */
@supports (animation-timeline: scroll()) {
@media (prefers-reduced-motion: no-preference) {
.smoke {
animation: smoke-reveal 1ms linear both;
animation-timeline: scroll(root block);
animation-range: 0 40vh; /* 연기가 화면 위로 빠져나가기 전에 다 드러난다 */
}
@keyframes smoke-reveal {
from {
mask-position: 0 30%;
}
to {
mask-position: 0 100%;
}
}
}
}
.hero h1 {
grid-area: title;
align-self: end;
color: var(--ink);
}
.facts {
grid-area: facts;
list-style: none;
padding: 0;
display: grid;
gap: var(--space-1);
border-top: 1px solid var(--line);
padding-top: var(--space-3);
color: var(--ink-muted);
}
/* ── 섹션 공통 ── */
.section {
padding-block: var(--space-8);
border-top: 1px solid var(--line);
}
.section[id] {
scroll-margin-top: 6rem;
scroll-margin-top: var(--space-4);
}
#aging .wrap {
width: min(100% - 2 * var(--pad-inline), var(--container-wide));
}
.band {
background: var(--surface-raised);
border-block: 1px solid var(--line);
.section p,
.section dd {
max-width: var(--measure);
}
/* ── 향목 (2단) ───────────────────────────────────────────────────────── */
/* ── 침향이란 — 절편 누끼 + 글 ── */
.two {
display: grid;
grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
gap: var(--space-6) var(--space-7);
align-items: center;
}
.two-photo img {
.two > * {
min-width: 0;
}
.slab-cut {
aspect-ratio: 1100 / 825;
overflow: hidden;
mask-image: radial-gradient(ellipse 45% 46% at 50% 48%, #000 82%, transparent 100%);
mix-blend-mode: multiply;
}
.slab-cut img {
display: block;
width: 100%;
height: auto;
border-radius: var(--radius);
filter: saturate(0.7) brightness(1.17) contrast(1.06);
}
.two-photo figcaption {
.slab figcaption {
font-size: var(--step--1);
color: var(--ink-faint);
color: var(--ink-muted);
margin-top: var(--space-2);
text-align: center;
}
.two-text p + p {
margin-top: var(--space-4);
}
.two-text p {
max-width: 42rem;
}
.two-text .muted {
margin-top: var(--space-4);
.two-text h2 {
margin-bottom: var(--space-4);
}
/* ── 숙성 장부 ────────────────────────────────────────────────────────── */
/* ── 기록과 가격 ── */
.aging-head {
max-width: 42rem;
.record-head {
max-width: var(--measure);
margin-bottom: var(--space-5);
}
.aging-head p {
.record-head p {
margin-top: var(--space-3);
}
.table-wrap {
overflow-x: auto;
background: var(--surface-raised);
border-radius: var(--radius);
padding: var(--space-2) var(--space-3);
}
table {
width: 100%;
@ -296,38 +338,49 @@ table {
}
thead th {
text-align: left;
font-weight: 500;
font-weight: var(--weight-strong);
font-size: var(--step--1);
color: var(--ink-muted);
padding: var(--space-2) var(--space-3);
border-bottom: 1px solid var(--ink-faint);
border-bottom: 1px solid var(--ink-muted);
}
tbody th {
font-family: var(--font-display);
font-weight: 500;
font-weight: 400;
text-align: left;
}
/* 자동 폭 표 셀에서 anywhere가 어절을 글자 단위로 쪼개므로 표 안만 break-word(typography §6-5 예외) */
table :is(th, td) {
overflow-wrap: break-word;
}
tbody th,
tbody td:last-child {
white-space: nowrap;
}
tbody td,
tbody th {
padding: var(--space-3);
border-bottom: 1px solid var(--line);
vertical-align: baseline;
}
tbody tr:last-child :is(td, th) {
border-bottom: 0;
}
.num {
font-variant-numeric: tabular-nums;
text-align: right;
white-space: nowrap;
}
.aging-note {
margin-top: var(--space-3);
font-size: var(--step--1);
.is-aging {
color: var(--accent-deep);
}
/* ── 아카이브 목록 ────────────────────────────────────────────────────── */
.collection-h {
margin-top: var(--space-7);
}
.collection {
list-style: none;
margin-top: var(--space-5);
margin-top: var(--space-4);
padding: 0;
border-top: 1px solid var(--line);
}
@ -339,10 +392,12 @@ tbody th {
padding-block: var(--space-4);
border-bottom: 1px solid var(--line);
}
.item h3 {
.item-name {
font-family: var(--font-display);
font-size: var(--step-1);
line-height: 1.3;
}
.item p {
.item-text p + p {
font-size: var(--step--1);
color: var(--ink-muted);
margin-top: var(--space-1);
@ -353,92 +408,105 @@ tbody th {
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.collection-note {
margin-top: var(--space-4);
max-width: 42rem;
}
/* ── 방문 ─────────────────────────────────────────────────────────────── */
/* ── 시향 방문 — 페이지의 행동 하나가 끝나는 곳 ── */
.visit {
border-top: 1px solid var(--line);
}
.visit-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: var(--space-5) var(--space-7);
align-items: start;
}
.visit address {
font-style: normal;
margin-top: var(--space-3);
color: var(--ink-muted);
.visit-grid > * {
min-width: 0;
}
.visit-info dl {
.visit-info {
display: grid;
gap: var(--space-3);
}
.visit-info dt {
font-size: var(--step--1);
color: var(--ink-faint);
color: var(--ink-muted);
}
.visit-info dd {
margin-top: 2px;
}
.visit-mark {
/* ── 푸터 — 큰 워드마크 한 줄(layout §2-d). 고지는 그 아래 한 줄이다. ── */
.site-foot {
border-top: 1px solid var(--line);
padding-block: var(--space-6) var(--space-5);
overflow: hidden;
}
.foot-mark {
font-family: var(--font-display);
color: var(--ink-faint);
font-weight: 400;
font-size: var(--step-mark);
line-height: 1;
letter-spacing: -0.03em;
white-space: nowrap;
color: var(--ink);
margin-inline-start: -0.04em;
}
.foot-line {
display: flex;
flex-wrap: wrap;
gap: var(--space-2) var(--space-5);
margin-top: var(--space-4);
font-size: var(--step--1);
letter-spacing: 0.08em;
align-self: end;
color: var(--ink-muted);
}
.foot-line span:last-child {
max-width: var(--measure);
}
/* ── 등장 모션 — 다른 페이지보다 느리다 ──────────────────────────────── */
.reveal {
opacity: 1;
translate: 0 0;
}
/* ── 반응형 ───────────────────────────────────────────────────────────── */
/* ── 반응형 ── */
@media (max-width: 900px) {
.hero-grid,
.two {
.hero-grid {
grid-template-columns: 1fr;
grid-template-areas:
"stage"
"title"
"facts";
row-gap: var(--space-4);
}
.stage {
min-block-size: 18rem;
}
.product {
width: min(100%, 22rem);
}
.two,
.visit-grid {
grid-template-columns: 1fr;
gap: var(--space-5);
}
.hero-photo {
max-width: 24rem;
justify-content: start;
justify-self: start;
}
.visit-grid {
grid-template-columns: 1fr;
}
.visit-mark {
display: none;
}
.hero {
min-block-size: auto;
padding-block: var(--space-6);
.slab {
max-width: 28rem;
}
}
@media (max-width: 560px) {
.head-inner {
flex-direction: column;
align-items: flex-start;
gap: var(--space-1);
.hero {
min-block-size: calc(100svh - 5rem);
}
.nav {
width: 100%;
justify-content: flex-start;
.stage {
min-block-size: 15rem;
}
.product {
width: min(100%, 18rem);
}
.item {
grid-template-columns: 1fr;
gap: var(--space-1);
}
.item-price {
white-space: normal;
.table-wrap {
padding-inline: var(--space-2);
}
thead th,
tbody td,
tbody th {
padding-inline: var(--space-2);
}
}

View file

@ -1,37 +1,41 @@
/* ==========================================================================
향연 — 디자인 토큰
프리셋: quiet-luxury
컨셉 한 문장: 밝은 편집면 위의 기록 — 여백이 주인공이고 연기 한 줄기가 흔적이다.
레퍼런스: 방향은 dogfood-incense(단, 그 파일의 6축 수치는 audit-references.md
에서 날조로 판명 — 토큰 근거로 쓰지 않는다). 사이트 선택(정향·아카이브
계열의 절제)만 방향 앵커로 쓰고, 값은 브리프에서 다시 정했다.
하지 않은 것: 스티커형 상품 카드, 영어 eyebrow, 배경 음영 그라디언트,
숫자 카운트업. 이유: 기록물의 권위는 고요함에서 온다.
향연 — 디자인 토큰 (2026-10-06 재작업)
컨셉 한 문장: 침향을 찾는 손님이 돌 받침에 꽂힌 향 한 자루와 연기를 보고,
입고 연도·수지 함량 기록을 읽은 뒤 시향 시간을 확인한다.
배정(outputs/rework-2026-10-06/plan.md): 제품 단독 히어로 · 내비 없음 ·
큰 워드마크 푸터 · Gowun Batang / Noto Sans KR · 회보라 #e6e1ea ·
강조 LCh 10° · radius 2px · scroll-driven 연기 · feTurbulence 연기 재질.
하지 않은 것: 웜 페이퍼 바탕, 마루 부리, 적갈 강조, 상단 바, 스크롤 리빌 —
font-foundry·thursday·muwol·materia와 0.80~0.96으로 묶였던 군집의 축이다.
========================================================================== */
:root {
/* 타입 — 최대(60px) ÷ 본문(17px) ≈ 3.5배. 본문을 17px로 — 천천히 읽히는 페이지 */
--step--1: 0.8125rem; /* 13px — 캡션 */
--step-0: 1.0625rem; /* 17px — 본문 */
--step-1: 1.25rem; /* 20px — 소제목 */
--step-2: clamp(1.375rem, 1.2rem + 0.9vw, 1.75rem);/* 28px — 섹션 표제 */
--step-3: clamp(2.25rem, 1.4rem + 3.6vw, 3.75rem); /* 60px — 디스플레이 */
/* 타입 — 본문 17px(천천히 읽히는 페이지), 표제는 한 줄 큰 낱말 하나뿐이라
본문의 8배까지 올린다(1440에서 144px, 390에서 63px). */
--step--1: 0.8125rem; /* 13px — 캡션·표 머리 */
--step-0: 1.0625rem; /* 17px — 본문 */
--step-1: 1.25rem; /* 20px — 소제목·가격 */
--step-2: clamp(1.5rem, 1.25rem + 1.2vw, 2.125rem); /* 24~34px — 섹션 표제 */
--step-3: clamp(3.5rem, 2rem + 8vw, 9rem); /* 56~144px — h1 한 줄 */
--step-mark: clamp(5rem, 2rem + 22vw, 20rem); /* 푸터 워드마크 */
--leading-tight: 1.3;
--leading-normal: 1.9;
--leading-tight: 1.2;
--leading-normal: 1.8;
--font-display: "MaruBuri", serif;
--font-body: "Pretendard Variable", Pretendard, -apple-system, sans-serif;
--font-display: "Gowun Batang", "Noto Serif KR", serif;
--font-body: "Noto Sans KR", "Apple SD Gothic Neo", sans-serif;
--weight-strong: 400; /* 폰트 전송량 때문에 웨이트는 패밀리당 하나(400)만 싣는다. 강조는 색·크기로 */
/* 색 — 따뜻한 중성 바탕 2단계 + 텍스트 3단계 + 적갈 1. */
--surface: #f6f2e9;
--surface-raised: #efe9dc;
--ink: #2b2724;
--ink-muted: #6d655c;
--ink-faint: #746c60;
--line: #ddd4c3;
--accent: #7c3b24; /* 적갈 — 링크와 핵심 동작만 */
--accent-hover: #5f2c1a;
/* 색 — 회보라 바탕 2단계 + 먹 3단계 + 불씨 1. 강조는 링크·행동·표의 "숙성 중" 한 칸.
대비(실측 2026-10-06): ink 11.6:1, ink-muted 5.7:1, accent 4.8:1 (모두 #e6e1ea 위). */
--surface: #e6e1ea;
--surface-raised: #ddd7e2;
--ink: #2a2530;
--ink-muted: #5a5361;
--line: #c6bfcd;
--accent: #b62752; /* 불씨 — CIELAB LCh 10.7° (similarity.mjs 기준) */
--accent-deep: #8f1f40; /* hover·작은 글자 */
--smoke: #6f6678; /* 연기 — 먹을 바탕 쪽으로 눕힌 회보라 */
--space-1: 0.25rem;
--space-2: 0.5rem;
@ -40,16 +44,17 @@
--space-5: 2.5rem;
--space-6: 4rem;
--space-7: 6.5rem;
--space-8: clamp(5rem, 3.4rem + 6vw, 10rem); /* 이 페이지의 여백은 다른 페이지보다 깊다 */
--space-8: clamp(5rem, 3.4rem + 6vw, 10rem);
--radius: 2px;
/* 향의 문장은 좁게, 장부와 실물 기록은 넓게 둔다. */
--measure: 36em; /* 한글 본문 한 줄 32~40자 (typography §6-5) */
--container: 1160px;
--container-wide: 1440px;
--pad-inline: clamp(1.25rem, 1rem + 2.5vw, 4.5rem);
--dur-quick: 160ms;
--dur-normal: 560ms; /* 느린 페이지 — 등장도 느리게 */
--ease-soft: cubic-bezier(0.25, 1, 0.35, 1);
/* 연기 — 스크롤 0~40vh 동안 마스크가 올라가며 연기가 더 높이 보인다. */
--smoke-rest: 55%; /* 미지원·감소 모션에서 드러나는 높이 */
}