- 핵심 규칙 6: 완료의 정의는 게이트 통과. 사용자를 QA로 쓰지 않는다 - 5단계 기계 검사 4번째: design-gate 실행 의무화 - references/audit-gate.md: 사고-검사 매핑, SEO/meta 체크리스트, OS/브라우저 특성, 하니스 규칙 - tools/design-gate.mjs: 범용 게이트(메타/SEO·대비·수축·리듬·트랙·스케일×폭 + 옵션 L0/L3/L4, checks 깊은 병합) - 리듬·트랙 불변식: 숫자 라벨 등폭·빈 셀 트랙 균일·등간격 — 시간표 자동배치 결함 재현 픽스처 검출, 앱 15뷰 통과(오탐 0) feat(site): 관리 앱 2종 프로덕션 콘솔(v6→v18) - 가온 학적부 9뷰·두레 수강신청 6뷰: shadcn 문법, Pretendard/Noto Serif/IBM Plex 폰트 전략, 볼드 금지(400/500/600), WCAG AA 대비 전면 교정, 한글 keep-all 조판 - LMS 필수 요소(알림 센터·공지·진도·평가 유형·출결 사유·학점 경고), 12명 기준 데이터 정합, SEO 구조(h1 유일·OG/twitter·og.png) - 시간표 자동배치 결함 수리(명시적 격자 좌표) - QA 게이트: L0 stylelint/html-validate · L1 단위 30 · L2 감사 61+불변식 · L3 시각회귀 30화면 · L4 WebKit · L5 키보드 탐색 — npm run verify 실패 시 배포 금지 체인
This commit is contained in:
parent
78ddc8b61a
commit
72337b7ee0
226 changed files with 18212 additions and 380 deletions
BIN
apps/site/public/work/muwol-coffee/assets/beans-hero.webp
Normal file
BIN
apps/site/public/work/muwol-coffee/assets/beans-hero.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
BIN
apps/site/public/work/muwol-coffee/assets/pourover.webp
Normal file
BIN
apps/site/public/work/muwol-coffee/assets/pourover.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
333
apps/site/public/work/muwol-coffee/index.html
Normal file
333
apps/site/public/work/muwol-coffee/index.html
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>무월 (霧月) · 싱글오리진 원두 정기구독</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="원두마다 산미·단맛·바디를 같은 척도로 측정해 적고, 생두 매입가를 공개합니다. 격주 화요일 로스팅, 서울 서촌."
|
||||
/>
|
||||
<meta property="og:title" content="무월 (霧月) · 싱글오리진 원두 정기구독" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="측정된 좌표로 원두를 고르는 격주 구독. 생두 매입 원장 공개."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta name="theme-color" content="#F4F4F0" />
|
||||
|
||||
<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 />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/gh/webfontworld/naver/MaruBuri.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
/>
|
||||
<link rel="stylesheet" href="./styles/main.css?v=2" />
|
||||
<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='%23F4F4F0'/%3E%3Cpath d='M16 7a7 7 0 0 1 7 7h-7z' fill='%237A3E1D'/%3E%3Cpath d='M16 9a7 7 0 0 0-7 7h7z' fill='%23181B18'/%3E%3Ccircle cx='16' cy='16' r='9' fill='none' stroke='%23181B18' stroke-width='1.5'/%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">
|
||||
무월 <span class="wordmark-han">霧月</span>
|
||||
</a>
|
||||
<nav class="nav" aria-label="섹션">
|
||||
<a href="#scale">척도</a>
|
||||
<a href="#ledger">원장</a>
|
||||
<a href="#recipe">레시피</a>
|
||||
<a href="#plan">구독</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="main">
|
||||
<!--
|
||||
히어로 — R1(coffeecollective.dk): 가격을 첫 화면에서 숨기지 않는다.
|
||||
문구만으로 시작하는 대신 이번 주 로스 사진 한 장과 원두 둘(값 포함)을 같이 둔다.
|
||||
-->
|
||||
<section class="hero" aria-labelledby="hero-h">
|
||||
<div class="wrap hero-grid">
|
||||
<div class="hero-text">
|
||||
<p class="hero-label reveal">싱글오리진 로스터리 · 서울 서촌</p>
|
||||
<h1 id="hero-h" class="reveal" style="--delay: 60ms">
|
||||
취향은 형용사가 아니라<br />측정된 좌표입니다
|
||||
</h1>
|
||||
<p class="lead reveal" style="--delay: 120ms">
|
||||
과일 향이 난다는 말로는 추출 온도를 정할 수 없습니다. 무월은 원두마다
|
||||
산미와 단맛, 바디를 같은 척도로 측정해 적고, 생두를 얼마에 들였는지까지
|
||||
공개합니다. 마셔보기 전에 판단할 수 있어야 원두 고르는 즐거움이 시작됩니다.
|
||||
</p>
|
||||
<div class="hero-actions reveal" style="--delay: 180ms">
|
||||
<a class="btn" href="#plan">격주 구독 시작하기</a>
|
||||
<p class="hero-note">격주 화요일 로스팅 출고 · 언제든 해지</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<figure class="hero-photo reveal" style="--delay: 100ms">
|
||||
<img
|
||||
src="./assets/beans-hero.webp"
|
||||
alt="따뜻한 회색 리넨 위 질도기 그릇에 담긴 갓 볶은 원두와 놋쇠 스쿱"
|
||||
width="900"
|
||||
height="1200"
|
||||
loading="eager"
|
||||
fetchpriority="high"
|
||||
/>
|
||||
<figcaption>이번 주 첫 로스 · 8월 19일</figcaption>
|
||||
</figure>
|
||||
|
||||
<!-- 이번 주 원두 — 카드가 아니라 원장의 첫 두 줄 -->
|
||||
<dl class="hero-beans reveal" style="--delay: 240ms">
|
||||
<div class="bean-row">
|
||||
<div>
|
||||
<dt>에티오피아 구지 우라가</dt>
|
||||
<dd class="bean-origin">워시드 · 해발 2,150m · 커핑 88.75</dd>
|
||||
</div>
|
||||
<dd class="bean-price"><span>100g</span> 8,500원</dd>
|
||||
</div>
|
||||
<div class="bean-row">
|
||||
<div>
|
||||
<dt>콜롬비아 엘 파라이소</dt>
|
||||
<dd class="bean-origin">혐기발효 · 해발 1,930m · 커핑 91.20</dd>
|
||||
</div>
|
||||
<dd class="bean-price"><span>100g</span> 11,000원</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!--
|
||||
척도 — 향미 좌표계. 히어로의 계기판 노릇을 내려놓고
|
||||
본문의 척도로 옮긴다. 눈금과 점만 남긴다.
|
||||
-->
|
||||
<section id="scale" class="section" aria-labelledby="scale-h">
|
||||
<div class="wrap scale-grid">
|
||||
<div class="scale-text">
|
||||
<h2 id="scale-h">같은 척도로 잰<br />향미 좌표</h2>
|
||||
<p>
|
||||
같은 밝기로 볶아도 생두가 머금은 수분과 밀도에 따라 열은 다르게
|
||||
들어갑니다. 그래서 무월은 색이 아니라 1차 팝핑 후 감률과 커핑 점수로
|
||||
로트를 기록합니다.
|
||||
</p>
|
||||
<p class="muted">
|
||||
좌표는 로트마다 다시 측정해 옮겨 적습니다. 지난 로트의 좌표와 지금이
|
||||
같다고 말하지 않습니다.
|
||||
</p>
|
||||
<ul class="scale-legend" aria-label="좌표 범례">
|
||||
<li><span class="key" aria-hidden="true"></span>우라가 G1 워시드</li>
|
||||
<li><span class="key key-b" aria-hidden="true"></span>엘 파라이소 혐기발효</li>
|
||||
<li><span class="key key-c" aria-hidden="true"></span>엘 소코로 마라카투라</li>
|
||||
</ul>
|
||||
</div>
|
||||
<figure class="scale-plot reveal">
|
||||
<svg
|
||||
viewBox="0 0 520 340"
|
||||
role="img"
|
||||
aria-label="산미-바디 2차원 좌표. 우라가는 산미 높음, 엘 파라이소는 단맛 높음, 엘 소코로는 바디 높음."
|
||||
>
|
||||
<!-- 눈금 격자 -->
|
||||
<g class="grid">
|
||||
<line x1="56" y1="40" x2="56" y2="280" />
|
||||
<line x1="56" y1="280" x2="500" y2="280" />
|
||||
<line x1="56" y1="160" x2="500" y2="160" />
|
||||
<line x1="278" y1="40" x2="278" y2="280" />
|
||||
<line x1="167" y1="40" x2="167" y2="280" stroke-dasharray="2 6" />
|
||||
<line x1="389" y1="40" x2="389" y2="280" stroke-dasharray="2 6" />
|
||||
<line x1="56" y1="100" x2="500" y2="100" stroke-dasharray="2 6" />
|
||||
<line x1="56" y1="220" x2="500" y2="220" stroke-dasharray="2 6" />
|
||||
</g>
|
||||
<!-- 축 이름 -->
|
||||
<g class="axis-labels">
|
||||
<text x="56" y="302">산미 →</text>
|
||||
<text x="500" y="302" text-anchor="end">바디 →</text>
|
||||
<text x="46" y="46" text-anchor="end">10.0</text>
|
||||
<text x="46" y="286" text-anchor="end">0</text>
|
||||
</g>
|
||||
<!-- 로트 점 -->
|
||||
<g class="points">
|
||||
<circle cx="140" cy="62" r="5" />
|
||||
<text x="140" y="46" text-anchor="middle">우라가 8.8</text>
|
||||
<circle cx="252" cy="92" r="5" class="pt-b" />
|
||||
<text x="252" y="76" text-anchor="middle">엘 파라이소 9.0</text>
|
||||
<circle cx="430" cy="196" r="5" class="pt-c" />
|
||||
<text x="430" y="180" text-anchor="middle">엘 소코로 8.6</text>
|
||||
</g>
|
||||
</svg>
|
||||
<figcaption>8월 3주차 로트 실측 · 좌표는 주마다 다시 놓입니다</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!--
|
||||
원장 — 이 페이지의 신뢰 장치 (R1: 거래 내역 공개가 이 업종의 스펙).
|
||||
밴드를 살짝 눌러 표가 페이지의 중심임을 알린다.
|
||||
-->
|
||||
<section id="ledger" class="section band" aria-labelledby="ledger-h">
|
||||
<div class="wrap">
|
||||
<div class="ledger-head">
|
||||
<h2 id="ledger-h">생두 매입 원장</h2>
|
||||
<p class="muted">
|
||||
농장에 돌아가는 돈이 얼마인지 보여주는 일이 스페셜티의 조건이라
|
||||
생각합니다. 1kg당 매입가와 가공 방식까지 로트 단위로 남깁니다.
|
||||
</p>
|
||||
</div>
|
||||
<div class="table-wrap reveal">
|
||||
<table>
|
||||
<caption class="sr-only">
|
||||
원두별 생두 매입 원장 — 원두명, 생산자, 가공 방식, 매입가, 커핑 점수
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">원두</th>
|
||||
<th scope="col">생산자</th>
|
||||
<th scope="col">가공</th>
|
||||
<th scope="col" class="num">매입가 (FOB/kg)</th>
|
||||
<th scope="col" class="num">커핑</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">에티오피아 구지 우라가</th>
|
||||
<td>하르소 콜루 세척장</td>
|
||||
<td>워시드 · 72시간 발효</td>
|
||||
<td class="num">$14.20</td>
|
||||
<td class="num">88.75</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">콜롬비아 엘 파라이소</th>
|
||||
<td>디에고 사무엘 베르무데스</td>
|
||||
<td>혐기발효 · 열충격 2회</td>
|
||||
<td class="num">$26.50</td>
|
||||
<td class="num">91.20</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">과테말라 엘 소코로</th>
|
||||
<td>후안 디에고 데 라 세르다</td>
|
||||
<td>전량 워시드</td>
|
||||
<td class="num">$16.80</td>
|
||||
<td class="num">89.00</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="ledger-note muted">
|
||||
운임·통관·관세는 포함하지 않은 현지 출하가이며, 환율은 매입일 기준입니다.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!--
|
||||
레시피 — 사진과 사양. 사양은 목록의 주인공이 아니라 사진의 각주다.
|
||||
-->
|
||||
<section id="recipe" class="section" aria-labelledby="recipe-h">
|
||||
<div class="wrap recipe-grid">
|
||||
<figure class="recipe-photo reveal">
|
||||
<img
|
||||
src="./assets/pourover.webp"
|
||||
alt="고핫물이 필터 백에 담긴 도자기 드리퍼로 얇은 물줄기로 들어가는 중"
|
||||
width="900"
|
||||
height="1200"
|
||||
loading="lazy"
|
||||
/>
|
||||
<figcaption>서촌 매장 · 오후 첫 잔</figcaption>
|
||||
</figure>
|
||||
<div class="recipe-text">
|
||||
<h2 id="recipe-h">원두 18g, 물 288g</h2>
|
||||
<p>
|
||||
구독 패키지에는 원두 밀도에 맞춘 분쇄도와 주수 간격을 적은 카드 한 장이
|
||||
들어갑니다. 드립의 변주는 그 다음 문제입니다.
|
||||
</p>
|
||||
<dl class="spec">
|
||||
<div>
|
||||
<dt>물 온도</dt>
|
||||
<dd>93°C</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>분쇄도</dt>
|
||||
<dd>코만단테 24딸</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>뜸 들이기</dt>
|
||||
<dd>40초 · 물 40g</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>주수</dt>
|
||||
<dd>3회 · 116g씩</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<p class="muted">
|
||||
추출 시간은 2분 30초에서 3분 사이가 기준입니다. 그보다 빨리 흘러내리면
|
||||
곱게 갈고, 늦으면 굵게 갑니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!--
|
||||
구독 — 회색조에서 가장 어두운 블록. 이 페이지의 유일한 강한 면.
|
||||
(1단계 회색조 위계 계획의 실행: CTA가 1위 덩어리)
|
||||
-->
|
||||
<section id="plan" class="section plan" aria-labelledby="plan-h">
|
||||
<div class="wrap plan-grid">
|
||||
<div class="plan-text">
|
||||
<h2 id="plan-h">격주, 서로 다른 좌표의<br />원두 두 종</h2>
|
||||
<p>
|
||||
2주마다 화요일 아침, 산미형 한 종과 밸런스형 한 종(각 100g)을 볶어
|
||||
보냅니다. 원두는 시음 후 남는 양이 없어 다음 주에 같은 로트를 못 드릴 수
|
||||
있습니다.
|
||||
</p>
|
||||
<ul class="plan-list">
|
||||
<li>원두별 추출 카드 동봉 — 분쇄도·온도·주수</li>
|
||||
<li>아로마 밸브 틴케이스 첫 회 증정</li>
|
||||
<li>출장·휴가 주는 앱에서 건너뛰기</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="plan-box">
|
||||
<p class="plan-price">
|
||||
<span>28,000원</span><span class="plan-unit">회당 · 배송비 포함</span>
|
||||
</p>
|
||||
<a class="btn btn-inverse" href="#plan">격주 구독 시작하기</a>
|
||||
<p class="plan-note">200g(100g×2) · 첫 회는 다음 화요일에 출고됩니다</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="site-foot">
|
||||
<div class="wrap foot-inner">
|
||||
<p>무월 로스터리 · 서울 종로구 옥인길 18</p>
|
||||
<p class="muted">화요일 로스팅 · 목요일부터 토요일까지 문을 엽니다</p>
|
||||
<p class="muted">roastery@muwol.kr</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
/* 목요일의 화원과 같은 문법 — 한 번 보이면 유지, 스크롤 이벤트 없음 */
|
||||
const io = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const e of entries) {
|
||||
if (!e.isIntersecting) continue;
|
||||
e.target.classList.add("is-in");
|
||||
io.unobserve(e.target);
|
||||
}
|
||||
},
|
||||
{ rootMargin: "0px 0px -8% 0px", threshold: 0.05 },
|
||||
);
|
||||
for (const el of document.querySelectorAll(".reveal")) io.observe(el);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
560
apps/site/public/work/muwol-coffee/styles/main.css
Normal file
560
apps/site/public/work/muwol-coffee/styles/main.css
Normal file
|
|
@ -0,0 +1,560 @@
|
|||
@import url("./tokens.css");
|
||||
|
||||
/* ==========================================================================
|
||||
무월 — quiet-commerce. 종이 원장의 문법.
|
||||
레이아웃 → 재질 → 모션 순서로 읽힌다.
|
||||
========================================================================== */
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
scroll-behavior: smooth;
|
||||
background: var(--surface);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--step-0);
|
||||
line-height: var(--leading-normal);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
:where(h1, h2) {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 500;
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: -0.01em;
|
||||
word-break: keep-all;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
:where(p, li, dd, dt, th, td, figcaption) {
|
||||
word-break: keep-all;
|
||||
overflow-wrap: break-word;
|
||||
line-height: 1.75;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: var(--step-3);
|
||||
}
|
||||
h2 {
|
||||
font-size: var(--step-2);
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
.skip {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
top: 0;
|
||||
background: var(--ink);
|
||||
color: var(--surface);
|
||||
padding: var(--space-3) var(--space-4);
|
||||
z-index: 100;
|
||||
}
|
||||
.skip:focus {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
clip: rect(0 0 0 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
width: min(100% - 2 * var(--pad-inline), var(--container));
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* ── 헤더 ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
.site-head {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
background: color-mix(in srgb, var(--surface) 88%, transparent);
|
||||
backdrop-filter: blur(8px);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.head-inner {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-4);
|
||||
padding-block: var(--space-3);
|
||||
}
|
||||
|
||||
.wordmark {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--step-1);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
text-decoration: none;
|
||||
}
|
||||
.wordmark-han {
|
||||
color: var(--ink-muted);
|
||||
font-size: var(--step-0);
|
||||
margin-left: var(--space-1);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
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 {
|
||||
padding-block: var(--space-7);
|
||||
}
|
||||
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
|
||||
gap: var(--space-7) var(--space-6);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.hero-label {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
letter-spacing: 0.04em;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.lead {
|
||||
max-width: 34em;
|
||||
}
|
||||
|
||||
.hero-text .lead {
|
||||
margin-top: var(--space-4);
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
margin-top: var(--space-5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.hero-note {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-faint);
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background: var(--accent);
|
||||
color: var(--accent-ink);
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: var(--radius);
|
||||
transition: background var(--dur-quick) var(--ease-soft);
|
||||
}
|
||||
.btn:hover {
|
||||
background: var(--accent-hover);
|
||||
}
|
||||
.btn-inverse {
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
}
|
||||
.btn-inverse:hover {
|
||||
background: var(--surface-bright);
|
||||
}
|
||||
|
||||
.hero-photo img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.hero-photo figcaption,
|
||||
.recipe-photo figcaption,
|
||||
.scale-plot figcaption {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-faint);
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
|
||||
/* 이번 주 원두 — 원장의 첫 두 줄 (카드 아님) */
|
||||
.hero-beans {
|
||||
margin-top: var(--space-6);
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
.bean-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
gap: var(--space-4);
|
||||
padding-block: var(--space-3);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.bean-row dt {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 500;
|
||||
font-size: var(--step-1);
|
||||
}
|
||||
.bean-origin {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
margin-top: 2px;
|
||||
}
|
||||
.bean-price {
|
||||
font-family: var(--font-mono);
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.bean-price span {
|
||||
color: var(--ink-faint);
|
||||
margin-right: var(--space-2);
|
||||
font-size: var(--step--1);
|
||||
}
|
||||
|
||||
/* ── 섹션 공통 ────────────────────────────────────────────────────────── */
|
||||
|
||||
.section {
|
||||
padding-block: var(--space-8);
|
||||
}
|
||||
.band {
|
||||
background: var(--surface-raised);
|
||||
border-block: 1px solid var(--line);
|
||||
}
|
||||
|
||||
/* ── 척도(좌표 플롯) ──────────────────────────────────────────────────── */
|
||||
|
||||
.scale-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
|
||||
gap: var(--space-6) var(--space-7);
|
||||
align-items: center;
|
||||
}
|
||||
.scale-text p + p {
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
.scale-legend {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: var(--space-4);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2) var(--space-4);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
.key {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--ink);
|
||||
margin-right: var(--space-1);
|
||||
vertical-align: baseline;
|
||||
}
|
||||
.key-b {
|
||||
background: var(--accent);
|
||||
}
|
||||
.key-c {
|
||||
background: var(--ink-faint);
|
||||
}
|
||||
|
||||
.scale-plot svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.scale-plot .grid line {
|
||||
stroke: var(--line);
|
||||
stroke-width: 1;
|
||||
}
|
||||
.scale-plot .grid line:first-child,
|
||||
.scale-plot .grid line:nth-child(2) {
|
||||
stroke: var(--ink-faint);
|
||||
stroke-width: 1.25;
|
||||
}
|
||||
.axis-labels text {
|
||||
font-family: var(--font-body);
|
||||
font-size: 13px;
|
||||
fill: var(--ink-faint);
|
||||
}
|
||||
.points circle {
|
||||
fill: var(--ink);
|
||||
}
|
||||
.points .pt-b {
|
||||
fill: var(--accent);
|
||||
}
|
||||
.points .pt-c {
|
||||
fill: var(--ink-faint);
|
||||
}
|
||||
.points text {
|
||||
font-family: var(--font-body);
|
||||
font-size: 13px;
|
||||
fill: var(--ink-muted);
|
||||
}
|
||||
|
||||
/* ── 원장(밴드) ───────────────────────────────────────────────────────── */
|
||||
|
||||
.ledger-head {
|
||||
max-width: 38em;
|
||||
margin-bottom: var(--space-5);
|
||||
}
|
||||
.ledger-head p {
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
|
||||
.table-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: var(--step-0);
|
||||
}
|
||||
thead th {
|
||||
text-align: left;
|
||||
font-weight: 500;
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border-bottom: 1px solid var(--ink-faint);
|
||||
}
|
||||
tbody th {
|
||||
text-align: left;
|
||||
font-weight: 500;
|
||||
}
|
||||
tbody td,
|
||||
tbody th {
|
||||
padding: var(--space-3);
|
||||
border-bottom: 1px solid var(--line);
|
||||
vertical-align: baseline;
|
||||
}
|
||||
.num {
|
||||
font-family: var(--font-mono);
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ledger-note {
|
||||
margin-top: var(--space-3);
|
||||
font-size: var(--step--1);
|
||||
}
|
||||
|
||||
/* ── 레시피 ───────────────────────────────────────────────────────────── */
|
||||
|
||||
.recipe-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
|
||||
gap: var(--space-6) var(--space-7);
|
||||
align-items: center;
|
||||
}
|
||||
.recipe-photo img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
.recipe-text p + p {
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
.spec {
|
||||
margin-top: var(--space-4);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
||||
gap: var(--space-3) var(--space-5);
|
||||
}
|
||||
.spec dt {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-faint);
|
||||
}
|
||||
.spec dd {
|
||||
font-family: var(--font-mono);
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-size: var(--step-1);
|
||||
margin-top: var(--space-1);
|
||||
}
|
||||
|
||||
/* ── 구독(반전 블록) ──────────────────────────────────────────────────── */
|
||||
|
||||
.plan {
|
||||
background: var(--surface-inverse);
|
||||
color: var(--ink-inverse);
|
||||
}
|
||||
.plan-note {
|
||||
color: var(--ink-inverse-muted);
|
||||
}
|
||||
.plan-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
|
||||
gap: var(--space-6) var(--space-7);
|
||||
align-items: center;
|
||||
}
|
||||
.plan-text p {
|
||||
margin-top: var(--space-4);
|
||||
max-width: 34em;
|
||||
}
|
||||
.plan-list {
|
||||
margin-top: var(--space-4);
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.plan-list li {
|
||||
padding-left: 1.25em;
|
||||
position: relative;
|
||||
color: var(--ink-inverse-muted);
|
||||
}
|
||||
.plan-list li::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0.72em;
|
||||
width: 6px;
|
||||
height: 1.5px;
|
||||
background: var(--ink-inverse-muted);
|
||||
}
|
||||
.plan-list li + li {
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
.plan-box {
|
||||
border: 1px solid var(--line-inverse);
|
||||
border-radius: var(--radius);
|
||||
padding: var(--space-5);
|
||||
display: grid;
|
||||
gap: var(--space-4);
|
||||
justify-items: start;
|
||||
}
|
||||
.plan-price span:first-child {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--step-2);
|
||||
font-weight: 600;
|
||||
}
|
||||
.plan-unit {
|
||||
display: block;
|
||||
font-size: var(--step--1);
|
||||
margin-top: var(--space-1);
|
||||
color: var(--ink-inverse-muted);
|
||||
}
|
||||
/* ── 푸터 ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
.site-foot {
|
||||
border-top: 1px solid var(--line);
|
||||
padding-block: var(--space-6);
|
||||
font-size: var(--step--1);
|
||||
}
|
||||
.foot-inner {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2) var(--space-5);
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* ── 등장 모션 — IO 1회, 유지 ─────────────────────────────────────────── */
|
||||
|
||||
.reveal {
|
||||
opacity: 0;
|
||||
translate: 0 12px;
|
||||
transition: opacity var(--dur-normal) var(--ease-soft),
|
||||
translate var(--dur-normal) var(--ease-soft);
|
||||
transition-delay: var(--delay, 0ms);
|
||||
}
|
||||
.reveal.is-in {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.reveal {
|
||||
opacity: 1;
|
||||
translate: 0 0;
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 반응형 ───────────────────────────────────────────────────────────── */
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.hero-grid,
|
||||
.scale-grid,
|
||||
.recipe-grid,
|
||||
.plan-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
.hero-photo,
|
||||
.recipe-photo {
|
||||
max-width: 26rem;
|
||||
}
|
||||
.hero {
|
||||
padding-block: var(--space-6);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
.head-inner {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
.nav {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.bean-row {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
.plan-box {
|
||||
padding: var(--space-4);
|
||||
}
|
||||
}
|
||||
67
apps/site/public/work/muwol-coffee/styles/tokens.css
Normal file
67
apps/site/public/work/muwol-coffee/styles/tokens.css
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* ==========================================================================
|
||||
무월 (霧月 · MUWOL) — 디자인 토큰
|
||||
프리셋: quiet-commerce
|
||||
컨셉 한 문장: 종이 원장처럼 정직한 구독 — 화면에는 사양과 실측만.
|
||||
레퍼런스: R1 coffeecollective.dk(구조·가격 노출·거래 투명성)
|
||||
R2 fitzcarraldoeditions.com(세리프 본문 정돈, 1강조색)
|
||||
R3 scroll-driven view() — 채택 안 함(IO 등장만 씀. 정적 HTML + 폴백 우선)
|
||||
하지 않은 것: 세로 GNB 레일, 영어 대문자 eyebrow, 전면 그레인 오버레이,
|
||||
FIG.00 캡션 문법, 카드 그림자. 이유: 계기판 흉내가 상품을 가림.
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
/* 타입 스케일 — 최대(64px) ÷ 본문(16px) = 4.0배 */
|
||||
--step--1: 0.8125rem; /* 13px — 캡션·주석 */
|
||||
--step-0: 1rem; /* 16px — 본문 */
|
||||
--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, 4rem); /* 64px — 디스플레이 */
|
||||
|
||||
--leading-tight: 1.28;
|
||||
--leading-normal: 1.75;
|
||||
--measure: 34ch;
|
||||
|
||||
--font-display: "MaruBuri", serif;
|
||||
--font-serif: "MaruBuri", serif;
|
||||
--font-body: "Pretendard Variable", Pretendard, -apple-system, sans-serif;
|
||||
--font-mono: "JetBrains Mono", monospace;
|
||||
|
||||
/* 색 — hue 2개: 안개 종이 + 볶은 원두 앰버. 강조색은 앰버 하나. */
|
||||
--surface: #f4f4f0;
|
||||
--surface-raised: #eaeae4;
|
||||
--surface-inverse: #181b18;
|
||||
--ink: #181b18;
|
||||
--ink-muted: #585c56;
|
||||
--ink-faint: #8c908a;
|
||||
--ink-inverse: #f4f4f0;
|
||||
--ink-inverse-muted: #a8aca4;
|
||||
|
||||
--line: #d5d7d0;
|
||||
--line-inverse: #3a3e39;
|
||||
|
||||
--accent: #7a3e1d;
|
||||
--accent-hover: #5c2d13;
|
||||
--surface-bright: #fffffa; /* 반전 블록 안 밝은 hover 단계 */
|
||||
--accent-ink: #f4f4f0;
|
||||
|
||||
/* 대비(실측 예정 — 5단계에서 재검): ink/surface 15.6, muted/surface 6.2,
|
||||
accent/surface 7.5, inverse 조합은 본문 AA 이상으로 설계 */
|
||||
|
||||
--space-1: 0.25rem;
|
||||
--space-2: 0.5rem;
|
||||
--space-3: 1rem;
|
||||
--space-4: 1.5rem;
|
||||
--space-5: 2.5rem;
|
||||
--space-6: 4rem;
|
||||
--space-7: 6rem;
|
||||
--space-8: clamp(4.5rem, 3rem + 6vw, 9rem);
|
||||
|
||||
--radius: 2px;
|
||||
|
||||
--container: 1120px;
|
||||
--pad-inline: clamp(1.25rem, 1rem + 2.5vw, 4rem);
|
||||
|
||||
--dur-quick: 180ms;
|
||||
--dur-normal: 420ms;
|
||||
--ease-soft: cubic-bezier(0.25, 1, 0.35, 1);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue