@import url("./tokens.css?v=20261006"); /* ========================================================================== 향연 — 회보라 바탕 위의 향 한 자루. 토큰은 tokens.css 한 곳에만 있다. ========================================================================== */ *, *::before, *::after { box-sizing: border-box; } * { margin: 0; } html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; background: var(--surface); font-synthesis-style: none; } @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; 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: 400; line-height: var(--leading-tight); 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, figcaption) { line-height: var(--leading-normal); text-wrap: pretty; } .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; overflow: hidden; 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). 고정하지 않고 흐리지 않는다. ── */ .brand-bar { position: relative; z-index: 2; } .bar-inner { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); padding-block: var(--space-4); } .wordmark { font-family: var(--font-display); font-weight: 400; font-size: var(--step-1); line-height: 1.2; white-space: nowrap; } .action { display: inline-flex; align-items: center; min-height: 44px; 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); } .action:hover { color: var(--accent-deep); text-decoration-thickness: 2px; } /* ── 히어로 — 제품 단독. 돌 받침 위 향 한 자루가 가운데, 글은 아래 한 줄과 사실 셋. ── */ .hero { min-block-size: calc(100svh - 5.5rem); display: grid; } .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); } .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: var(--space-4); } .section p, .section dd { max-width: var(--measure); } /* ── 침향이란 — 절편 누끼 + 글 ── */ .two { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--space-6) var(--space-7); align-items: center; } .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; filter: saturate(0.7) brightness(1.17) contrast(1.06); } .slab figcaption { font-size: var(--step--1); color: var(--ink-muted); margin-top: var(--space-2); text-align: center; } .two-text p + p { margin-top: var(--space-4); } .two-text h2 { margin-bottom: var(--space-4); } /* ── 기록과 가격 ── */ .record-head { max-width: var(--measure); margin-bottom: var(--space-5); } .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%; border-collapse: collapse; } thead th { text-align: left; 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-muted); } tbody th { font-family: var(--font-display); 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; } .is-aging { color: var(--accent-deep); } .collection-h { margin-top: var(--space-7); } .collection { list-style: none; margin-top: var(--space-4); padding: 0; border-top: 1px solid var(--line); } .item { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: var(--space-4); padding-block: var(--space-4); border-bottom: 1px solid var(--line); } .item-name { font-family: var(--font-display); font-size: var(--step-1); line-height: 1.3; } .item-text p + p { font-size: var(--step--1); color: var(--ink-muted); margin-top: var(--space-1); } .item-price { font-family: var(--font-display); font-size: var(--step-1); font-variant-numeric: tabular-nums; white-space: nowrap; } /* ── 시향 방문 — 페이지의 행동 하나가 끝나는 곳 ── */ .visit-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-5) var(--space-7); align-items: start; } .visit-grid > * { min-width: 0; } .visit-info { display: grid; gap: var(--space-3); } .visit-info dt { font-size: var(--step--1); color: var(--ink-muted); } .visit-info dd { margin-top: 2px; } /* ── 푸터 — 큰 워드마크 한 줄(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); 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); color: var(--ink-muted); } .foot-line span:last-child { max-width: var(--measure); } /* ── 반응형 ── */ @media (max-width: 900px) { .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); } .slab { max-width: 28rem; } } @media (max-width: 560px) { .hero { min-block-size: calc(100svh - 5rem); } .stage { min-block-size: 15rem; } .product { width: min(100%, 18rem); } .item { grid-template-columns: 1fr; gap: var(--space-1); } .table-wrap { padding-inline: var(--space-2); } thead th, tbody td, tbody th { padding-inline: var(--space-2); } }