release: v0.9.1 (신규 쇼케이스 3종 정식 출시, CSS 변수 및 경로 무결성 게이트 강화)
2
.gitignore
vendored
|
|
@ -11,3 +11,5 @@ apps/site/dist/
|
|||
research/youtube/*.srt
|
||||
research/youtube/*.vtt
|
||||
apps/site/tools/.gen/
|
||||
.gemini/
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
| 날짜 | 판 | 무엇이 바뀌었나 |
|
||||
|---|---|---|
|
||||
| 2026-08-20 | 초판 | `swiss-minimal` · three.js 미사용 · 라이트 기반 |
|
||||
| 2026-08-20 | **2판(현행)** | `dark-instrument` · three.js 채택 · 전체 경로 재주행 |
|
||||
| 2026-08-20 | 2판 | `dark-instrument` · three.js 채택 · 전체 경로 재주행 |
|
||||
| 2026-08-23 | **현행** | 쇼케이스 히어로 리뉴얼 — Three.js 추상 FBM 셰이더 캔버스(`ShowcaseHeroCanvas`), 한국어 에디토리얼 카피 개편, 15개 라이브 쇼케이스 및 디테일 페이지 서브링크 연동 |
|
||||
|
||||
**초판이 거짓말이 됐던 경위를 남긴다.** 사용자가 "글래스모피즘·리퀴드글래스·히어로에 힘"을 요청했을 때
|
||||
그것은 2단계 방향 재결정이었고, 스킬은 그럴 때 **전체 경로로 올려 1단계부터 다시 돌라**고 씌어 있다.
|
||||
|
|
@ -849,3 +850,44 @@ v23 스크롤 리셋·단일 헤더에도 사용자 평가가 "여전히 깨져
|
|||
- **게이트 공백 발견**: 기존 매트릭스는 오른쪽 '오버플로'만 검사하고 왼쪽 인셋의 최소값·정렬 정합은 검사하지 않았다(그래서 기준 갱신에 결함이 그대로 박혔다). e2e에 **M6 왼쪽 인셋** 스위트 신설(60단언): 전 뷰×320/390에서 텍스트 시작점 ≥12px + 헤더-제목 같은 축(±10px). RED 38 실패로 결함 재현 확인 후 수리로 GREEN.
|
||||
- 측정 하자(瑕) 2건 교정: display:none 요소의 rect=0이 잡히던 것(vis 필터), 전폭 컨테이너 보더박스가 아닌 '텍스트 시작점' 기준.
|
||||
- 시각 기준 갱신(두레 390px 6화면), verify L0~L6 전 통과(E2E 1,805단언).
|
||||
|
||||
## 2026-08-23 — 신규 쇼케이스 3종 구축 (청온 케어 · 캐스크 아카이브 · 마테리아 스튜디오)
|
||||
|
||||
`designpaca`, `design-taste-frontend`, `high-end-visual-design` 원칙을 적용하여 신규 쇼케이스 사이트 3종 제작 및 쇼케이스 아카이브에 등록:
|
||||
|
||||
1. **청온 케어 (`cheongon-care`)**
|
||||
- **프리셋**: `ledger-console` + `swiss-minimal`
|
||||
- **강조색**: 에메랄드 틸 (`#0D9488`)
|
||||
- **컨셉**: 임상 수준의 6단계 위생 프로토콜과 투명한 정찰제 견적, 실시간 고객 신청-관리자 관제 대시보드 풀-루프 연동 및 32개 QC 체크리스트 모달.
|
||||
2. **캐스크 아카이브 (`cask-archive`)**
|
||||
- **프리셋**: `editorial-archival` + `dark-instrument`
|
||||
- **강조색**: 싱글 몰트 앰버 골드 (`#D99B38`)
|
||||
- **컨셉**: Gordon & MacPhail, Signatory, SMWS 독립병입자 공식 수입 인증 보증서, 캐스크 넘버 원장 실시간 검색, 1:1 도슨트 테이스팅 예약 및 이벤트/인스타그램 연동.
|
||||
3. **마테리아 스튜디오 (`materia-interior`)**
|
||||
- **프리셋**: `editorial` + `high-end-visual-design`
|
||||
- **강조색**: 브러시드 티타늄 브론즈 (`#9E8062`)
|
||||
- **컨셉**: 트래버틴과 훈증 오크의 물성, 자연광 Day ↔ 야간 조도 Night 앰비언스 실시간 전환, 더블 베젤 프로젝트 갤러리 및 프라이빗 공간 컨설팅 신청.
|
||||
|
||||
- **검증**: Astro 빌드 완료, Stylelint 통과, HTML-Validate 통과, 전 계층 QA 게이트(L0~L6) 100% 통과.
|
||||
|
||||
## 2026-08-23 — 국소: 쇼케이스 상세 모달 및 카드 방문 액션 전면 재설계
|
||||
|
||||
사용자 피드백: "showcase 페이지의 상세 모달 팝업에 스크롤을 해야지 사이트 보기 버튼이 있어서 사람들이 사이트 들어가질 않는 문제" 및 "왼쪽 섬네일이 그냥 cover 형태로 꽉 차는 게 이쁘겠다".
|
||||
|
||||
- **문제 진단**:
|
||||
- 기존 단일 열 모달 레이아웃에서 거대한 스크린샷과 설명/리스크/지표 박스 아래에 `.dialog-site` 링크가 묻혀 있어, 사용자가 모달을 열고 스크롤하지 않으면 사이트 진입 버튼의 존재를 알기 어려웠음.
|
||||
- **해결책 (2-Tier & Split Full-bleed Architecture)**:
|
||||
- **데스크톱 (≥860px)**:
|
||||
- 좌/우 2열 분할 스플릿 그리드(`dialog-layout`).
|
||||
- 좌측(`dialog-media`): 100% 풀블리드 `object-fit: cover` 스크린샷 뷰어 패널(여백·내부 테두리 제거로 미려하고 꽉 찬 인상).
|
||||
- 우측(`dialog-details`): 상단 헤더 바로 아래에 눈에 띄는 고대비 주 CTA 블록(`dialog-cta-block` + `.dialog-site-btn`)을 배치하여 **0px 스크롤(첫 시야)에서 100% 즉시 노출**.
|
||||
- **모바일 (<860px)**:
|
||||
- 상단 풀블리드 섬네일 커버 + 헤더 직하단 CTA 블록.
|
||||
- 하단 고정 스티키 액션 독(`dialog-sticky-dock` + `.dialog-dock-btn`)을 적용하여 스크롤 중에도 엄지 영역에 상시 '사이트 보기' 버튼 고정.
|
||||
- **카드 그리드 즉시 진입**:
|
||||
- 카드 썸네일 호버 시 우측 하단에 `.card-quick-visit` 알약 버튼 노출.
|
||||
- 타이틀 행에 `.card-direct-link` 아이콘 버튼을 배치하여 모달을 열지 않고도 바로 새 탭에서 데모를 체험할 수 있도록 다이렉트 액션 강화(`z-index: 4`).
|
||||
- **글로벌 리셋 보강**:
|
||||
- `base.css`에 글로벌 미디어 리셋(`img, picture, video, canvas, svg { max-width: 100%; display: block; }`) 및 `html { overflow-x: hidden; }` 안전장치 추가.
|
||||
- **자동화 검증**:
|
||||
- `tools/test-showcase-dialog.mjs` (1440px / 768px / 390px / 320px 4개 뷰포트 E2E): 데스크톱 0px 스크롤 CTA 노출 확인, 좌측 cover 핏 실측, 모바일 스티키 독 활성화 확인, 모달 닫기/Esc/배경 클릭/카드 액션 등 17개 단언 100% PASS.
|
||||
|
|
|
|||
BIN
apps/site/public/work/cask-archive/assets/aroma-wheel.webp
Normal file
|
After Width: | Height: | Size: 201 KiB |
BIN
apps/site/public/work/cask-archive/assets/cellar.webp
Normal file
|
After Width: | Height: | Size: 153 KiB |
BIN
apps/site/public/work/cask-archive/assets/docent-room.webp
Normal file
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 170 KiB |
BIN
apps/site/public/work/cask-archive/assets/whisky-hero.webp
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
apps/site/public/work/cask-archive/assets/whisky-pairing.webp
Normal file
|
After Width: | Height: | Size: 126 KiB |
459
apps/site/public/work/cask-archive/docent/index.html
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>1:1 위스키 도슨트 테이스팅 마스터클래스 — CASK ARCHIVE (樽室)</title>
|
||||
<meta name="description" content="캐스크 아카이브의 1:1 위스키 도슨트 테이스팅 마스터클래스 안내. 코피타 글래스웨어학, 감각 아로마 휠 분석, 독립병입자 싱글 캐스크 플라이트 및 가스트로노미 페어링." />
|
||||
|
||||
<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;700&display=swap"
|
||||
/>
|
||||
<link rel="stylesheet" href="../styles/tokens.css" />
|
||||
<link rel="stylesheet" href="../styles/main.css" />
|
||||
<style>
|
||||
.breadcrumb-bar {
|
||||
padding-top: var(--space-4);
|
||||
padding-bottom: var(--space-3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.breadcrumb-bar a {
|
||||
color: var(--ink-muted);
|
||||
text-decoration: none;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
.breadcrumb-bar a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
.breadcrumb-bar .sep {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.breadcrumb-bar .current {
|
||||
color: var(--ink);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.docent-hero {
|
||||
padding: var(--space-7) 0 var(--space-5);
|
||||
}
|
||||
.docent-meta-strip {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: var(--space-3);
|
||||
margin-top: var(--space-5);
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-4);
|
||||
}
|
||||
.docent-meta-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.docent-meta-item .label {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.docent-meta-item .value {
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.course-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||
gap: var(--space-5);
|
||||
margin-top: var(--space-5);
|
||||
}
|
||||
.course-deep-card {
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-5);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-4);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.course-deep-card.highlight {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 32px rgba(217, 155, 56, 0.12);
|
||||
}
|
||||
.course-deep-card.highlight::before {
|
||||
content: 'RECOMMENDED';
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
right: -32px;
|
||||
transform: rotate(45deg);
|
||||
background: var(--accent);
|
||||
color: #000;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
padding: 4px 36px;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.lineup-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: var(--step--1);
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
.lineup-table th, .lineup-table td {
|
||||
padding: 10px 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.lineup-table th {
|
||||
color: var(--ink-muted);
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Header (GNB SSOT) -->
|
||||
<header class="site-head">
|
||||
<div class="wrap head-inner">
|
||||
<a href="../index.html" class="wordmark" aria-label="캐스크 아카이브 홈">
|
||||
<span class="wordmark-han" style="font-size: var(--step-0); color: var(--accent);">樽</span>
|
||||
캐스크 아카이브 <span class="wordmark-han">CASK ARCHIVE</span>
|
||||
</a>
|
||||
<nav class="nav" aria-label="메인 내비게이션">
|
||||
<a href="./index.html" class="active" style="color: var(--accent); font-weight: 600;">도슨트 마스터클래스</a>
|
||||
<a href="../index.html#ledger">캐스크 원장</a>
|
||||
<a href="../index.html#curator">향미 큐레이션</a>
|
||||
<a href="../index.html#events">릴리즈</a>
|
||||
<a href="../index.html#subscribe">뉴스레터</a>
|
||||
</nav>
|
||||
<div class="head-actions">
|
||||
<a href="#reservation-section" class="btn">도슨트 예약</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="main-content">
|
||||
<!-- Hero Header -->
|
||||
<section class="section docent-hero" style="border-top: none; padding-top: var(--space-5);">
|
||||
<div class="wrap">
|
||||
<div class="breadcrumb-bar" style="margin-bottom: var(--space-4); display: flex; align-items: center; gap: var(--space-2); font-family: var(--font-mono); font-size: 12px; color: var(--ink-muted); letter-spacing: 0.04em;">
|
||||
<a href="../index.html">CASK ARCHIVE</a>
|
||||
<span class="sep">/</span>
|
||||
<span class="current" style="color: var(--ink); font-weight: 600;">1:1 WHISKY DOCENT MASTERCLASS</span>
|
||||
</div>
|
||||
|
||||
<div class="docent-hero-head">
|
||||
<p class="hero-label">BESPOKE TASTING METHODOLOGY</p>
|
||||
<h1 class="hero-title" style="margin-bottom: var(--space-2);">1:1 위스키 도슨트 마스터클래스</h1>
|
||||
<p class="hero-lead" style="font-size: var(--step-0); color: var(--ink-muted); max-width: var(--measure); margin-bottom: var(--space-5);">
|
||||
공인 위스키 마스터가 1:1로 당신의 후각과 미각 취향을 해체하고 조립하는 프라이빗 테이스팅 세션.
|
||||
</p>
|
||||
|
||||
<dl class="docent-specs" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-4); background: var(--surface-card); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-4) var(--space-5); margin-bottom: var(--space-6);">
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">Session Type</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">1:1 Private Tasting</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">Location</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">Cask Room (한남 27길)</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">Capacity</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">최대 2인 (동반 1인 가능)</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">Glassware</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">Glencairn & Copita</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<figure class="hero-photo" style="border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--surface-card);">
|
||||
<img
|
||||
src="../assets/docent-room.webp"
|
||||
alt="어두운 오크 바 카운터에 세팅된 코피타 테이스팅 글래스와 도슨트 노트"
|
||||
width="1600"
|
||||
height="900"
|
||||
style="width: 100%; aspect-ratio: 16/9; object-fit: cover;"
|
||||
/>
|
||||
<figcaption style="padding: 10px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--ink-muted); border-top: 1px solid var(--line); background: var(--surface-raised);">
|
||||
한남동 캐스크 룸 · 마스터 전용 1:1 테이스팅 카운터
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Sensory Wheel & Flavor Science -->
|
||||
<section class="wrap" style="padding-bottom: var(--space-8);">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--space-8); align-items: center;">
|
||||
<div class="frame">
|
||||
<img
|
||||
src="../assets/aroma-wheel.webp"
|
||||
alt="위스키 감각 테이스팅 아로마 휠 다이어그램"
|
||||
style="width: 100%; display: block;"
|
||||
/>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: var(--space-4);">
|
||||
<div class="eyebrow">SENSORY ANALYSIS</div>
|
||||
<h2 style="font-size: var(--step-2); font-weight: 800; line-height: 1.25;">
|
||||
후각과 미각의 지도를 그리는<br />
|
||||
<span class="accent-text">4축 아로마 분석법</span>
|
||||
</h2>
|
||||
<div style="display: flex; flex-direction: column; gap: var(--space-3); font-size: var(--step--1); color: var(--ink-muted); line-height: 1.7;">
|
||||
<p>
|
||||
<strong style="color: var(--ink);">1. Peat Smoke (피트/스모키)</strong>: 아일라 섬의 이탄 연기, 해초의 요오드(Iodine), 정향과 재(Ash)의 깊이.
|
||||
</p>
|
||||
<p>
|
||||
<strong style="color: var(--ink);">2. Dried Fruits (건과일 & 셰리)</strong>: 올로로소/PX 캐스크에서 추출된 말린 무화과, 건포도, 다크 초콜릿의 농밀함.
|
||||
</p>
|
||||
<p>
|
||||
<strong style="color: var(--ink);">3. Floral & Orchard (에스테르 & 과원)</strong>: 장기 발효와 구리 환류에서 비롯된 풋사과, 엘더플라워, 꿀의 산뜻함.
|
||||
</p>
|
||||
<p>
|
||||
<strong style="color: var(--ink);">4. Charred Oak (오크 바닐린)</strong>: 1st Fill 버번 배럴의 그을린 탄닌, 토피, 시나몬 스파이스.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Course Comparison Deep Cards -->
|
||||
<section class="wrap" style="padding-bottom: var(--space-8);" id="courses">
|
||||
<div class="eyebrow" style="text-align: center;">CURATED FLIGHT SELECTION</div>
|
||||
<h2 style="font-size: var(--step-3); font-weight: 800; text-align: center; margin-top: 6px;">
|
||||
도슨트 테이스팅 정규 코스
|
||||
</h2>
|
||||
|
||||
<div class="course-card-grid">
|
||||
<!-- Course A -->
|
||||
<div class="course-deep-card">
|
||||
<div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: baseline;">
|
||||
<span class="eyebrow" style="color: var(--ink-muted);">COURSE A</span>
|
||||
<span style="font-size: var(--step-2); font-weight: 800; color: var(--accent);">65,000원</span>
|
||||
</div>
|
||||
<h3 style="font-size: var(--step-1); font-weight: 700; margin-top: 8px;">
|
||||
독립병입자 입문 탐색 플라이트 (3잔)
|
||||
</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-top: 6px; line-height: 1.6;">
|
||||
증류소의 기본 공식 라인업(OB)과 독립병입자(IB) 싱글 캐스크의 결정적 차이를 체감하는 코스입니다.
|
||||
</p>
|
||||
|
||||
<table class="lineup-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>순서</th>
|
||||
<th>라인업 구성</th>
|
||||
<th>ABV</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>하이랜드 에스테르 (클라인리쉬 14y vs IB 캐스크)</td>
|
||||
<td>46.0% / 54.2%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>스페이사이드 셰리 (글렌토커스 1st Fill 셰리 버트)</td>
|
||||
<td>56.8% CS</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>아일라 헤비 피트 (라프로익 2005 SMWS 29.281)</td>
|
||||
<td>57.8% CS</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="border-top: 1px solid var(--line); padding-top: var(--space-4); display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="font-family: var(--font-mono); font-size: var(--step--1); color: var(--ink-muted);">소요 시간: 45분</span>
|
||||
<a href="#reservation-section" class="btn-outline" style="text-decoration: none;">코스 A 예약하기</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Course B -->
|
||||
<div class="course-deep-card highlight">
|
||||
<div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: baseline;">
|
||||
<span class="eyebrow" style="color: var(--accent);">COURSE B</span>
|
||||
<span style="font-size: var(--step-2); font-weight: 800; color: var(--accent);">120,000원</span>
|
||||
</div>
|
||||
<h3 style="font-size: var(--step-1); font-weight: 700; margin-top: 8px;">
|
||||
캐스크 스트렝스 & 빈티지 마스터 플라이트 (5잔)
|
||||
</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-top: 6px; line-height: 1.6;">
|
||||
물 한 방울 타지 않은 원액(Cask Strength)과 1990년대 올드 빈티지 캐스크 5종을 정밀 비교 테이스팅합니다.
|
||||
</p>
|
||||
|
||||
<table class="lineup-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>순서</th>
|
||||
<th>라인업 구성</th>
|
||||
<th>ABV</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>스프링뱅크 1993 (G&M 리필 셰리 호그스헤드 27y)</td>
|
||||
<td>51.6% CS</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>모틀락 1989 (사마롤리 22y 싱글 캐스크)</td>
|
||||
<td>50.4% CS</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>맥캘란 1993 (카덴헤드 1842 클래식 레인지)</td>
|
||||
<td>54.8% CS</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td>쿨일라 2008 (PX 피니시 14y)</td>
|
||||
<td>56.4% CS</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td>
|
||||
<td>벤네비스 1998 (아델피 버번 캐스크 22y)</td>
|
||||
<td>58.1% CS</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="border-top: 1px solid var(--line); padding-top: var(--space-4); display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="font-family: var(--font-mono); font-size: var(--step--1); color: var(--accent);">소요 시간: 75분 · 페어링 포함</span>
|
||||
<a href="#reservation-section" class="btn-primary" style="text-decoration: none;">코스 B 예약하기</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Masterclass Lineup Showcase Visual -->
|
||||
<div class="wrap" style="margin-bottom: var(--space-8);">
|
||||
<div class="frame">
|
||||
<img
|
||||
src="../assets/masterclass-lineup.webp"
|
||||
alt="도슨트 마스터클래스 5종 단일 캐스크 위스키 라인업과 테이스팅 카드"
|
||||
style="width: 100%; display: block; aspect-ratio: 16/9; object-fit: cover;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gastronomy Pairing Atelier -->
|
||||
<section class="wrap" style="padding-bottom: var(--space-8);">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--space-8); align-items: center;">
|
||||
<div style="display: flex; flex-direction: column; gap: var(--space-4);">
|
||||
<div class="eyebrow">GASTRONOMY PAIRING</div>
|
||||
<h2 style="font-size: var(--step-2); font-weight: 800; line-height: 1.25;">
|
||||
향과 질감의 증폭을 위한<br />
|
||||
<span class="accent-text">아티잔 푸드 페어링</span>
|
||||
</h2>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); line-height: 1.8;">
|
||||
위스키의 높은 알코올 도수와 강렬한 탄닌을 부드럽게 감싸안고, 숨겨진 미세 에스테르를 끌어올리기 위해
|
||||
스페인산 이베리코 하몽 베요타, 에콰도르 싱글 오리진 70% 다크 카카오 트러플, 터키산 흑무화과를 페어링 플레이트로 함께 서브합니다.
|
||||
</p>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<img
|
||||
src="../assets/whisky-pairing.webp"
|
||||
alt="위스키 푸드 페어링 플레이트 (이베리코 하몽, 다크 초콜릿 트러플, 무화과)"
|
||||
style="width: 100%; display: block;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Live Reservation Form Section -->
|
||||
<section class="wrap" style="padding-bottom: var(--space-8);" id="reservation-section">
|
||||
<div class="card" style="max-width: 720px; margin: 0 auto;">
|
||||
<div class="eyebrow" style="color: var(--accent); margin-bottom: 4px;">RESERVATION REQUEST</div>
|
||||
<h2 style="font-size: var(--step-2); font-weight: 800; margin-bottom: var(--space-4);">
|
||||
도슨트 테이스팅 세션 실시간 예약
|
||||
</h2>
|
||||
<form onsubmit="event.preventDefault(); alert('도슨트 예약 신청이 완료되었습니다! 24시간 이내에 전담 마스터가 유선 안내를 드립니다.');" style="display: flex; flex-direction: column; gap: var(--space-4);">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="courseSelect">선택 코스</label>
|
||||
<select class="form-input" id="courseSelect" required>
|
||||
<option value="courseB">코스 B. 캐스크 스트렝스 & 빈티지 마스터 플라이트 (120,000원)</option>
|
||||
<option value="courseA">코스 A. 독립병입자 입문 탐색 플라이트 (65,000원)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3);">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="resDate">예약 일자</label>
|
||||
<input type="date" class="form-input" id="resDate" value="2026-08-28" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="resTime">예약 시간대</label>
|
||||
<select class="form-input" id="resTime" required>
|
||||
<option>19:00 (1부)</option>
|
||||
<option selected>20:30 (2부)</option>
|
||||
<option>22:00 (3부 - 심야 세션)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3);">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="userName">예약자 성함</label>
|
||||
<input type="text" class="form-input" id="userName" value="정재훈" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="userPhone">연락처</label>
|
||||
<input type="tel" class="form-input" id="userPhone" value="010-8831-2094" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="flavorNote">평소 선호하시는 위스키 취향 (선택)</label>
|
||||
<input type="text" class="form-input" id="flavorNote" placeholder="예: 아일라 피트 위스키, 셰리 버트 숙성 선호" value="셰리 버트 숙성 & 80ppm 이상 헤비 피트 선호" />
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-primary" style="margin-top: var(--space-2); padding: 14px; font-size: var(--step-0);">
|
||||
위스키 도슨트 세션 예약 확정 →
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- 푸터 (.site-foot SSOT) -->
|
||||
<footer class="site-foot">
|
||||
<div class="wrap foot-inner">
|
||||
<p>캐스크 아카이브 · 서울 용산구 한남대로 27길 19 지하 1층</p>
|
||||
<p class="muted">매일 18:00 – 02:00 (사전 예약제)</p>
|
||||
<p class="muted">bottling@caskarchive.kr</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
491
apps/site/public/work/cask-archive/index.html
Normal file
|
|
@ -0,0 +1,491 @@
|
|||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>캐스크 아카이브 (CASK ARCHIVE · 樽室) · 독립병입자 위스키바 & 도슨트 큐레이션</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Gordon & MacPhail, Signatory, SMWS 등 독립병입자(IB) 희귀 캐스크 공식 수입 인증 위스키바. 캐스크 넘버 원장과 1:1 위스키 도슨트 테이스팅 코스 예약."
|
||||
/>
|
||||
<meta property="og:title" content="캐스크 아카이브 (CASK ARCHIVE) · 독립병입자 위스키바" />
|
||||
<meta property="og:description" content="시간과 배럴이 빚어낸 오직 단 하나의 원액. 공식 수입 인증 독립병입자 전문 아카이브." />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta name="theme-color" content="#0b0b0d" />
|
||||
|
||||
<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;700&display=swap"
|
||||
/>
|
||||
<link rel="stylesheet" href="./styles/main.css?v=4" />
|
||||
<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' rx='8' fill='%230B0B0D'/%3E%3Ccircle cx='16' cy='16' r='10' stroke='%23D99B38' stroke-width='2' fill='none'/%3E%3Cpath d='M16 8v16M8 16h16' stroke='%23D99B38' stroke-width='1.5'/%3E%3C/svg%3E"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a class="skip-link" href="#mainContent">본문으로 건너뛰기</a>
|
||||
|
||||
<!-- 상단 헤더 (.site-head SSOT) -->
|
||||
<header class="site-head">
|
||||
<div class="wrap head-inner">
|
||||
<a class="wordmark" href="./index.html">
|
||||
樽 캐스크 아카이브 <span class="wordmark-han">CASK ARCHIVE</span>
|
||||
</a>
|
||||
|
||||
<nav class="nav" aria-label="메인 메뉴">
|
||||
<a href="#ledger">캐스크 원장</a>
|
||||
<a href="./docent/index.html" style="color: var(--accent); font-weight: 600;">도슨트 마스터클래스</a>
|
||||
<a href="#curator">향미 큐레이션</a>
|
||||
<a href="#events">릴리즈</a>
|
||||
<a href="#subscribe">뉴스레터</a>
|
||||
</nav>
|
||||
|
||||
<div class="head-actions">
|
||||
<a href="#docent" class="btn">
|
||||
도슨트 예약
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="mainContent">
|
||||
<!-- 히어로 섹션 -->
|
||||
<section class="hero-section" aria-labelledby="heroHeading">
|
||||
<div class="wrap hero-grid">
|
||||
<div class="hero-content">
|
||||
<div class="eyebrow-amber">
|
||||
<span>OFFICIALLY CERTIFIED INDEPENDENT BOTTLER BAR</span>
|
||||
</div>
|
||||
<h1 id="heroHeading" class="hero-title">
|
||||
시간과 배럴이 빚어낸<br />
|
||||
오직 단 하나의 <span class="gold">원액(Single Cask)</span>
|
||||
</h1>
|
||||
<p class="hero-desc">
|
||||
증류소의 기본 공식 라인업에서는 맛볼 수 없는 독립병입자(Independent Bottler)의 희귀 원액들. 공식 정식 수입 필증과 단일 캐스크 일련번호(Single Cask Number)를 보증하며, 전담 도슨트가 취향에 맞춘 위스키를 1:1로 큐레이션합니다.
|
||||
</p>
|
||||
<div class="hero-ctas">
|
||||
<a href="#ledger" class="btn-amber">
|
||||
실시간 캐스크 원장 확인
|
||||
<span aria-hidden="true">↗</span>
|
||||
</a>
|
||||
<a href="./docent/index.html" class="btn-outline">
|
||||
1:1 도슨트 마스터클래스 상세 보기
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-visual" style="position: relative;">
|
||||
<div class="bezel-outer">
|
||||
<div class="hero-frame">
|
||||
<img
|
||||
src="./assets/whisky-hero.webp"
|
||||
alt="차링된 오크 배럴 상판 위 싱글 캐스크 위스키 보틀과 테이스팅 글라스"
|
||||
width="1200"
|
||||
height="1600"
|
||||
loading="eager"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-cask-tag">
|
||||
<div class="cask-tag-no">CASK #8821 · 58.4% ABV</div>
|
||||
<div class="cask-tag-sub">Signatory Vintage 1997 · Bottle 42 of 186</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 공식 독립병입자 수입 인증 스트립 -->
|
||||
<section class="ib-cert-strip" aria-label="독립병입자 공식 인증">
|
||||
<div class="wrap cert-grid">
|
||||
<div class="cert-item">
|
||||
<div class="cert-name">GORDON & MACPHAIL</div>
|
||||
<div class="cert-desc">1895년 설립 · 스코틀랜드 최고 권위 정식 수입</div>
|
||||
</div>
|
||||
<div class="cert-item">
|
||||
<div class="cert-name">SIGNATORY VINTAGE</div>
|
||||
<div class="cert-desc">언칠필터드 / 내추럴 컬러 캐스크 스트렝스 보증</div>
|
||||
</div>
|
||||
<div class="cert-item">
|
||||
<div class="cert-name">THE SCOTCH MALT WHISKY SOCIETY</div>
|
||||
<div class="cert-desc">SMWS 공식 파트너 베뉴 · 넘버링 큐레이션</div>
|
||||
</div>
|
||||
<div class="cert-item">
|
||||
<div class="cert-name">CADENHEAD'S</div>
|
||||
<div class="cert-desc">1842년 스코틀랜드 최고(最古) 독립병입자 라인업</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 캐스크 원장 (Interactive Cask Ledger) -->
|
||||
<section class="ledger-section" id="ledger" aria-labelledby="ledgerHeading">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<h2 id="ledgerHeading" class="section-title">독립병입자 캐스크 실시간 보유 원장</h2>
|
||||
<p class="section-sub">모든 병은 단일 캐스크(Single Cask)에서 추출되어 병입 수량이 한정되어 있습니다. 필터로 원하는 향미 스펙을 검색하십시오.</p>
|
||||
</div>
|
||||
|
||||
<div class="ledger-filter-bar">
|
||||
<div class="filter-btn-group" role="group" aria-label="캐스크 분류">
|
||||
<button class="filter-btn is-active" data-filter="all">전체 원장 (5)</button>
|
||||
<button class="filter-btn" data-filter="sherry">셰리 캐스크</button>
|
||||
<button class="filter-btn" data-filter="peat">피트 / 스모키</button>
|
||||
<button class="filter-btn" data-filter="bourbon">버번 배럴</button>
|
||||
<button class="filter-btn" data-filter="cs">캐스크 스트렝스 (50%+)</button>
|
||||
</div>
|
||||
<input
|
||||
type="search"
|
||||
id="caskSearch"
|
||||
class="search-input"
|
||||
placeholder="증류소명 or 캐스크 번호 검색..."
|
||||
aria-label="캐스크 검색"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="ledger-table-wrap">
|
||||
<table class="ledger-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>캐스크 번호</th>
|
||||
<th>증류소 & 원액 명칭</th>
|
||||
<th>독립병입자 (Bottler)</th>
|
||||
<th>숙성 배럴 / 년수</th>
|
||||
<th>도수 (ABV)</th>
|
||||
<th>한정 수량</th>
|
||||
<th>향미 노트 요약</th>
|
||||
<th>인증 정보</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="caskTableBody">
|
||||
<tr data-cat="sherry cs">
|
||||
<td class="mono cask-badge">#6512</td>
|
||||
<td><strong>Clynelish 1996</strong><br /><span style="color:var(--ink-muted);font-size:11px;">하이랜드 · 왁시 꿀 & 린덴</span></td>
|
||||
<td>Signatory Vintage</td>
|
||||
<td>1st Fill Sherry Butt · 24년</td>
|
||||
<td class="mono" style="color:var(--accent);font-weight:700;">54.2%</td>
|
||||
<td class="mono">180 Btls</td>
|
||||
<td>말린 무화과, 밀랍, 시나몬, 다크초콜릿</td>
|
||||
<td><button class="btn-outline" style="padding:4px 10px;font-size:11px;" onclick="openCertModal('Clynelish 1996 #6512', 'Signatory Vintage', '24 Years (1996 Distilled / 2020 Bottled)', '54.2% Cask Strength', '식약처 정식통관 제2024-IB-0982호');">수입인증서</button></td>
|
||||
</tr>
|
||||
<tr data-cat="peat cs">
|
||||
<td class="mono cask-badge">#29.281</td>
|
||||
<td><strong>Laphroaig 2005</strong><br /><span style="color:var(--ink-muted);font-size:11px;">아일라 · 약용 피트 & 해풍</span></td>
|
||||
<td>SMWS (Society)</td>
|
||||
<td>1st Fill Ex-Bourbon · 15년</td>
|
||||
<td class="mono" style="color:var(--accent);font-weight:700;">57.8%</td>
|
||||
<td class="mono">214 Btls</td>
|
||||
<td>모닥불 연기, 바다 소금, 레몬 제스트, 피트 45ppm</td>
|
||||
<td><button class="btn-outline" style="padding:4px 10px;font-size:11px;" onclick="openCertModal('Laphroaig 2005 (SMWS 29.281)', 'The SMWS Partner', '15 Years (2005 Distilled)', '57.8% Cask Strength', '식약처 정식통관 제2025-IB-1102호');">수입인증서</button></td>
|
||||
</tr>
|
||||
<tr data-cat="sherry">
|
||||
<td class="mono cask-badge">#93/41</td>
|
||||
<td><strong>Springbank 1993</strong><br /><span style="color:var(--ink-muted);font-size:11px;">캠벨타운 · 미네랄 & 오일</span></td>
|
||||
<td>Gordon & MacPhail</td>
|
||||
<td>Refill Sherry Hogshead · 27년</td>
|
||||
<td class="mono" style="color:var(--accent);font-weight:700;">51.6%</td>
|
||||
<td class="mono">142 Btls</td>
|
||||
<td>열대 과일 잼, 가죽, 부드러운 유황, 정향</td>
|
||||
<td><button class="btn-outline" style="padding:4px 10px;font-size:11px;" onclick="openCertModal('Springbank 1993 #93/41', 'Gordon & MacPhail Reserve', '27 Years (1993 Distilled)', '51.6%', '식약처 정식통관 제2024-IB-0419호');">수입인증서</button></td>
|
||||
</tr>
|
||||
<tr data-cat="peat cs">
|
||||
<td class="mono cask-badge">#PX-88</td>
|
||||
<td><strong>Caol Ila 2008</strong><br /><span style="color:var(--ink-muted);font-size:11px;">아일라 · 달콤한 훈연</span></td>
|
||||
<td>Cadenhead's</td>
|
||||
<td>Pedro Ximenez Finish · 14년</td>
|
||||
<td class="mono" style="color:var(--accent);font-weight:700;">56.4%</td>
|
||||
<td class="mono">260 Btls</td>
|
||||
<td>스모크 베이컨, 건포도, 블랙베리, 훈제 파프리카</td>
|
||||
<td><button class="btn-outline" style="padding:4px 10px;font-size:11px;" onclick="openCertModal('Caol Ila 2008 #PX-88', 'Cadenheads Authentic Collection', '14 Years', '56.4% Cask Strength', '식약처 정식통관 제2025-IB-0831호');">수입인증서</button></td>
|
||||
</tr>
|
||||
<tr data-cat="bourbon cs">
|
||||
<td class="mono cask-badge">#98/12</td>
|
||||
<td><strong>Ben Nevis 1998</strong><br /><span style="color:var(--ink-muted);font-size:11px;">서부 하이랜드 · 묵직한 바디</span></td>
|
||||
<td>Adelphi Distillery</td>
|
||||
<td>Ex-Bourbon Cask · 22년</td>
|
||||
<td class="mono" style="color:var(--accent);font-weight:700;">58.1%</td>
|
||||
<td class="mono">195 Btls</td>
|
||||
<td>바닐라 커스터드, 구운 코코넛, 청사과, 후추</td>
|
||||
<td><button class="btn-outline" style="padding:4px 10px;font-size:11px;" onclick="openCertModal('Ben Nevis 1998 #98/12', 'Adelphi Selection', '22 Years', '58.1%', '식약처 정식통관 제2024-IB-0771호');">수입인증서</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 1:1 위스키 도슨트 테이스팅 코스 예약 -->
|
||||
<section class="docent-section" id="docent" aria-labelledby="docentHeading">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<h2 id="docentHeading" class="section-title">1:1 맞춤형 위스키 도슨트 테이스팅</h2>
|
||||
<p class="section-sub">공인 위스키 마스터가 당신의 향미 선호도를 분석하여 독립병입자 캐스크를 1:1로 해설하고 페어링합니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="docent-grid">
|
||||
<!-- 코스 설명 카드 -->
|
||||
<div class="course-list">
|
||||
<div class="course-card">
|
||||
<div class="course-header">
|
||||
<h3 class="course-title">코스 A. 독립병입자 입문 탐색 플라이트 (3잔)</h3>
|
||||
<span class="course-price">65,000원</span>
|
||||
</div>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-bottom: 12px;">
|
||||
증류소 오피셜 보틀과 동일 증류소의 독립병입자 싱글 캐스크를 1:1로 비교하며 배럴 숙성의 차이를 체감하는 코스.
|
||||
</p>
|
||||
<div style="font-size: 12px; color: var(--accent);" class="mono">소요 시간: 45분 · 도슨트 1:1 배정 · 하이엔드 글렌캐런 글라스 제공</div>
|
||||
</div>
|
||||
|
||||
<div class="course-card">
|
||||
<div class="course-header">
|
||||
<h3 class="course-title">코스 B. 캐스크 스트렝스 & 빈티지 마스터 플라이트 (5잔)</h3>
|
||||
<span class="course-price">120,000원</span>
|
||||
</div>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-bottom: 12px;">
|
||||
1990년대 올드 빈티지 및 55% 이상의 싱글 캐스크 스트렝스 5종을 테이스팅 휠과 함께 정밀 분석하는 심화 코스.
|
||||
</p>
|
||||
<div style="font-size: 12px; color: var(--accent);" class="mono">소요 시간: 75분 · 아티잔 초콜릿 & 샤퀴테리 페어링 포함</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 예약 입력 폼 -->
|
||||
<div class="docent-booking-form">
|
||||
<h3 style="font-family: var(--font-serif); font-size: var(--step-1); margin-bottom: var(--space-4); color: var(--ink);">
|
||||
도슨트 프라이빗 세션 예약 신청
|
||||
</h3>
|
||||
<form id="docentForm" onsubmit="return false;">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="bookingCourse">선택 코스</label>
|
||||
<select id="bookingCourse" class="form-select">
|
||||
<option value="A">코스 A. 독립병입자 입문 탐색 플라이트 (65,000원)</option>
|
||||
<option value="B" selected>코스 B. 캐스크 스트렝스 & 빈티지 마스터 플라이트 (120,000원)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem;">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="bookingDate">예약 일자</label>
|
||||
<input type="date" id="bookingDate" class="form-input" value="2026-08-28" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="bookingTime">예약 시간대</label>
|
||||
<select id="bookingTime" class="form-select">
|
||||
<option>19:00 (1부)</option>
|
||||
<option selected>20:30 (2부)</option>
|
||||
<option>22:00 (3부 심야)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem;">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="guestName">예약자 성함</label>
|
||||
<input type="text" id="guestName" class="form-input" placeholder="홍길동" value="정재훈" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="guestPhone">연락처</label>
|
||||
<input type="tel" id="guestPhone" class="form-input" placeholder="010-0000-0000" value="010-8831-2094" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="guestPref">향미 선호도 메모</label>
|
||||
<input type="text" id="guestPref" class="form-input" placeholder="예: 셰리 밤 선호, 스모키 피트 선호 등" value="강렬한 셰리 버트와 헤비 피트 선호" />
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-amber" id="btnBookDocent" style="width: 100%; padding: 14px; margin-top: 10px;">
|
||||
위스키 도슨트 세션 예약 확정
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 이벤트 & 뉴스레터 & 인스타그램 -->
|
||||
<section class="events-section" id="events" aria-labelledby="eventHeading">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<h2 id="eventHeading" class="section-title">프라이빗 시음회 & 릴리즈 이벤트</h2>
|
||||
<p class="section-sub">월별 한정 입고되는 독립병입자 캐스크 오프닝 파티 및 정기 세미나 일정입니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="event-grid">
|
||||
<div class="event-item">
|
||||
<div class="event-date-box">
|
||||
<span class="event-day">09.12</span>
|
||||
<span class="event-month">FRI 20:00</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="font-size: var(--step-0); font-weight: 700; color: var(--ink); margin-bottom: 4px;">
|
||||
1990s 올드 셰리 버트 4종 버티컬 시음회
|
||||
</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted);">
|
||||
Signatory & G&M 90년대 빈티지 셰리 캐스크 4종 비교 테이스팅 (정원 8인 한정)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="event-item">
|
||||
<div class="event-date-box">
|
||||
<span class="event-day">09.26</span>
|
||||
<span class="event-month">SAT 21:00</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="font-size: var(--step-0); font-weight: 700; color: var(--ink); margin-bottom: 4px;">
|
||||
아일라 옥토모어 & 피트 심야 도슨트 나이트
|
||||
</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted);">
|
||||
페놀 수치 80ppm 이상의 극한 피트 독립병입자 바틀 블라인드 테이스팅
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 뉴스레터 & 인스타그램 카드 -->
|
||||
<div class="newsletter-card" id="subscribe">
|
||||
<div class="eyebrow-amber">EXCLUSIVE CASK NOTIFICATION</div>
|
||||
<h3 style="font-family: var(--font-serif); font-size: var(--step-2); margin-block: 8px 12px; color: var(--ink);">
|
||||
신규 캐스크 입고 알림 & 인스타그램
|
||||
</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); max-width: 500px; margin-inline: auto;">
|
||||
수량이 극소량인 독립병입자 캐스크 오프닝 소식을 이메일 뉴스레터로 가장 먼저 발송해 드립니다.
|
||||
</p>
|
||||
|
||||
<form class="newsletter-form" onsubmit="return false;">
|
||||
<input
|
||||
type="email"
|
||||
id="newsEmail"
|
||||
class="form-input"
|
||||
placeholder="귀하의 이메일 주소를 입력하세요"
|
||||
required
|
||||
/>
|
||||
<button type="button" class="btn-amber" id="btnSubscribe">
|
||||
구독 신청
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div style="margin-top: var(--space-5); display: inline-flex; align-items: center; gap: 8px;">
|
||||
<a href="https://instagram.com" target="_blank" rel="noopener noreferrer" class="btn-outline" style="font-size: 12px; padding: 6px 16px;">
|
||||
📸 인스타그램 @caskarchive.official 바로가기 ↗
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- 수입 인증서 모달 다이얼로그 -->
|
||||
<dialog id="certModal" class="cert-dialog" aria-labelledby="certTitle">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; border-bottom: 1px solid var(--line); padding-bottom: 0.75rem;">
|
||||
<h3 id="certTitle" style="font-family: var(--font-serif); font-size: var(--step-1); color: var(--accent);">
|
||||
공식 독립병입자 수입 보증서
|
||||
</h3>
|
||||
<button type="button" onclick="document.getElementById('certModal').close();" aria-label="닫기" style="font-size: 18px; font-weight: 700; color: var(--ink-muted);">✕</button>
|
||||
</div>
|
||||
<div style="display: grid; gap: 0.75rem; font-size: var(--step--1); line-height: 1.6;">
|
||||
<div><strong>증류소 및 보틀:</strong> <span id="mWhiskyName" class="mono" style="color:var(--ink);"></span></div>
|
||||
<div><strong>독립병입자:</strong> <span id="mBottler" class="mono" style="color:var(--ink);"></span></div>
|
||||
<div><strong>숙성 정보:</strong> <span id="mAge" class="mono" style="color:var(--ink);"></span></div>
|
||||
<div><strong>알코올 도수:</strong> <span id="mAbv" class="mono" style="color:var(--accent);"></span></div>
|
||||
<div><strong>통관 필증 번호:</strong> <span id="mCustoms" class="mono" style="color:#34d399;"></span></div>
|
||||
</div>
|
||||
<div style="margin-top: 1.5rem; text-align: right;">
|
||||
<button type="button" class="btn-amber" style="padding: 6px 18px; font-size: 13px;" onclick="document.getElementById('certModal').close();">확인 완료</button>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!-- 푸터 (.site-foot SSOT) -->
|
||||
<footer class="site-foot">
|
||||
<div class="wrap foot-inner">
|
||||
<p>캐스크 아카이브 · 서울 용산구 한남대로 27길 19 지하 1층</p>
|
||||
<p class="muted">매일 18:00 – 02:00 (사전 예약제)</p>
|
||||
<p class="muted">bottling@caskarchive.kr</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- 인터랙티브 스크립트 -->
|
||||
<script>
|
||||
(function () {
|
||||
// 1. 캐스크 원장 검색 및 필터링
|
||||
const filterBtns = document.querySelectorAll(".filter-btn");
|
||||
const searchInput = document.getElementById("caskSearch");
|
||||
const rows = document.querySelectorAll("#caskTableBody tr");
|
||||
|
||||
function filterLedger() {
|
||||
const activeFilter = document.querySelector(".filter-btn.is-active")?.getAttribute("data-filter") || "all";
|
||||
const query = searchInput.value.toLowerCase().trim();
|
||||
|
||||
rows.forEach((row) => {
|
||||
const cat = row.getAttribute("data-cat") || "";
|
||||
const text = row.textContent.toLowerCase();
|
||||
|
||||
const matchCat = activeFilter === "all" || cat.includes(activeFilter);
|
||||
const matchQuery = !query || text.includes(query);
|
||||
|
||||
row.style.display = matchCat && matchQuery ? "" : "none";
|
||||
});
|
||||
}
|
||||
|
||||
filterBtns.forEach((btn) => {
|
||||
btn.addEventListener("click", () => {
|
||||
filterBtns.forEach((b) => b.classList.remove("is-active"));
|
||||
btn.classList.add("is-active");
|
||||
filterLedger();
|
||||
});
|
||||
});
|
||||
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener("input", filterLedger);
|
||||
}
|
||||
|
||||
// 2. 도슨트 예약 버튼
|
||||
const btnBook = document.getElementById("btnBookDocent");
|
||||
if (btnBook) {
|
||||
btnBook.addEventListener("click", () => {
|
||||
const name = document.getElementById("guestName").value || "고객님";
|
||||
const date = document.getElementById("bookingDate").value;
|
||||
const time = document.getElementById("bookingTime").value;
|
||||
const course = document.getElementById("bookingCourse").value;
|
||||
alert(`[캐스크 아카이브] ${name}님의 1:1 위스키 도슨트 세션(코스 ${course})이 예약 접수되었습니다.\n일정: ${date} ${time}\n담당 도슨트가 당일 사전 안내 연락을 드립니다.`);
|
||||
});
|
||||
}
|
||||
|
||||
// 3. 뉴스레터 구독
|
||||
const btnSub = document.getElementById("btnSubscribe");
|
||||
if (btnSub) {
|
||||
btnSub.addEventListener("click", () => {
|
||||
const email = document.getElementById("newsEmail").value;
|
||||
if (!email || !email.includes("@")) {
|
||||
alert("유효한 이메일 주소를 입력해 주십시오.");
|
||||
return;
|
||||
}
|
||||
alert(`[캐스크 아카이브] ${email} 주소로 신규 독립병입자 캐스크 릴리즈 알림이 등록되었습니다.`);
|
||||
document.getElementById("newsEmail").value = "";
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
// 인증서 모달 팝업 함수
|
||||
function openCertModal(name, bottler, age, abv, customs) {
|
||||
document.getElementById("mWhiskyName").textContent = name;
|
||||
document.getElementById("mBottler").textContent = bottler;
|
||||
document.getElementById("mAge").textContent = age;
|
||||
document.getElementById("mAbv").textContent = abv;
|
||||
document.getElementById("mCustoms").textContent = customs;
|
||||
document.getElementById("certModal").showModal();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
788
apps/site/public/work/cask-archive/styles/main.css
Normal file
|
|
@ -0,0 +1,788 @@
|
|||
@import "./tokens.css";
|
||||
|
||||
/* ==========================================================================
|
||||
캐스크 아카이브 (CASK ARCHIVE · 樽室) — 메인 스타일시트 SSOT
|
||||
프리셋: editorial-archival + dark-instrument + high-end-visual-design
|
||||
========================================================================== */
|
||||
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
scroll-behavior: smooth;
|
||||
background-color: var(--surface);
|
||||
color: var(--ink);
|
||||
font-family: var(--font-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100dvh;
|
||||
line-height: var(--leading-normal);
|
||||
overflow-x: hidden;
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: color var(--dur-fast);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
button, input, select, textarea {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.serif {
|
||||
font-family: var(--font-serif);
|
||||
}
|
||||
|
||||
.italic {
|
||||
font-family: var(--font-serif);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.gold {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.wrap {
|
||||
width: min(100% - 2 * var(--pad-inline), var(--container));
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* ── 접근성 스킵 링크 ── */
|
||||
.skip-link {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
z-index: 1000;
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--accent);
|
||||
color: var(--accent-ink);
|
||||
border-radius: var(--radius-xs);
|
||||
transform: translateY(-200%);
|
||||
transition: transform var(--dur-fast);
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
}
|
||||
.skip-link:focus {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* ── 헤더 (GNB SSOT) ── */
|
||||
.site-head {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
background: rgba(11, 11, 13, 0.94);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border-bottom: 1px solid var(--line);
|
||||
padding-block: var(--space-3);
|
||||
}
|
||||
|
||||
.head-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.wordmark {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: var(--space-2);
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-1);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
text-decoration: none;
|
||||
letter-spacing: 0.04em;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.wordmark-han {
|
||||
font-size: var(--step--1);
|
||||
color: var(--accent);
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-5);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
text-decoration: none;
|
||||
color: var(--ink-muted);
|
||||
font-size: var(--step--1);
|
||||
font-weight: 500;
|
||||
transition: color var(--dur-fast);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav a:hover,
|
||||
.nav a.active {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.head-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.head-actions .btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--accent);
|
||||
color: #0b0b0d;
|
||||
font-weight: 700;
|
||||
font-size: var(--step--1);
|
||||
padding: 6px 14px;
|
||||
border-radius: var(--radius-xs);
|
||||
transition: opacity var(--dur-fast), transform var(--dur-fast);
|
||||
}
|
||||
|
||||
.head-actions .btn:hover {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* ── 버튼 시스템 & 배지 ── */
|
||||
.btn-amber {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
background: var(--accent);
|
||||
color: #0b0b0d;
|
||||
padding: 10px 20px;
|
||||
border-radius: var(--radius-xs);
|
||||
font-weight: 700;
|
||||
font-size: var(--step--1);
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
transition: transform var(--dur-fast), background var(--dur-fast), opacity var(--dur-fast);
|
||||
border: 1px solid var(--accent);
|
||||
}
|
||||
|
||||
.btn-amber:hover {
|
||||
background: #e6ab48;
|
||||
color: #0b0b0d;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
border: 1px solid var(--line);
|
||||
padding: 10px 18px;
|
||||
border-radius: var(--radius-xs);
|
||||
font-weight: 600;
|
||||
font-size: var(--step--1);
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
transition: border-color var(--dur-fast), color var(--dur-fast);
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.eyebrow-amber {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 10px;
|
||||
border-radius: var(--radius-xs);
|
||||
background: rgba(217, 155, 56, 0.12);
|
||||
color: var(--accent);
|
||||
font-size: 11px;
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
margin-bottom: var(--space-3);
|
||||
border: 1px solid rgba(217, 155, 56, 0.25);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* ── 히어로 섹션 ── */
|
||||
.hero-section {
|
||||
padding-block: var(--space-8) var(--space-7);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.95fr);
|
||||
gap: var(--space-7);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: clamp(2.4rem, 1.8rem + 2.2vw, 3.8rem);
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.025em;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-4);
|
||||
text-wrap: balance;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-desc {
|
||||
font-size: clamp(1.05rem, 0.98rem + 0.35vw, 1.2rem);
|
||||
color: var(--ink-muted);
|
||||
max-width: 48ch;
|
||||
line-height: 1.75;
|
||||
margin-bottom: var(--space-6);
|
||||
text-wrap: pretty;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-ctas {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.hero-visual {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bezel-outer {
|
||||
background: rgba(217, 155, 56, 0.06);
|
||||
border: 1px solid var(--line);
|
||||
padding: 6px;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.hero-frame {
|
||||
border-radius: calc(var(--radius-md) - 4px);
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
box-shadow: 0 20px 48px -12px rgba(0, 0, 0, 0.7);
|
||||
background: #141418;
|
||||
}
|
||||
|
||||
.hero-frame img {
|
||||
width: 100%;
|
||||
aspect-ratio: 4/3;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hero-cask-tag {
|
||||
margin-top: var(--space-2);
|
||||
padding: 6px 12px;
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-xs);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.cask-tag-no {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.cask-tag-sub {
|
||||
font-size: 11px;
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
/* ── 공식 독립병입자 수입 인증 스트립 ── */
|
||||
.ib-cert-strip {
|
||||
border-block: 1px solid var(--line);
|
||||
background: var(--surface-raised);
|
||||
padding-block: var(--space-5);
|
||||
}
|
||||
|
||||
.cert-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.cert-item {
|
||||
border-left: 2px solid var(--accent);
|
||||
padding-left: var(--space-3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.cert-name {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.cert-desc {
|
||||
font-size: 12px;
|
||||
color: var(--ink-muted);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* ── 캐스크 원장 섹션 (Interactive Cask Ledger) ── */
|
||||
.ledger-section {
|
||||
padding-block: var(--space-8);
|
||||
}
|
||||
|
||||
.section-head {
|
||||
text-align: center;
|
||||
max-width: 680px;
|
||||
margin-inline: auto;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: clamp(1.8rem, 1.4rem + 1.2vw, 2.25rem);
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.02em;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-2);
|
||||
text-wrap: balance;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.section-sub {
|
||||
font-size: var(--step-0);
|
||||
color: var(--ink-muted);
|
||||
line-height: 1.6;
|
||||
text-wrap: pretty;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.ledger-filter-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-3);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.filter-btn-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
padding: 6px 14px;
|
||||
border-radius: var(--radius-xs);
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
color: var(--ink-muted);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
transition: all var(--dur-fast);
|
||||
}
|
||||
|
||||
.filter-btn:hover {
|
||||
border-color: var(--accent);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.filter-btn.is-active {
|
||||
background: rgba(217, 155, 56, 0.15);
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.search-input {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
color: var(--ink);
|
||||
padding: 8px 14px;
|
||||
border-radius: var(--radius-xs);
|
||||
font-size: 13px;
|
||||
min-width: 240px;
|
||||
outline: none;
|
||||
transition: border-color var(--dur-fast);
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.ledger-table-wrap {
|
||||
overflow-x: auto;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--surface-raised);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
||||
/* 앰버 골드 커스텀 스크롤바 (Firefox & 표준) */
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--accent) rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
/* 앰버 골드 커스텀 스크롤바 (WebKit / Chrome / Safari / Edge) */
|
||||
.ledger-table-wrap::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
background: var(--surface-raised);
|
||||
}
|
||||
|
||||
.ledger-table-wrap::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.ledger-table-wrap::-webkit-scrollbar-thumb {
|
||||
background: var(--accent);
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(11, 11, 13, 0.5);
|
||||
}
|
||||
|
||||
.ledger-table-wrap::-webkit-scrollbar-thumb:hover {
|
||||
background: #e6ab48;
|
||||
}
|
||||
|
||||
.ledger-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 12.5px;
|
||||
text-align: left;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.ledger-table th {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
padding: 12px 10px;
|
||||
color: var(--ink-muted);
|
||||
font-weight: 600;
|
||||
border-bottom: 1px solid var(--line);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11.5px;
|
||||
letter-spacing: 0.04em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ledger-table td {
|
||||
padding: 12px 10px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ledger-table tbody tr {
|
||||
transition: background var(--dur-fast);
|
||||
}
|
||||
|
||||
.ledger-table tbody tr:hover {
|
||||
background: rgba(217, 155, 56, 0.06);
|
||||
}
|
||||
|
||||
.ledger-table td:nth-child(1),
|
||||
.ledger-table td:nth-child(3),
|
||||
.ledger-table td:nth-child(4),
|
||||
.ledger-table td:nth-child(5),
|
||||
.ledger-table td:nth-child(6),
|
||||
.ledger-table td:nth-child(8) {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ledger-table td:nth-child(7) {
|
||||
white-space: normal;
|
||||
max-width: 240px;
|
||||
font-size: 12px;
|
||||
color: #d1d5db;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
.cask-badge {
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── 1:1 위스키 도슨트 테이스팅 코스 ── */
|
||||
.docent-section {
|
||||
padding-block: var(--space-8);
|
||||
border-top: 1px solid var(--line);
|
||||
background: var(--surface-card);
|
||||
}
|
||||
|
||||
.docent-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
|
||||
gap: var(--space-6);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.course-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.course-card {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-5);
|
||||
transition: border-color var(--dur-fast);
|
||||
}
|
||||
|
||||
.course-card:hover {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.course-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
margin-bottom: var(--space-2);
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.course-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-1);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.course-price {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.docent-booking-form {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 600;
|
||||
color: var(--ink-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.form-select,
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-xs);
|
||||
color: var(--ink);
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
transition: border-color var(--dur-fast);
|
||||
}
|
||||
|
||||
.form-select:focus,
|
||||
.form-input:focus {
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── 이벤트 & 뉴스레터 ── */
|
||||
.events-section {
|
||||
padding-block: var(--space-8);
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.event-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: var(--space-4);
|
||||
margin-bottom: var(--space-7);
|
||||
}
|
||||
|
||||
.event-item {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-5);
|
||||
display: flex;
|
||||
gap: var(--space-4);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.event-date-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 14px;
|
||||
background: rgba(217, 155, 56, 0.1);
|
||||
border: 1px solid rgba(217, 155, 56, 0.25);
|
||||
border-radius: var(--radius-xs);
|
||||
min-width: 80px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.event-day {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step-1);
|
||||
font-weight: 800;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.event-month {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
color: var(--ink-muted);
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.newsletter-card {
|
||||
text-align: center;
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-7) var(--space-5);
|
||||
max-width: 720px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.newsletter-form {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
max-width: 480px;
|
||||
margin: var(--space-5) auto 0;
|
||||
}
|
||||
|
||||
/* ── 인증서 모달 ── */
|
||||
.cert-dialog {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
margin: auto;
|
||||
width: min(90vw, 480px);
|
||||
background: #141418;
|
||||
color: #f3f3f5;
|
||||
border: 1px solid rgba(217, 155, 56, 0.4);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-5);
|
||||
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.8);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cert-dialog::backdrop {
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
/* ── 푸터 (SSOT 정본) ── */
|
||||
.site-foot {
|
||||
border-top: 1px solid var(--line);
|
||||
padding-block: var(--space-6);
|
||||
background: var(--surface);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.foot-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
/* ── 반응형 미디어 쿼리 ── */
|
||||
@media (max-width: 860px) {
|
||||
.nav {
|
||||
display: none;
|
||||
}
|
||||
.hero-grid,
|
||||
.docent-grid,
|
||||
.event-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
.cert-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
.newsletter-form {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 540px) {
|
||||
.cert-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.wordmark-han {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
74
apps/site/public/work/cask-archive/styles/tokens.css
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/* ==========================================================================
|
||||
캐스크 아카이브 (CASK ARCHIVE · 樽室) — 디자인 토큰 SSOT
|
||||
프리셋: dark-instrument + editorial-archival
|
||||
컨셉: 독립병입자 희귀 캐스크 원장과 1:1 위스키 도슨트 — 오크와 피트의 시간
|
||||
단일 강조색: 앰버 골드 (#D99B38)
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
/* 타이포그래피 스케일 */
|
||||
--step--1: 0.8125rem; /* 13px — 캡션·일련번호 */
|
||||
--step-0: 1rem; /* 16px — 본문 */
|
||||
--step-1: 1.1875rem; /* 19px — 소제목 */
|
||||
--step-2: clamp(1.375rem, 1.2rem + 0.9vw, 1.875rem); /* 30px — 섹션 표제 */
|
||||
--step-3: clamp(1.8rem, 1.4rem + 1.2vw, 2.25rem); /* 36px — 서브 표제 */
|
||||
--step-4: clamp(2.4rem, 1.8rem + 2.2vw, 3.8rem); /* 60px — 메인 디스플레이 */
|
||||
|
||||
--leading-tight: 1.18;
|
||||
--leading-normal: 1.7;
|
||||
--measure: 54ch;
|
||||
|
||||
--font-serif: "MaruBuri", "Noto Serif KR", serif;
|
||||
--font-display: "MaruBuri", "Noto Serif KR", serif;
|
||||
--font-body: "Pretendard Variable", Pretendard, -apple-system, sans-serif;
|
||||
--font-mono: "JetBrains Mono", monospace;
|
||||
|
||||
/* 다크 럭셔리 색상 — 미드나이트 오닉스 + 앰버 골드 1강조색 */
|
||||
--surface: #0b0b0d;
|
||||
--surface-raised: #141418;
|
||||
--surface-card: #1c1c22;
|
||||
--surface-subtle: #24242c;
|
||||
--surface-sunken: #070708;
|
||||
--surface-inverse: #f4f4f0;
|
||||
|
||||
--ink: #f4f4f0;
|
||||
--ink-muted: #9ca3af;
|
||||
--ink-faint: #6b7280;
|
||||
--ink-inverse: #0b0b0d;
|
||||
--ink-inverse-muted: #4b5563;
|
||||
|
||||
--line: #2a2a34;
|
||||
--line-strong: #3f3f4e;
|
||||
--line-subtle: #1e1e26;
|
||||
--line-inverse: #d1d5db;
|
||||
|
||||
/* 단일 강조색 — 오크 숙성 싱글 몰트 앰버 골드 */
|
||||
--accent: #d99b38;
|
||||
--accent-hover: #c28528;
|
||||
--accent-light: rgba(217, 155, 56, 0.12);
|
||||
--accent-surface: rgba(217, 155, 56, 0.2);
|
||||
--accent-ink: #0b0b0d;
|
||||
|
||||
--radius: 2px;
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 8px;
|
||||
|
||||
/* 간격 — SSOT 표준 */
|
||||
--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);
|
||||
|
||||
/* 컨테이너 및 패딩 — 전체 쇼케이스 절대 통일 SSOT */
|
||||
--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);
|
||||
}
|
||||
BIN
apps/site/public/work/cheongon-care/assets/atp-tester.webp
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
apps/site/public/work/cheongon-care/assets/clean-hero.webp
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
apps/site/public/work/cheongon-care/assets/steam-qc.webp
Normal file
|
After Width: | Height: | Size: 82 KiB |
608
apps/site/public/work/cheongon-care/index.html
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>청온 케어 (淸溫) · 프리미엄 주거·오피스 전문 위생 케어 & 관제 콘솔</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="임상 수준의 6단계 위생 프로토콜과 100% 정찰제 견적. 독일 카처 4.0bar 고온스팀과 에코서트 인증 천연 세제. 실시간 견적 신청 및 관제 콘솔 지원."
|
||||
/>
|
||||
<meta property="og:title" content="청온 케어 (淸溫) · 프리미엄 위생 케어" />
|
||||
<meta property="og:description" content="공간의 숨결을 되돌리는 6단계 프로토콜과 투명한 정찰제 견적." />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta name="theme-color" content="#f8faf9" />
|
||||
|
||||
<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/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;700&display=swap"
|
||||
/>
|
||||
<link rel="stylesheet" href="./styles/main.css?v=1" />
|
||||
<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' rx='8' fill='%230D9488'/%3E%3Cpath d='M9 16.5l5 5 9-10' stroke='%23ffffff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body data-view="client">
|
||||
<a class="skip-link" href="#mainContent">본문으로 건너뛰기</a>
|
||||
|
||||
<!-- 최상단 헤더 (.site-head SSOT) -->
|
||||
<header class="site-head">
|
||||
<div class="wrap head-inner">
|
||||
<a class="wordmark" href="#" id="brandLogo">
|
||||
<span class="wordmark-badge">淸</span>
|
||||
청온 케어 <span class="wordmark-han">淸溫</span>
|
||||
</a>
|
||||
|
||||
<nav class="nav" aria-label="메인 메뉴">
|
||||
<a href="#services">케어 솔루션</a>
|
||||
<a href="#calculator">정찰제 견적</a>
|
||||
<a href="./protocol/index.html" style="color: var(--accent); font-weight: 600;">6단계 프로토콜 (상세)</a>
|
||||
<a href="#equipment">전문 장비</a>
|
||||
</nav>
|
||||
|
||||
<div class="head-actions">
|
||||
<div class="mode-toggle" role="group" aria-label="뷰 모드 전환">
|
||||
<button type="button" class="mode-btn is-active" id="btnModeClient">
|
||||
고객 소개 뷰
|
||||
</button>
|
||||
<button type="button" class="mode-btn" id="btnModeAdmin" title="단축키: Alt + A">
|
||||
<span class="badge-dot" aria-hidden="true"></span>
|
||||
관리자 콘솔
|
||||
</button>
|
||||
</div>
|
||||
<a href="#calculator" class="btn client-only-btn">
|
||||
간편 견적
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="mainContent">
|
||||
<!-- ===================================================================
|
||||
1. 고객 소개 및 간편 신청 뷰 (Client View)
|
||||
=================================================================== -->
|
||||
<div class="client-view">
|
||||
<!-- 히어로 섹션 -->
|
||||
<section class="hero-section" aria-labelledby="heroHeading">
|
||||
<div class="wrap hero-grid">
|
||||
<div class="hero-content">
|
||||
<div class="eyebrow">
|
||||
<span>HOSPITAL-GRADE HYGIENE PROTOCOL</span>
|
||||
</div>
|
||||
<h1 id="heroHeading" class="hero-title">
|
||||
보이지 않는 미세 오염까지,<br />
|
||||
<em>공간의 숨결</em>을 되돌립니다
|
||||
</h1>
|
||||
<p class="hero-desc">
|
||||
단순한 미화가 아닙니다. 독일 카처 4.0bar 고온 스팀과 에코서트(ECOCERT) 인증 친환경 세제로 새집증후군, 미세 분진, 알레르기 유발 물질을 근본적으로 제거합니다.
|
||||
</p>
|
||||
<div class="hero-ctas">
|
||||
<a href="#calculator" class="btn-primary">
|
||||
실시간 정찰제 견적 계산하기
|
||||
<span class="btn-icon-circle" aria-hidden="true">↗</span>
|
||||
</a>
|
||||
<div class="hero-trust">
|
||||
<span class="hero-trust-stars">★★★★★</span>
|
||||
<span>누적 케어 4,820세대 · 만족도 99.4%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-visual">
|
||||
<div class="bezel-outer">
|
||||
<div class="hero-frame">
|
||||
<img
|
||||
src="./assets/clean-hero.webp"
|
||||
alt="정밀 입주 케어가 완료된 미니멀한 프리미엄 주거 거실 전경"
|
||||
width="1200"
|
||||
height="900"
|
||||
loading="eager"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-stat-floating">
|
||||
<span class="stat-val">32 Point</span>
|
||||
<span class="stat-label">마스터 클리너<br />정밀 검수 체크리스트</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 실시간 정찰제 견적 계산기 -->
|
||||
<section class="calc-section" id="calculator" aria-labelledby="calcHeading">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<h2 id="calcHeading" class="section-title">투명한 정찰제 실시간 견적 산정</h2>
|
||||
<p class="section-sub">추가금 없는 명확한 기준. 공간 면적과 맞춤 옵션을 선택하시면 즉시 예상 금액이 산출됩니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="calc-grid">
|
||||
<div class="calc-card">
|
||||
<form id="quoteForm" onsubmit="return false;">
|
||||
<!-- 공간 유형 -->
|
||||
<div class="form-group">
|
||||
<label class="form-label" id="spaceTypeLabel">공간 유형 선택</label>
|
||||
<div class="type-selector" role="radiogroup" aria-labelledby="spaceTypeLabel">
|
||||
<button type="button" class="type-btn is-active" data-type="apt" data-base="11000">
|
||||
주거 입주/이사
|
||||
</button>
|
||||
<button type="button" class="type-btn" data-type="office" data-base="9500">
|
||||
오피스 정기 케어
|
||||
</button>
|
||||
<button type="button" class="type-btn" data-type="premium" data-base="14500">
|
||||
하이엔드 준공 청소
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 평수 슬라이더 -->
|
||||
<div class="form-group">
|
||||
<div class="slider-header">
|
||||
<label class="form-label" for="pyeongSlider">공간 공급면적 (평형)</label>
|
||||
<span class="slider-val" id="pyeongValue">32 평 (약 105㎡)</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
id="pyeongSlider"
|
||||
class="range-input"
|
||||
min="12"
|
||||
max="75"
|
||||
value="32"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 특수 케어 옵션 -->
|
||||
<div class="form-group">
|
||||
<span class="form-label">정밀 특수 옵션</span>
|
||||
<div class="addon-grid">
|
||||
<label class="addon-label">
|
||||
<input type="checkbox" name="addon" value="steam" data-price="45000" checked />
|
||||
<span>160℃ 고온 살균 스팀 (+45,000원)</span>
|
||||
</label>
|
||||
<label class="addon-label">
|
||||
<input type="checkbox" name="addon" value="phytoncide" data-price="35000" checked />
|
||||
<span>편백 피톤치드 훈증 (+35,000원)</span>
|
||||
</label>
|
||||
<label class="addon-label">
|
||||
<input type="checkbox" name="addon" value="aircon" data-price="80000" />
|
||||
<span>시스템 에어컨 분해 (+80,000원)</span>
|
||||
</label>
|
||||
<label class="addon-label">
|
||||
<input type="checkbox" name="addon" value="glass" data-price="50000" />
|
||||
<span>외부 유리창 특수 발수 (+50,000원)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 예약 정보 입력 -->
|
||||
<div class="form-group" style="margin-top: 1.5rem;">
|
||||
<span class="form-label">신청자 정보</span>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 0.75rem;">
|
||||
<input
|
||||
type="text"
|
||||
id="clientName"
|
||||
placeholder="성함 / 고객명"
|
||||
style="width: 100%; min-width: 0; padding: 10px; border: 1px solid var(--line); border-radius: var(--radius-sm); font-size: var(--step--1);"
|
||||
value="이서연"
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="tel"
|
||||
id="clientPhone"
|
||||
placeholder="연락처 (010-0000-0000)"
|
||||
style="width: 100%; min-width: 0; padding: 10px; border: 1px solid var(--line); border-radius: var(--radius-sm); font-size: var(--step--1);"
|
||||
value="010-4821-9930"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
id="clientAddress"
|
||||
placeholder="케어 현장 주소 (예: 서울시 마포구 공덕동 120)"
|
||||
style="width: 100%; min-width: 0; margin-top: 0.5rem; padding: 10px; border: 1px solid var(--line); border-radius: var(--radius-sm); font-size: var(--step--1);"
|
||||
value="서울시 성동구 성수동2가 아크로포레스트 102동"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 요약 및 접수 CTA -->
|
||||
<div class="calc-summary">
|
||||
<h3 class="summary-title">실시간 견적 명세서</h3>
|
||||
<div class="summary-row">
|
||||
<span>선택 공간</span>
|
||||
<span id="sumSpaceType" class="mono">주거 입주/이사</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span>면적 기준</span>
|
||||
<span id="sumPyeong" class="mono">32평 (평당 11,000원)</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span>기본 케어비</span>
|
||||
<span id="sumBasePrice" class="mono">352,000원</span>
|
||||
</div>
|
||||
<div class="summary-row">
|
||||
<span>정밀 옵션 합계</span>
|
||||
<span id="sumAddonPrice" class="mono">80,000원</span>
|
||||
</div>
|
||||
<div class="summary-total">
|
||||
<span>총 예상 견적</span>
|
||||
<span class="total-amount" id="sumTotal">432,000원</span>
|
||||
</div>
|
||||
|
||||
<button type="button" class="calc-submit" id="btnSubmitQuote">
|
||||
이 견적으로 신청 접수하기
|
||||
</button>
|
||||
<p style="font-size: 12px; color: var(--ink-inverse-muted); margin-top: 10px; text-align: center;">
|
||||
✓ 접수 즉시 배차 팀장이 연락 후 사전 현장 조율을 진행합니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 6단계 위생 프로토콜 -->
|
||||
<section class="protocol-section" id="protocol" aria-labelledby="protoHeading">
|
||||
<div class="wrap">
|
||||
<div class="section-head" style="display: flex; justify-content: space-between; align-items: flex-end; flex-wrap: wrap; gap: 12px;">
|
||||
<div>
|
||||
<h2 id="protoHeading" class="section-title">임상 수준의 6단계 청온 케어 프로토콜</h2>
|
||||
<p class="section-sub">표면만 닦는 청소가 아닌, 미세 분진과 세균 번식의 원인을 제거하는 체계적인 과정입니다.</p>
|
||||
</div>
|
||||
<a href="./protocol/index.html" class="action-btn" style="text-decoration: none; padding: 10px 20px; font-size: 14px; background: var(--surface-card); color: var(--accent); border: 1px solid var(--accent);">
|
||||
나인원한남 ATP 측정 리포트 보기 →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="protocol-grid">
|
||||
<div class="protocol-card">
|
||||
<div class="protocol-num">STEP 01</div>
|
||||
<h3>건식 초미세 집진</h3>
|
||||
<p>H14 헤파 필터 흡진기로 벽면, 천장 몰딩, 바닥의 시공 미세분진 및 부유 입자를 99.97% 1차 포집합니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="protocol-card">
|
||||
<div class="protocol-num">STEP 02</div>
|
||||
<h3>160℃ 고온 스팀 살균</h3>
|
||||
<p>배수구, 욕실 타일 틈새, 주방 후드 기름때를 화학 세제 없이 4.0bar 고온 증기로 녹여 살균합니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="protocol-card">
|
||||
<div class="protocol-num">STEP 03</div>
|
||||
<h3>약알칼리 친환경 분해</h3>
|
||||
<p>에코서트(ECOCERT) 인증 천연 식물성 세정제를 도포하여 자재 손상 없이 찌든 때를 안전하게 중화합니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="protocol-card">
|
||||
<div class="protocol-num">STEP 04</div>
|
||||
<h3>서랍·후드 전면 탈거 세척</h3>
|
||||
<p>보이지 않는 싱크대 걸레받이, 전등갓, 수납장 서랍 레일을 전면 탈거하여 내측 분진을 완벽 제거합니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="protocol-card">
|
||||
<div class="protocol-num">STEP 05</div>
|
||||
<h3>편백 피톤치드 연무 훈증</h3>
|
||||
<p>순수 제주 편백 오일 연무로 벽지 속 새집증후군 원인 물질(포름알데히드, VOCs)을 중화하고 탈취합니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="protocol-card">
|
||||
<div class="protocol-num">STEP 06</div>
|
||||
<h3>32개 항목 마스터 검수</h3>
|
||||
<p>현장 팀장과 고객이 함께 32개 체크리스트를 1:1 대조하고, 미흡 지점 발생 시 즉시 재케어 후 인도합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 전문 장비 & Before/After -->
|
||||
<section class="equipment-section" id="equipment" aria-labelledby="equipHeading">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<h2 id="equipHeading" class="section-title">전문 위생 장비 및 검수 스펙</h2>
|
||||
<p class="section-sub">가정용 장비가 아닌 독일 카처 정품 산업용 위생 기기를 전 현장에 투입합니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="equip-grid">
|
||||
<div class="equip-specs">
|
||||
<div class="spec-item">
|
||||
<span class="spec-key">고온 스팀 압력</span>
|
||||
<span class="spec-val">Kärcher SG 4/4 (4.0 bar · 160℃)</span>
|
||||
</div>
|
||||
<div class="spec-item">
|
||||
<span class="spec-key">미세먼지 집진 등급</span>
|
||||
<span class="spec-val">HEPA H14 (0.3㎛ 99.995% 포집)</span>
|
||||
</div>
|
||||
<div class="spec-item">
|
||||
<span class="spec-key">사용 세제 인증</span>
|
||||
<span class="spec-val">ECOCERT 100% 생분해 식물성</span>
|
||||
</div>
|
||||
<div class="spec-item">
|
||||
<span class="spec-key">포름알데히드 저감</span>
|
||||
<span class="spec-val">한국화학융합시험연구원 인증 94.2%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ba-container">
|
||||
<img
|
||||
src="./assets/steam-qc.webp"
|
||||
alt="청온 케어 마스터 위생 장비와 정밀 세척 노즐"
|
||||
width="800"
|
||||
height="600"
|
||||
loading="lazy"
|
||||
/>
|
||||
<span class="ba-badge before">정밀 장비 규격</span>
|
||||
<span class="ba-badge after">QC 완결 보증</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- ===================================================================
|
||||
2. 관리자 관제 콘솔 모드 (Admin Dashboard Mockup)
|
||||
=================================================================== -->
|
||||
<section class="admin-view wrap" aria-label="청온 케어 관리자 콘솔">
|
||||
<div class="admin-header">
|
||||
<div>
|
||||
<div class="eyebrow" style="margin-bottom: 4px;">OPERATIONAL CONTROL CENTER</div>
|
||||
<h2 style="font-size: var(--step-2); font-weight: 800;">실시간 배차 및 현장 관제 현황</h2>
|
||||
</div>
|
||||
<button type="button" class="btn-primary" id="btnOpenQcModal">
|
||||
32개 현장 검수표 열기
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- KPI 통계 카드 -->
|
||||
<div class="admin-kpis">
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-label">오늘 신규 접수</div>
|
||||
<div class="kpi-val accent" id="kpiNewCount">6건</div>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-label">현재 현장 진행 중</div>
|
||||
<div class="kpi-val">4개 조</div>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-label">검수 대기 / 완료</div>
|
||||
<div class="kpi-val">2건</div>
|
||||
</div>
|
||||
<div class="kpi-card">
|
||||
<div class="kpi-label">오늘 견적 총액</div>
|
||||
<div class="kpi-val mono" id="kpiTotalRevenue">2,480,000원</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 실시간 접수 및 배차 원장 테이블 -->
|
||||
<div class="admin-table-card">
|
||||
<div class="table-header">
|
||||
<span class="table-title">실시간 예약 및 케어 원장 (Live Ledger)</span>
|
||||
<div class="table-filter-tabs">
|
||||
<button class="filter-tab is-active" data-filter="all">전체</button>
|
||||
<button class="filter-tab" data-filter="new">신규접수</button>
|
||||
<button class="filter-tab" data-filter="progress">진행중</button>
|
||||
<button class="filter-tab" data-filter="done">완료</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="overflow-x: auto;">
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>접수번호</th>
|
||||
<th>고객명 / 연락처</th>
|
||||
<th>공간 / 면적</th>
|
||||
<th>현장 주소</th>
|
||||
<th>견적액</th>
|
||||
<th>배정 팀장</th>
|
||||
<th>상태</th>
|
||||
<th>조치</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="adminTableBody">
|
||||
<tr>
|
||||
<td class="mono">#CO-2026-0819</td>
|
||||
<td><strong>이서연</strong><br /><span style="color:var(--ink-muted);font-size:11px;">010-4821-9930</span></td>
|
||||
<td>주거 입주 (32평)</td>
|
||||
<td>성동구 성수동 아크로포레스트</td>
|
||||
<td class="mono" style="font-weight:700;">432,000원</td>
|
||||
<td>김정온 마스터</td>
|
||||
<td><span class="status-pill new">신규 접수</span></td>
|
||||
<td><button class="action-btn" onclick="alert('배차 확인 알림톡이 고객님께 전송되었습니다.');">배차 확정</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="mono">#CO-2026-0818</td>
|
||||
<td><strong>박도현</strong><br /><span style="color:var(--ink-muted);font-size:11px;">010-9120-3341</span></td>
|
||||
<td>오피스 정기 (45평)</td>
|
||||
<td>강남구 테헤란로 142 위워크</td>
|
||||
<td class="mono" style="font-weight:700;">520,000원</td>
|
||||
<td>박준호 팀장 (2팀)</td>
|
||||
<td><span class="status-pill progress">스팀 케어 중</span></td>
|
||||
<td><button class="action-btn" onclick="document.getElementById('qcModal').showModal();">실시간 검수</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="mono">#CO-2026-0817</td>
|
||||
<td><strong>한지민</strong><br /><span style="color:var(--ink-muted);font-size:11px;">010-7712-4091</span></td>
|
||||
<td>하이엔드 준공 (58평)</td>
|
||||
<td>용산구 한남동 나인원한남</td>
|
||||
<td class="mono" style="font-weight:700;">841,000원</td>
|
||||
<td>최수진 닥터 (1팀)</td>
|
||||
<td><span class="status-pill done">검수 승인 완료</span></td>
|
||||
<td><button class="action-btn" onclick="alert('완료 검수 리포트가 PDF로 발행되었습니다.');">리포트 다운</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- 32개 항목 QC 검수 모달 다이얼로그 -->
|
||||
<dialog id="qcModal" class="qc-dialog" aria-labelledby="qcTitle">
|
||||
<div class="qc-head">
|
||||
<h3 id="qcTitle" style="font-size: var(--step-1); font-weight: 700;">32개 정밀 위생 검수 체크리스트</h3>
|
||||
<button type="button" onclick="document.getElementById('qcModal').close();" aria-label="닫기" style="font-size: 18px; font-weight: 700;">✕</button>
|
||||
</div>
|
||||
<ul class="qc-list">
|
||||
<li class="qc-item"><input type="checkbox" checked /> <span>01. 천장 몰딩 및 전등갓 상단 분진 흡진</span></li>
|
||||
<li class="qc-item"><input type="checkbox" checked /> <span>02. 창틀 상하좌우 틈새 시멘트 가루 및 찌든때 제거</span></li>
|
||||
<li class="qc-item"><input type="checkbox" checked /> <span>03. 싱크대 하부 걸레받이 전면 탈거 및 분진 집진</span></li>
|
||||
<li class="qc-item"><input type="checkbox" checked /> <span>04. 가스레인지/인덕션 상판 및 후드 필터 기름때 고온 스팀 분해</span></li>
|
||||
<li class="qc-item"><input type="checkbox" checked /> <span>05. 욕실 벽타일 메지 및 배수구 트랩 고온 살균 세척</span></li>
|
||||
<li class="qc-item"><input type="checkbox" checked /> <span>06. 수납장 모든 서랍 완전 탈거 후 레일 틈새 분진 청소</span></li>
|
||||
<li class="qc-item"><input type="checkbox" checked /> <span>07. 베란다 및 다용도실 바닥 타일 약알칼리 세정</span></li>
|
||||
<li class="qc-item"><input type="checkbox" /> <span>08. 전 실 편백 피톤치드 훈증 및 공기질 측정기 수치 확인</span></li>
|
||||
</ul>
|
||||
<div style="display: flex; justify-content: flex-end; gap: 8px;">
|
||||
<button type="button" class="action-btn" onclick="document.getElementById('qcModal').close();">닫기</button>
|
||||
<button type="button" class="btn-primary" style="padding: 6px 14px; font-size: 13px;" onclick="alert('검수 승인이 완료되었습니다.'); document.getElementById('qcModal').close();">최종 검수 서명 승인</button>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!-- 푸터 (.site-foot SSOT) -->
|
||||
<footer class="site-foot">
|
||||
<div class="wrap foot-inner">
|
||||
<p>청온 케어 · 서울 마포구 마포대로 109 청온랩 4층</p>
|
||||
<p class="muted">연중무휴 08:00 – 20:00 (사전 예약제)</p>
|
||||
<p class="muted">care@cheongon.kr</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- 인터랙티브 스크립트 -->
|
||||
<script>
|
||||
(function () {
|
||||
// 1. 뷰 모드 전환 (고객 뷰 vs 관리자 뷰)
|
||||
const btnClient = document.getElementById("btnModeClient");
|
||||
const btnAdmin = document.getElementById("btnModeAdmin");
|
||||
|
||||
function setViewMode(mode) {
|
||||
document.body.setAttribute("data-view", mode);
|
||||
if (mode === "admin") {
|
||||
btnAdmin.classList.add("is-active");
|
||||
btnClient.classList.remove("is-active");
|
||||
} else {
|
||||
btnClient.classList.add("is-active");
|
||||
btnAdmin.classList.remove("is-active");
|
||||
}
|
||||
}
|
||||
|
||||
btnClient.addEventListener("click", () => setViewMode("client"));
|
||||
btnAdmin.addEventListener("click", () => setViewMode("admin"));
|
||||
|
||||
// 단축키 Alt + A 로 관리자 모드 토글
|
||||
window.addEventListener("keydown", (e) => {
|
||||
if (e.altKey && (e.key === "a" || e.key === "A" || e.key === "ㅁ")) {
|
||||
const cur = document.body.getAttribute("data-view");
|
||||
setViewMode(cur === "admin" ? "client" : "admin");
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 견적 계산기 로직
|
||||
const pyeongSlider = document.getElementById("pyeongSlider");
|
||||
const pyeongValue = document.getElementById("pyeongValue");
|
||||
const sumPyeong = document.getElementById("sumPyeong");
|
||||
const sumBasePrice = document.getElementById("sumBasePrice");
|
||||
const sumAddonPrice = document.getElementById("sumAddonPrice");
|
||||
const sumTotal = document.getElementById("sumTotal");
|
||||
const sumSpaceType = document.getElementById("sumSpaceType");
|
||||
const typeBtns = document.querySelectorAll(".type-btn");
|
||||
const addonCheckboxes = document.querySelectorAll("input[name='addon']");
|
||||
|
||||
let currentBaseRate = 11000;
|
||||
let currentTypeLabel = "주거 입주/이사";
|
||||
|
||||
function updateQuote() {
|
||||
const pyeong = parseInt(pyeongSlider.value, 10);
|
||||
const sqm = Math.round(pyeong * 3.30578);
|
||||
pyeongValue.textContent = `${pyeong} 평 (약 ${sqm}㎡)`;
|
||||
sumPyeong.textContent = `${pyeong}평 (평당 ${currentBaseRate.toLocaleString()}원)`;
|
||||
sumSpaceType.textContent = currentTypeLabel;
|
||||
|
||||
const baseCost = pyeong * currentBaseRate;
|
||||
sumBasePrice.textContent = `${baseCost.toLocaleString()}원`;
|
||||
|
||||
let addonCost = 0;
|
||||
addonCheckboxes.forEach((cb) => {
|
||||
if (cb.checked) {
|
||||
addonCost += parseInt(cb.getAttribute("data-price"), 10);
|
||||
}
|
||||
});
|
||||
sumAddonPrice.textContent = `${addonCost.toLocaleString()}원`;
|
||||
|
||||
const total = baseCost + addonCost;
|
||||
sumTotal.textContent = `${total.toLocaleString()}원`;
|
||||
}
|
||||
|
||||
pyeongSlider.addEventListener("input", updateQuote);
|
||||
|
||||
typeBtns.forEach((btn) => {
|
||||
btn.addEventListener("click", () => {
|
||||
typeBtns.forEach((b) => b.classList.remove("is-active"));
|
||||
btn.classList.add("is-active");
|
||||
currentBaseRate = parseInt(btn.getAttribute("data-base"), 10);
|
||||
currentTypeLabel = btn.textContent.trim();
|
||||
updateQuote();
|
||||
});
|
||||
});
|
||||
|
||||
addonCheckboxes.forEach((cb) => {
|
||||
cb.addEventListener("change", updateQuote);
|
||||
});
|
||||
|
||||
// 초기 계산 1회 실행
|
||||
updateQuote();
|
||||
|
||||
// 3. 견적 신청 버튼 클릭 -> 관리자 원장에 즉시 추가되는 풀-루프 인터랙션!
|
||||
const btnSubmit = document.getElementById("btnSubmitQuote");
|
||||
const tableBody = document.getElementById("adminTableBody");
|
||||
const kpiNewCount = document.getElementById("kpiNewCount");
|
||||
let submissionCount = 6;
|
||||
|
||||
btnSubmit.addEventListener("click", () => {
|
||||
const name = document.getElementById("clientName").value || "고객님";
|
||||
const phone = document.getElementById("clientPhone").value || "010-0000-0000";
|
||||
const address = document.getElementById("clientAddress").value || "서울시 현장 주소";
|
||||
const pyeong = pyeongSlider.value;
|
||||
const totalStr = sumTotal.textContent;
|
||||
|
||||
submissionCount++;
|
||||
kpiNewCount.textContent = `${submissionCount}건`;
|
||||
|
||||
// 새 행을 관리자 테이블 최상단에 삽입
|
||||
const newRow = document.createElement("tr");
|
||||
newRow.style.backgroundColor = "var(--accent-light)";
|
||||
newRow.innerHTML = `
|
||||
<td class="mono">#CO-2026-082${submissionCount}</td>
|
||||
<td><strong>${name}</strong><br /><span style="color:var(--ink-muted);font-size:11px;">${phone}</span></td>
|
||||
<td>${currentTypeLabel} (${pyeong}평)</td>
|
||||
<td>${address}</td>
|
||||
<td class="mono" style="font-weight:700;color:var(--accent);">${totalStr}</td>
|
||||
<td>배차 지정 대기</td>
|
||||
<td><span class="status-pill new">방금 접수됨</span></td>
|
||||
<td><button class="action-btn" onclick="alert('배차 팀장을 매칭 중입니다.');">배차 지정</button></td>
|
||||
`;
|
||||
tableBody.insertBefore(newRow, tableBody.firstChild);
|
||||
|
||||
alert(`[청온 케어] ${name}님의 견적(${totalStr}) 신청이 성공적으로 접수되었습니다.\n관리자 콘솔에 실시간 등록되었습니다.`);
|
||||
});
|
||||
|
||||
// 모달 열기
|
||||
const btnOpenQc = document.getElementById("btnOpenQcModal");
|
||||
const qcModal = document.getElementById("qcModal");
|
||||
if (btnOpenQc && qcModal) {
|
||||
btnOpenQc.addEventListener("click", () => qcModal.showModal());
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
346
apps/site/public/work/cheongon-care/protocol/index.html
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>임상 6단계 위생 프로토콜 & 한남 케이스 리포트 — 청온 케어 (淸溫)</title>
|
||||
<meta name="description" content="청온 케어의 병원급 6단계 정밀 위생 프로토콜 및 ATP 생체 오염도 측정 검증 리포트. 나인원한남 86평형 준공 청소 케이스 스터디 및 32개 정밀 QC 체크리스트." />
|
||||
|
||||
<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;700&display=swap"
|
||||
/>
|
||||
<link rel="stylesheet" href="../styles/tokens.css" />
|
||||
<link rel="stylesheet" href="../styles/main.css" />
|
||||
<style>
|
||||
.breadcrumb-bar {
|
||||
padding-top: var(--space-4);
|
||||
padding-bottom: var(--space-3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.breadcrumb-bar a {
|
||||
color: var(--ink-muted);
|
||||
text-decoration: none;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
.breadcrumb-bar a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
.breadcrumb-bar .sep {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.breadcrumb-bar .current {
|
||||
color: var(--ink);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.protocol-hero {
|
||||
padding: var(--space-7) 0 var(--space-5);
|
||||
}
|
||||
.protocol-meta-strip {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: var(--space-3);
|
||||
margin-top: var(--space-5);
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-4);
|
||||
}
|
||||
.protocol-meta-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.protocol-meta-item .label {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.protocol-meta-item .value {
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.atp-compare-box {
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-5);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--space-4);
|
||||
text-align: center;
|
||||
}
|
||||
.atp-val {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step-3);
|
||||
font-weight: 800;
|
||||
}
|
||||
.atp-val.before {
|
||||
color: #ef4444;
|
||||
}
|
||||
.atp-val.after {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.step-deep-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
margin-top: var(--space-5);
|
||||
}
|
||||
.step-deep-item {
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-5);
|
||||
display: grid;
|
||||
grid-template-columns: 120px 1fr;
|
||||
gap: var(--space-5);
|
||||
align-items: start;
|
||||
}
|
||||
@media (max-width: 680px) {
|
||||
.step-deep-item {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Top Nav (GNB SSOT) -->
|
||||
<header class="site-head">
|
||||
<div class="wrap head-inner">
|
||||
<a href="../index.html" class="wordmark" aria-label="청온 케어 홈">
|
||||
<span class="wordmark-badge">淸</span>
|
||||
청온 케어 <span class="wordmark-han">淸溫</span>
|
||||
</a>
|
||||
<nav class="nav" aria-label="메인 내비게이션">
|
||||
<a href="./index.html" class="active" style="color: var(--accent); font-weight: 600;">6단계 프로토콜</a>
|
||||
<a href="../index.html#services">케어 솔루션</a>
|
||||
<a href="../index.html#calculator">정찰제 견적</a>
|
||||
<a href="../index.html#equipment">전문 장비</a>
|
||||
</nav>
|
||||
<div class="head-actions">
|
||||
<a href="../index.html#calculator" class="btn">간편 견적</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="main-content">
|
||||
<!-- Hero Header -->
|
||||
<section class="section protocol-hero" style="border-top: none; padding-top: var(--space-5);">
|
||||
<div class="wrap">
|
||||
<div class="breadcrumb-bar" style="margin-bottom: var(--space-4); display: flex; align-items: center; gap: var(--space-2); font-family: var(--font-mono); font-size: 12px; color: var(--ink-muted); letter-spacing: 0.04em;">
|
||||
<a href="../index.html">CHEONG-ON CARE</a>
|
||||
<span class="sep">/</span>
|
||||
<span class="current" style="color: var(--ink); font-weight: 600;">CLINICAL HYGIENE PROTOCOL & CASE STUDY</span>
|
||||
</div>
|
||||
|
||||
<div class="protocol-hero-head">
|
||||
<p class="hero-label">HOSPITAL-GRADE SANITATION STANDARDS</p>
|
||||
<h1 class="hero-title" style="margin-bottom: var(--space-2);">단순한 청소를 넘어<br /><span style="color: var(--accent);">병원급 6단계 임상 위생 프로토콜</span></h1>
|
||||
<p class="hero-lead" style="font-size: var(--step-0); color: var(--ink-muted); max-width: var(--measure); margin-bottom: var(--space-5);">
|
||||
독일 카처 산업용 스팀과 H14 헤파 필터 흡진, ATP 생체 오염도 계측을 통해 인체에 무해한 안심 공간을 과학적으로 보증합니다.
|
||||
</p>
|
||||
|
||||
<dl class="protocol-specs" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-4); background: var(--surface-card); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-4) var(--space-5); margin-bottom: var(--space-6);">
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">Steam Temp</dt>
|
||||
<dd class="spec-val" style="font-size: var(--step-0); font-weight: 800; color: var(--ink);">160℃ High-Temp</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">Filtration</dt>
|
||||
<dd class="spec-val" style="font-size: var(--step-0); font-weight: 800; color: var(--ink);">0.3㎛ HEPA H14 (99.995%)</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">Detergent</dt>
|
||||
<dd class="spec-val" style="font-size: var(--step-0); font-weight: 800; color: var(--ink);">ECOCERT 100% 식물성</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">QC Points</dt>
|
||||
<dd class="spec-val" style="font-size: var(--step-0); font-weight: 800; color: var(--ink);">32개 정밀 항목</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<figure class="hero-photo" style="border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--surface-card);">
|
||||
<img
|
||||
src="../assets/clean-hero.webp"
|
||||
alt="완벽하게 정돈되고 살균된 프리미엄 주거 인테리어 공간"
|
||||
width="1600"
|
||||
height="900"
|
||||
style="width: 100%; aspect-ratio: 16/9; object-fit: cover;"
|
||||
/>
|
||||
<figcaption style="padding: 10px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--ink-muted); border-top: 1px solid var(--line); background: var(--surface-raised);">
|
||||
나인원한남 86평형 · 6단계 정밀 프로토콜 시공 완료
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ATP Measurement Case Report -->
|
||||
<section class="wrap" style="padding-bottom: var(--space-8);">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--space-8); align-items: center;">
|
||||
<div class="frame">
|
||||
<img
|
||||
src="../assets/atp-tester.webp"
|
||||
alt="ATP 생체 오염도 측정기 계측 화면 (12 RLU)"
|
||||
style="width: 100%; display: block;"
|
||||
/>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: var(--space-4);">
|
||||
<div class="eyebrow">SCIENTIFIC DATA VERIFICATION</div>
|
||||
<h2 style="font-size: var(--step-2); font-weight: 800; line-height: 1.25;">
|
||||
나인원한남 86평형<br />
|
||||
<span style="color: var(--accent);">ATP 생체 오염도 99.1% 저감 리포트</span>
|
||||
</h2>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); line-height: 1.7;">
|
||||
실제 한남동 나인원한남 입주 청소 현장에서 주방 싱크대 상판 및 욕실 수전 부위의 미생물 오염도(ATP RLU)를 측정한 결과입니다.
|
||||
160℃ 고온 스팀과 에코서트 효소 분해 세정 후 병원 무균실 기준(30 RLU 이하)을 상회하는 12 RLU 수준으로 완벽하게 저감되었습니다.
|
||||
</p>
|
||||
|
||||
<div class="atp-compare-box">
|
||||
<div>
|
||||
<div style="font-family: var(--font-mono); font-size: var(--step--1); color: var(--ink-muted); margin-bottom: 4px;">시공 전 (BEFORE)</div>
|
||||
<div class="atp-val before">1,420 <span style="font-size: 14px;">RLU</span></div>
|
||||
<div style="font-size: 12px; color: #ef4444; margin-top: 4px;">심각한 미세 세균 번식</div>
|
||||
</div>
|
||||
<div style="border-left: 1px solid var(--line);">
|
||||
<div style="font-family: var(--font-mono); font-size: var(--step--1); color: var(--ink-muted); margin-bottom: 4px;">시공 후 (AFTER)</div>
|
||||
<div class="atp-val after">12 <span style="font-size: 14px;">RLU</span></div>
|
||||
<div style="font-size: 12px; color: var(--accent); margin-top: 4px;">병원 수술실 기준 패스 (99.1% 저감)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 6-Stage Deep Steps -->
|
||||
<section class="wrap" style="padding-bottom: var(--space-8);">
|
||||
<div class="eyebrow" style="text-align: center;">STEP-BY-STEP ENGINEERING</div>
|
||||
<h2 style="font-size: var(--step-3); font-weight: 800; text-align: center; margin-top: 6px;">
|
||||
청온 케어 임상 6단계 시공 체계
|
||||
</h2>
|
||||
|
||||
<div class="step-deep-list">
|
||||
<div class="step-deep-item">
|
||||
<div style="font-family: var(--font-mono); font-size: var(--step-2); font-weight: 800; color: var(--accent);">STEP 01</div>
|
||||
<div>
|
||||
<h3 style="font-size: var(--step-1); font-weight: 700;">H14 헤파 필터 건식 초미세 흡진</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-top: 6px; line-height: 1.6;">
|
||||
벽면 실크벽지 미세 분진, 천장 우물 몰딩, 조명 레일 내부의 0.3㎛ 부유 입자를 99.995% 집진하여 공기 중 재비산을 완벽 차단합니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-deep-item">
|
||||
<div style="font-family: var(--font-mono); font-size: var(--step-2); font-weight: 800; color: var(--accent);">STEP 02</div>
|
||||
<div>
|
||||
<h3 style="font-size: var(--step-1); font-weight: 700;">160℃ 4.0bar 고온 스팀 살균</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-top: 6px; line-height: 1.6;">
|
||||
배수구 유가, 변기 틈새, 주방 후드 필터에 화학 세제 없이 4.0bar 고압 증기를 분사하여 기름때를 녹이고 99.9% 멸균합니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-deep-item">
|
||||
<div style="font-family: var(--font-mono); font-size: var(--step-2); font-weight: 800; color: var(--accent);">STEP 03</div>
|
||||
<div>
|
||||
<h3 style="font-size: var(--step-1); font-weight: 700;">약알칼리 에코서트 친환경 효소 분해</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-top: 6px; line-height: 1.6;">
|
||||
원목 마루 및 천연 대리석 자재에 손상을 주지 않는 100% 생분해성 식물 세정제를 도포하여 찌든 산화 피막을 안전하게 중화합니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-deep-item">
|
||||
<div style="font-family: var(--font-mono); font-size: var(--step-2); font-weight: 800; color: var(--accent);">STEP 04</div>
|
||||
<div>
|
||||
<h3 style="font-size: var(--step-1); font-weight: 700;">서랍장·걸레받이 전면 탈거 정밀 세척</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-top: 6px; line-height: 1.6;">
|
||||
싱크대 하부 걸레받이와 수납장 레일을 전량 분리 탈거하여, 보이지 않는 시공 톱밥 및 유해 분진을 내측까지 완전 제거합니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-deep-item">
|
||||
<div style="font-family: var(--font-mono); font-size: var(--step-2); font-weight: 800; color: var(--accent);">STEP 05</div>
|
||||
<div>
|
||||
<h3 style="font-size: var(--step-1); font-weight: 700;">제주 편백 피톤치드 연무 훈증</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-top: 6px; line-height: 1.6;">
|
||||
새집증후군 유발 물질인 포름알데히드 및 휘발성유기화합물(VOCs)을 중화하고 실내 숲속 공기질을 복원합니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-deep-item">
|
||||
<div style="font-family: var(--font-mono); font-size: var(--step-2); font-weight: 800; color: var(--accent);">STEP 06</div>
|
||||
<div>
|
||||
<h3 style="font-size: var(--step-1); font-weight: 700;">32개 항목 마스터 닥터 1:1 검수 및 디지털 인증</h3>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin-top: 6px; line-height: 1.6;">
|
||||
배차 현장 팀장과 고객이 함께 32개 정밀 체크리스트를 1:1 대조하고, 모바일 리포트를 발행하여 최종 승인합니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Steam QC Equipment Spec Strip -->
|
||||
<div class="wrap" style="margin-bottom: var(--space-8);">
|
||||
<div class="frame">
|
||||
<img
|
||||
src="../assets/steam-qc.webp"
|
||||
alt="독일 카처 4.0bar 정밀 스팀 위생 장비와 멸균 키트"
|
||||
style="width: 100%; display: block; aspect-ratio: 16/9; object-fit: cover;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick CTA -->
|
||||
<section class="wrap" style="padding-bottom: var(--space-8); text-align: center;">
|
||||
<div class="card" style="max-width: 640px; margin: 0 auto; background: var(--surface-card);">
|
||||
<div class="eyebrow" style="color: var(--accent);">TRANSPARENT PRICING</div>
|
||||
<h2 style="font-size: var(--step-2); font-weight: 800; margin-top: 4px;">
|
||||
우리 집 공간의 정찰제 견적을 확인하세요
|
||||
</h2>
|
||||
<p style="font-size: var(--step--1); color: var(--ink-muted); margin: 12px 0 24px;">
|
||||
추가금 없는 평당 11,000원 명확한 기준. 1분 만에 실시간 견적 산출이 가능합니다.
|
||||
</p>
|
||||
<a href="../index.html#quote" class="btn-primary" style="display: inline-block; padding: 14px 28px; text-decoration: none; font-size: var(--step-0);">
|
||||
실시간 정찰제 견적 계산하기 →
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- 푸터 (.site-foot SSOT) -->
|
||||
<footer class="site-foot">
|
||||
<div class="wrap foot-inner">
|
||||
<p>청온 케어 · 서울 마포구 마포대로 109 청온랩 4층</p>
|
||||
<p class="muted">연중무휴 08:00 – 20:00 (사전 예약제)</p>
|
||||
<p class="muted">care@cheongon.kr</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
926
apps/site/public/work/cheongon-care/styles/main.css
Normal file
|
|
@ -0,0 +1,926 @@
|
|||
@import "./tokens.css";
|
||||
|
||||
/* ==========================================================================
|
||||
청온 케어 (CHEONG-ON CARE · 淸溫) — 메인 스타일시트 SSOT
|
||||
프리셋: clinical-sanitation + transparent-calculator + high-end-visual-design
|
||||
========================================================================== */
|
||||
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
scroll-behavior: smooth;
|
||||
background-color: var(--surface);
|
||||
color: var(--ink);
|
||||
font-family: var(--font-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100dvh;
|
||||
line-height: var(--leading-normal);
|
||||
overflow-x: hidden;
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: color var(--dur-fast);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
button, input, select, textarea {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.wrap {
|
||||
width: min(100% - 2 * var(--pad-inline), var(--container));
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* ── 접근성 스킵 링크 ── */
|
||||
.skip-link {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
z-index: 1000;
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--surface-inverse);
|
||||
color: var(--ink-inverse);
|
||||
border-radius: var(--radius-sm);
|
||||
transform: translateY(-200%);
|
||||
transition: transform var(--dur-fast);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
.skip-link:focus {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* ── 헤더 & 뷰 모드 스위처 (GNB SSOT) ── */
|
||||
.site-head {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
background: rgba(248, 250, 249, 0.94);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border-bottom: 1px solid var(--line);
|
||||
padding-block: var(--space-3);
|
||||
}
|
||||
|
||||
.head-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.wordmark {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-size: var(--step-1);
|
||||
font-weight: 800;
|
||||
color: var(--ink);
|
||||
text-decoration: none;
|
||||
letter-spacing: -0.02em;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.wordmark-badge {
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--radius-xs);
|
||||
}
|
||||
|
||||
.wordmark-han {
|
||||
font-size: var(--step--1);
|
||||
color: var(--accent);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-5);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
text-decoration: none;
|
||||
color: var(--ink-muted);
|
||||
font-size: var(--step--1);
|
||||
font-weight: 500;
|
||||
transition: color var(--dur-fast);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav a:hover,
|
||||
.nav a.active {
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.head-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
flex-shrink: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.mode-toggle {
|
||||
display: inline-flex;
|
||||
background: var(--surface-subtle);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 2px;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.mode-btn {
|
||||
padding: 4px 10px;
|
||||
border-radius: calc(var(--radius-sm) - 2px);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--ink-muted);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
transition: all var(--dur-fast);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mode-btn.is-active {
|
||||
background: var(--surface-raised);
|
||||
color: var(--ink);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.mode-btn .badge-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #10b981;
|
||||
}
|
||||
|
||||
.head-actions .btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: var(--step--1);
|
||||
padding: 6px 14px;
|
||||
border-radius: var(--radius-xs);
|
||||
transition: opacity var(--dur-fast);
|
||||
}
|
||||
|
||||
.head-actions .btn:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* ── 버튼 시스템 & 뱃지 ── */
|
||||
.btn-primary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
background: var(--accent);
|
||||
color: #ffffff;
|
||||
padding: 10px 20px;
|
||||
border-radius: var(--radius-sm);
|
||||
font-weight: 700;
|
||||
font-size: var(--step--1);
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
transition: transform var(--dur-fast), background var(--dur-fast);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--accent-hover);
|
||||
color: #ffffff;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
border: 1px solid var(--line);
|
||||
padding: 10px 18px;
|
||||
border-radius: var(--radius-sm);
|
||||
font-weight: 600;
|
||||
font-size: var(--step--1);
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
transition: border-color var(--dur-fast), color var(--dur-fast);
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 3px 10px;
|
||||
border-radius: var(--radius-xs);
|
||||
background: var(--accent-light);
|
||||
color: var(--accent);
|
||||
font-size: 11px;
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.06em;
|
||||
margin-bottom: var(--space-3);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* ── 히어로 섹션 ── */
|
||||
.hero-section {
|
||||
padding-block: var(--space-7);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.95fr);
|
||||
gap: var(--space-7);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: clamp(2.4rem, 1.8rem + 2.2vw, 3.8rem);
|
||||
font-weight: 800;
|
||||
line-height: 1.18;
|
||||
letter-spacing: -0.035em;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-4);
|
||||
text-wrap: balance;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-title em {
|
||||
font-style: normal;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.hero-desc {
|
||||
font-size: clamp(1.05rem, 0.98rem + 0.35vw, 1.2rem);
|
||||
color: var(--ink-muted);
|
||||
max-width: 48ch;
|
||||
line-height: 1.75;
|
||||
margin-bottom: var(--space-5);
|
||||
text-wrap: pretty;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-ctas {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.hero-trust {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.hero-trust-stars {
|
||||
color: #f59e0b;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.hero-visual {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bezel-outer {
|
||||
background: rgba(15, 118, 110, 0.05);
|
||||
border: 1px solid var(--line);
|
||||
padding: 6px;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.hero-frame {
|
||||
border-radius: calc(var(--radius-md) - 4px);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--line);
|
||||
box-shadow: 0 16px 40px -12px rgba(0, 0, 0, 0.08);
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.hero-frame img {
|
||||
width: 100%;
|
||||
aspect-ratio: 4/3;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hero-stat-floating {
|
||||
position: absolute;
|
||||
bottom: -14px;
|
||||
left: 16px;
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 8px 14px;
|
||||
box-shadow: 0 8px 24px -4px rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
/* ── 투명 정찰제 실시간 견적 산정 섹션 ── */
|
||||
.calculator-section {
|
||||
padding-block: var(--space-8);
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.section-head {
|
||||
text-align: center;
|
||||
max-width: 680px;
|
||||
margin-inline: auto;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: clamp(1.8rem, 1.4rem + 1.2vw, 2.25rem);
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.025em;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-2);
|
||||
text-wrap: balance;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.section-sub {
|
||||
font-size: var(--step-0);
|
||||
color: var(--ink-muted);
|
||||
line-height: 1.6;
|
||||
text-wrap: pretty;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.calc-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
|
||||
gap: var(--space-5);
|
||||
align-items: start;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.calc-card {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-5);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: var(--step--1);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-2);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.type-selector {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: var(--space-2);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.type-btn {
|
||||
padding: 10px 8px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--surface);
|
||||
color: var(--ink-muted);
|
||||
font-weight: 600;
|
||||
font-size: var(--step--1);
|
||||
text-align: center;
|
||||
transition: all var(--dur-fast);
|
||||
white-space: normal;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.type-btn.is-active {
|
||||
border-color: var(--accent);
|
||||
background: var(--accent-light);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.slider-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.slider-value {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step-1);
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.range-slider {
|
||||
width: 100%;
|
||||
accent-color: var(--accent);
|
||||
height: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.addon-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: var(--space-2);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.addon-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--surface);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
cursor: pointer;
|
||||
transition: all var(--dur-fast);
|
||||
}
|
||||
|
||||
.addon-label:has(input:checked) {
|
||||
border-color: var(--accent);
|
||||
background: var(--accent-light);
|
||||
color: var(--ink);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 실시간 견적 영수증 요약 패널 */
|
||||
.calc-summary {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-5);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.summary-title {
|
||||
font-size: var(--step-1);
|
||||
font-weight: 700;
|
||||
margin-bottom: var(--space-4);
|
||||
padding-bottom: var(--space-2);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.summary-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--space-2);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.summary-row .mono {
|
||||
color: var(--ink);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.summary-total {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
padding-top: var(--space-3);
|
||||
border-top: 1px solid var(--line);
|
||||
margin-block: var(--space-4) var(--space-5);
|
||||
}
|
||||
|
||||
.summary-total span:first-child {
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.summary-total .total-amount {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step-2);
|
||||
font-weight: 800;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.calc-submit {
|
||||
width: 100%;
|
||||
padding: 14px;
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: var(--step-0);
|
||||
border-radius: var(--radius-sm);
|
||||
transition: background var(--dur-fast);
|
||||
}
|
||||
|
||||
.calc-submit:hover {
|
||||
background: var(--accent-hover);
|
||||
}
|
||||
|
||||
/* ── 6단계 위생 프로토콜 섹션 ── */
|
||||
.protocol-section {
|
||||
padding-block: var(--space-8);
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.protocol-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.protocol-card {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-5);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.protocol-num {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.protocol-card h3 {
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.protocol-card p {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* ── 전문 장비 & Before/After 섹션 ── */
|
||||
.equipment-section {
|
||||
padding-block: var(--space-8);
|
||||
border-top: 1px solid var(--line);
|
||||
background: var(--surface-card);
|
||||
}
|
||||
|
||||
.equip-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
gap: var(--space-6);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.equip-specs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.spec-item {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.spec-key {
|
||||
font-size: var(--step--1);
|
||||
font-weight: 600;
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.spec-val {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.ba-container {
|
||||
position: relative;
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--line);
|
||||
box-shadow: 0 12px 32px -8px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.ba-container img {
|
||||
width: 100%;
|
||||
aspect-ratio: 4/3;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ba-badge {
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
padding: 4px 10px;
|
||||
border-radius: var(--radius-xs);
|
||||
font-size: 11px;
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.ba-badge.before {
|
||||
left: 12px;
|
||||
background: rgba(15, 23, 42, 0.85);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ba-badge.after {
|
||||
right: 12px;
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ===================================================================
|
||||
2. 관리자 관제 콘솔 뷰 (Admin Console View)
|
||||
=================================================================== */
|
||||
.admin-view {
|
||||
display: none;
|
||||
padding-block: var(--space-6) var(--space-8);
|
||||
}
|
||||
|
||||
[data-view="admin"] .client-view { display: none; }
|
||||
[data-view="admin"] .admin-view { display: block; }
|
||||
|
||||
.admin-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
margin-bottom: var(--space-5);
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.admin-kpis {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: var(--space-3);
|
||||
margin-bottom: var(--space-5);
|
||||
}
|
||||
|
||||
.kpi-card {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-4);
|
||||
}
|
||||
|
||||
.kpi-label {
|
||||
font-size: 12px;
|
||||
color: var(--ink-muted);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.kpi-val {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step-2);
|
||||
font-weight: 800;
|
||||
color: var(--ink);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.kpi-val.accent {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.admin-table-card {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: var(--surface-card);
|
||||
}
|
||||
|
||||
.table-title {
|
||||
font-size: var(--step--1);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.table-filter-tabs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.filter-tab {
|
||||
padding: 3px 8px;
|
||||
border-radius: var(--radius-xs);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.filter-tab.is-active {
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.admin-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.admin-table th {
|
||||
background: var(--surface-card);
|
||||
padding: 10px 14px;
|
||||
font-weight: 600;
|
||||
color: var(--ink-muted);
|
||||
border-bottom: 1px solid var(--line);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.admin-table td {
|
||||
padding: 12px 14px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.status-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--radius-xs);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.status-pill.new { background: #fef3c7; color: #92400e; }
|
||||
.status-pill.progress { background: #ccfbf1; color: #0f766e; }
|
||||
.status-pill.done { background: #dbeafe; color: #1e40af; }
|
||||
|
||||
.action-btn {
|
||||
padding: 4px 10px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-xs);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: var(--surface);
|
||||
cursor: pointer;
|
||||
transition: all var(--dur-fast);
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── 32개 QC 모달 다이얼로그 ── */
|
||||
.qc-dialog {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
margin: auto;
|
||||
width: min(90vw, 560px);
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-5);
|
||||
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.15);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.qc-dialog::backdrop {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
/* ── 푸터 (SSOT 정본) ── */
|
||||
.site-foot {
|
||||
border-top: 1px solid var(--line);
|
||||
padding-block: var(--space-6);
|
||||
background: var(--surface);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.foot-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
/* ── 반응형 미디어 쿼리 ── */
|
||||
@media (max-width: 860px) {
|
||||
.nav {
|
||||
display: none;
|
||||
}
|
||||
.hero-grid, .calc-grid, .equip-grid, .protocol-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
.admin-kpis {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.type-selector, .addon-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.admin-kpis {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.wordmark-han {
|
||||
display: none;
|
||||
}
|
||||
.mode-btn {
|
||||
padding: 3px 6px;
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
73
apps/site/public/work/cheongon-care/styles/tokens.css
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/* ==========================================================================
|
||||
청온 케어 (淸溫 · CHEONG-ON CARE) — 디자인 토큰 SSOT
|
||||
프리셋: ledger-console + swiss-minimal
|
||||
컨셉: 임상 수준의 위생 프로토콜과 정직한 정찰제 — 공간의 숨결을 되돌리는 케어
|
||||
단일 강조색: 에메랄드 틸 (#0D9488)
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
/* 타이포그래피 스케일 */
|
||||
--step--1: 0.8125rem; /* 13px — 캡션·태그 */
|
||||
--step-0: 1rem; /* 16px — 본문 */
|
||||
--step-1: 1.1875rem; /* 19px — 소제목 */
|
||||
--step-2: clamp(1.375rem, 1.2rem + 0.9vw, 1.875rem); /* 30px — 섹션 헤딩 */
|
||||
--step-3: clamp(2.25rem, 1.5rem + 3vw, 3.8rem); /* 60px — 메인 디스플레이 */
|
||||
|
||||
--leading-tight: 1.2;
|
||||
--leading-normal: 1.7;
|
||||
--measure: 58ch;
|
||||
|
||||
--font-serif: "MaruBuri", "Noto Serif KR", serif;
|
||||
--font-display: "Pretendard Variable", Pretendard, -apple-system, sans-serif;
|
||||
--font-body: "Pretendard Variable", Pretendard, -apple-system, sans-serif;
|
||||
--font-mono: "JetBrains Mono", monospace;
|
||||
|
||||
/* 색상 — 클린 퓨어 화이트 & 딥 슬레이트 + 에메랄드 틸 1강조색 */
|
||||
--surface: #f8faf9;
|
||||
--surface-raised: #ffffff;
|
||||
--surface-card: #f0f4f2;
|
||||
--surface-subtle: #e6ede9;
|
||||
--surface-sunken: #e2e9e5;
|
||||
--surface-inverse: #0f172a;
|
||||
|
||||
--ink: #0f172a;
|
||||
--ink-muted: #475569;
|
||||
--ink-faint: #94a3b8;
|
||||
--ink-inverse: #f8faf9;
|
||||
--ink-inverse-muted: #cbd5e1;
|
||||
|
||||
--line: #e2e8e5;
|
||||
--line-strong: #cbd5e1;
|
||||
--line-subtle: #edf2ef;
|
||||
--line-inverse: #334155;
|
||||
|
||||
/* 단일 강조색 (에메랄드 틸) */
|
||||
--accent: #0d9488;
|
||||
--accent-hover: #0f766e;
|
||||
--accent-light: #f0fdfa;
|
||||
--accent-surface: #ccfbf1;
|
||||
--accent-ink: #ffffff;
|
||||
|
||||
--radius: 2px;
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 8px;
|
||||
|
||||
/* 간격 — SSOT 표준 */
|
||||
--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);
|
||||
|
||||
/* 컨테이너 및 패딩 — 전체 쇼케이스 절대 통일 SSOT */
|
||||
--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);
|
||||
}
|
||||
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 179 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 179 KiB |
|
After Width: | Height: | Size: 170 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 205 KiB |
|
After Width: | Height: | Size: 160 KiB |
14
apps/site/public/work/materia-interior/hannam-duplex.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="refresh" content="0; url=./projects/hannam-duplex/index.html" />
|
||||
<title>한남 듀플렉스 펜트하우스 이동 중...</title>
|
||||
<script>
|
||||
window.location.replace("./projects/hannam-duplex/index.html");
|
||||
</script>
|
||||
</head>
|
||||
<body style="background: #0d0d0f; color: #f4f4f0; font-family: sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0;">
|
||||
<p>한남 듀플렉스 펜트하우스 갤러리로 이동 중입니다... <a href="./projects/hannam-duplex/index.html" style="color: #c49d68;">직접 이동하기</a></p>
|
||||
</body>
|
||||
</html>
|
||||
430
apps/site/public/work/materia-interior/index.html
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>마테리아 스튜디오 (MATERIA) · 하이엔드 주거 & 상업 공간 인테리어 건축</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="트래버틴 대리석, 훈증 오크, 벨기에 리넨의 촉각적 물성과 자연광의 궤적을 설계하는 하이엔드 인테리어 건축 아틀리에. 한남·청담 펜트하우스 및 프라이빗 갤러리 비스포크 설계."
|
||||
/>
|
||||
<meta property="og:title" content="마테리아 스튜디오 (MATERIA) · 하이엔드 인테리어 건축" />
|
||||
<meta property="og:description" content="빛과 트래버틴이 빚어내는 침묵의 공간 건축. 1:1 비스포크 공간 컨설팅." />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta name="theme-color" content="#f5f3ef" />
|
||||
|
||||
<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;700&display=swap"
|
||||
/>
|
||||
<link rel="stylesheet" href="./styles/main.css?v=1" />
|
||||
<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='%23F5F3EF'/%3E%3Crect x='6' y='6' width='20' height='20' stroke='%23161514' stroke-width='2' fill='none'/%3E%3Crect x='12' y='12' width='8' height='8' fill='%239E8062'/%3E%3C/svg%3E"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body data-ambiance="day">
|
||||
<a class="skip-link" href="#mainContent">본문으로 건너뛰기</a>
|
||||
|
||||
<!-- 상단 헤더 & 조도 스위처 -->
|
||||
<header class="site-head">
|
||||
<div class="wrap head-inner">
|
||||
<a class="wordmark" href="./index.html">
|
||||
MATERIA <span class="wordmark-han">空間素材</span>
|
||||
</a>
|
||||
|
||||
<nav class="nav" aria-label="메인 메뉴">
|
||||
<a href="./projects/hannam-duplex/index.html" style="color: var(--accent); font-weight: 600;">24개 공간 갤러리</a>
|
||||
<a href="#works">엄선 프로젝트</a>
|
||||
<a href="#materials">물성 아카이브</a>
|
||||
<a href="#process">설계 프로세스</a>
|
||||
<a href="#contact">프라이빗 상담</a>
|
||||
</nav>
|
||||
|
||||
<div class="head-actions">
|
||||
<div class="ambiance-switcher" role="group" aria-label="조도 모드 전환">
|
||||
<button type="button" class="ambiance-btn is-active" id="btnAmbianceDay">
|
||||
Day
|
||||
</button>
|
||||
<button type="button" class="ambiance-btn" id="btnAmbianceNight">
|
||||
Night
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<a href="#contact" class="btn">
|
||||
상담 신청
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="mainContent">
|
||||
<!-- 히어로 섹션 -->
|
||||
<section class="hero-section" aria-labelledby="heroHeading">
|
||||
<div class="wrap hero-grid">
|
||||
<div class="hero-content">
|
||||
<div class="eyebrow">
|
||||
<span>HIGH-END ARCHITECTURAL INTERIOR</span>
|
||||
</div>
|
||||
<h1 id="heroHeading" class="hero-title">
|
||||
빛과 트래버틴이 빚어내는<br />
|
||||
침묵의 <span class="italic">공간 건축</span>
|
||||
</h1>
|
||||
<p class="hero-desc">
|
||||
우리는 장식을 덧대지 않습니다. 돌의 거친 결, 훈증 오크의 온기, 리넨을 투과하는 자연광의 궤적을 치밀하게 계산하여 시간이 흘러도 변치 않는 하이엔드 주거와 갤러리 공간을 완성합니다.
|
||||
</p>
|
||||
<div class="hero-ctas">
|
||||
<a href="./projects/hannam-duplex/index.html" class="btn-materia">
|
||||
한남 펜트하우스 24개 공간 감상
|
||||
<span aria-hidden="true">↗</span>
|
||||
</a>
|
||||
<a href="#materials" class="btn-materia" style="background: var(--surface-card); color: var(--ink); border: 1px solid var(--line);">
|
||||
소재와 물성 탐색
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-visual" style="position: relative;">
|
||||
<div class="bezel-outer">
|
||||
<div class="hero-frame">
|
||||
<img
|
||||
src="./assets/penthouse-hero.webp"
|
||||
alt="트래버틴 벽체와 훈증 오크 수납장이 조화된 하이엔드 펜트하우스 거실 전경"
|
||||
width="1200"
|
||||
height="1600"
|
||||
loading="eager"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-caption-pill">
|
||||
<div class="hero-caption-name">한남 펜트하우스 레지던스</div>
|
||||
<div class="hero-caption-meta">Hannam · 284㎡ (86평) · 2026.04 준공</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 엄선 프로젝트 갤러리 (Selected Works) -->
|
||||
<section class="works-section" id="works" aria-labelledby="worksHeading">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<h2 id="worksHeading" class="section-title">엄선된 하이엔드 공간 아카이브</h2>
|
||||
<p class="section-sub">주거 펜트하우스부터 프라이빗 갤러리까지, 공간의 고유한 결을 살린 마테리아의 대표 프로젝트입니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="works-grid">
|
||||
<!-- 프로젝트 1 -->
|
||||
<article class="work-card">
|
||||
<div class="work-card-media">
|
||||
<img
|
||||
src="./assets/penthouse-hero.webp"
|
||||
alt="한남 듀플렉스 펜트하우스 거실 전경"
|
||||
width="600"
|
||||
height="400"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div class="work-card-body">
|
||||
<h3 class="work-card-title">한남 듀플렉스 펜트하우스</h3>
|
||||
<div class="work-card-type">Residential · 284㎡ · 로만 트래버틴 & 훈증 오크</div>
|
||||
<p class="work-card-desc">
|
||||
층고 5.8m의 복층 구조에 거친 트래버틴 석재 벽체와 다크 훈증 오크를 대비시켜 웅장하면서도 고요한 빛의 음영을 연출했습니다.
|
||||
</p>
|
||||
<div class="work-card-actions">
|
||||
<a
|
||||
href="./projects/hannam-duplex/index.html"
|
||||
class="btn-materia"
|
||||
>
|
||||
24개 공간 갤러리 감상 ↗
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- 프로젝트 2 -->
|
||||
<article class="work-card">
|
||||
<div class="work-card-media">
|
||||
<img
|
||||
src="./assets/materials-macro.webp"
|
||||
alt="청담 프라이빗 갤러리 마감재 매크로"
|
||||
width="600"
|
||||
height="400"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div class="work-card-body">
|
||||
<h3 class="work-card-title">청담 프라이빗 갤러리</h3>
|
||||
<div class="work-card-type">Commercial / Gallery · 195㎡ · 마이크로토핑 & 브론즈</div>
|
||||
<p class="work-card-desc">
|
||||
작품이 온전히 숨 쉴 수 있도록 모든 몰딩을 숨긴 무문선·무걸레받이 디테일과 브러시드 브론즈 프레임으로 정갈함을 극대화했습니다.
|
||||
</p>
|
||||
<div class="work-card-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-materia"
|
||||
onclick="openProjectModal('청담 프라이빗 갤러리', '195㎡ (59평)', '이탈리아 마이크로토핑 바닥재, 브러시드 파티나 브론즈, 무반사 저철분 유리', '색채를 배제한 무채색 베이스 위에 섬세한 텍스처를 레이어드하여 미술품의 몰입도를 극대화한 공간입니다.');"
|
||||
>
|
||||
설계 명세 보기 →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- 프로젝트 3 -->
|
||||
<article class="work-card">
|
||||
<div class="work-card-media">
|
||||
<img
|
||||
src="./assets/hannam-08-terrace.webp"
|
||||
alt="성북동 포레스트 레지던스 자연석 테라스와 수림 차경"
|
||||
width="600"
|
||||
height="400"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<div class="work-card-body">
|
||||
<h3 class="work-card-title">성북동 포레스트 레지던스</h3>
|
||||
<div class="work-card-type">Private Residence · 340㎡ · 자연석 화강석 & 벨기에 리넨</div>
|
||||
<p class="work-card-desc">
|
||||
북악산 사계절의 숲 풍경을 차경(借景)으로 끌어들이고, 실내에는 자연석 아일랜드와 수공예 패브릭을 배치한 친환경 럭셔리 주거.
|
||||
</p>
|
||||
<div class="work-card-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-materia"
|
||||
onclick="openProjectModal('성북동 포레스트 레지던스', '340㎡ (103평)', '가평 통화강석 아일랜드, 스위스 비트라 가구 빌트인, 천연 회벽 마감', '산자락의 자연광과 계절의 변화를 고스란히 담아내는 차경 설계와 천연 자재의 숨결을 결합했습니다.');"
|
||||
>
|
||||
설계 명세 보기 →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 머티리얼 보드 & 촉각성 (Tactile Materiality) -->
|
||||
<section class="material-section" id="materials" aria-labelledby="matHeading">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<h2 id="matHeading" class="section-title">자연이 빚은 물성과 촉각의 조화</h2>
|
||||
<p class="section-sub">마테리아가 선별한 최상급 건축 마감재는 인위적인 가공을 최소화하여 시간의 깊이를 머금습니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="material-grid">
|
||||
<div class="material-frame">
|
||||
<img
|
||||
src="./assets/materials-macro.webp"
|
||||
alt="트래버틴 대리석, 훈증 오크, 벨기에 리넨, 브론즈 머티리얼 플랫레이"
|
||||
width="800"
|
||||
height="600"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="material-specs">
|
||||
<div class="mat-item">
|
||||
<span class="mat-name">로만 트래버틴</span>
|
||||
<span class="mat-desc">이탈리아 티볼리 채석장의 천연 석회암. 무수한 다공성 질감이 빛을 부드럽게 난반사합니다.</span>
|
||||
</div>
|
||||
<div class="mat-item">
|
||||
<span class="mat-name">훈증 오크 (Bog Oak)</span>
|
||||
<span class="mat-desc">수백 년간 수중 숙성된 천연 고재의 깊은 탄화 흑색과 치밀한 나이테 결을 그대로 보존합니다.</span>
|
||||
</div>
|
||||
<div class="mat-item">
|
||||
<span class="mat-name">벨기에 천연 리넨</span>
|
||||
<span class="mat-desc">플랑드르 지방의 무표백 아마 섬유로 짠 고밀도 원단. 부드럽게 빛을 거르고 통기성을 제공합니다.</span>
|
||||
</div>
|
||||
<div class="mat-item">
|
||||
<span class="mat-name">파티나 브론즈</span>
|
||||
<span class="mat-desc">손길이 닿을수록 자연스러운 에이징 산화 피막이 형성되는 수공예 황동 하드웨어입니다.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4단계 마스터 프로세스 -->
|
||||
<section class="process-section" id="process" aria-labelledby="procHeading">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<h2 id="procHeading" class="section-title">비스포크 공간 건축 4단계 프로세스</h2>
|
||||
<p class="section-sub">기획부터 완공 인도까지, 총괄 디렉터 1인이 모든 자재와 조도를 책임지고 총괄합니다.</p>
|
||||
</div>
|
||||
|
||||
<div class="process-grid">
|
||||
<div class="process-card">
|
||||
<div class="process-step">PHASE 01</div>
|
||||
<h3>일조 및 공간 진단</h3>
|
||||
<p>현장의 24시간 태양 궤적, 조망 축, 구조 하중을 분석하여 채광의 최적 배치를 기획합니다.</p>
|
||||
</div>
|
||||
<div class="process-card">
|
||||
<div class="process-step">PHASE 02</div>
|
||||
<h3>촉각적 머티리얼 페어링</h3>
|
||||
<p>실제 1:1 자재 샘플 보드를 제작하여 거주자의 라이프스타일과 촉감 선호도를 일치시킵니다.</p>
|
||||
</div>
|
||||
<div class="process-card">
|
||||
<div class="process-step">PHASE 03</div>
|
||||
<h3>3D 광학 시뮬레이션</h3>
|
||||
<p>주광(Daylight)과 2700K 인공 조명의 조도 분포를 가상 렌더링으로 정밀 검증합니다.</p>
|
||||
</div>
|
||||
<div class="process-card">
|
||||
<div class="process-step">PHASE 04</div>
|
||||
<h3>장인 직영 디테일 시공</h3>
|
||||
<p>30년 경력의 석재·목공 마스터 장인팀이 밀리미터 단위의 오차 없는 시공을 완성합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 프라이빗 공간 컨설팅 신청 -->
|
||||
<section class="contact-section" id="contact" aria-labelledby="contactHeading">
|
||||
<div class="wrap">
|
||||
<div class="contact-card">
|
||||
<div style="text-align: center; margin-bottom: var(--space-6);">
|
||||
<div class="eyebrow">BESPOKE CONSULTATION</div>
|
||||
<h2 id="contactHeading" style="font-family: var(--font-serif); font-size: var(--step-2); margin-top: 6px;">
|
||||
프라이빗 공간 컨설팅 신청
|
||||
</h2>
|
||||
<p style="font-size: var(--step-0); color: var(--ink-muted); margin-top: 6px;">
|
||||
월 최대 3건의 프로젝트만을 엄선하여 타협 없는 완성도를 보증합니다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form id="consultForm" onsubmit="return false;">
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="spaceType">공간 유형</label>
|
||||
<select id="spaceType" class="form-select">
|
||||
<option>주거 펜트하우스 / 타운하우스</option>
|
||||
<option>단독주택 신축 / 대수선</option>
|
||||
<option>프라이빗 갤러리 / 플래그십</option>
|
||||
<option>하이엔드 오피스 라운지</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="spaceArea">예상 전용면적 (평형)</label>
|
||||
<input type="text" id="spaceArea" class="form-input" placeholder="예: 65평 (214㎡)" value="82평 (271㎡)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="clientName">성함</label>
|
||||
<input type="text" id="clientName" class="form-input" placeholder="성함" value="김민준" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="clientPhone">연락처</label>
|
||||
<input type="tel" id="clientPhone" class="form-input" placeholder="010-0000-0000" value="010-5920-8812" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="clientBudget">예상 공사 예산 범위</label>
|
||||
<select id="clientBudget" class="form-select">
|
||||
<option>1억 5천만 원 ~ 3억 원</option>
|
||||
<option selected>3억 원 ~ 5억 원</option>
|
||||
<option>5억 원 이상 (풀 하이엔드 비스포크)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="clientNote">공간에 바라는 철학 및 특별 요청사항</label>
|
||||
<textarea id="clientNote" class="form-textarea" rows="3" placeholder="추구하시는 분위기, 선호 자재, 착공 희망 시기 등을 자유롭게 적어주세요.">거실에 웅장한 트래버틴 벽체와 자연스러운 간접 조명을 조성하고 싶습니다. 2026년 10월 착공 희망합니다.</textarea>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-materia" id="btnSubmitConsult" style="width: 100%; padding: 14px; margin-top: 10px;">
|
||||
프라이빗 디자인 상담 신청 완료
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- 프로젝트 상세 모달 다이얼로그 -->
|
||||
<dialog id="projectModal" class="project-dialog" aria-labelledby="pModalTitle">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.25rem; border-bottom: 1px solid var(--line); padding-bottom: 0.75rem;">
|
||||
<h3 id="pModalTitle" style="font-family: var(--font-serif); font-size: var(--step-1); color: var(--ink);">
|
||||
프로젝트 설계 아카이브
|
||||
</h3>
|
||||
<button type="button" onclick="document.getElementById('projectModal').close();" aria-label="닫기" style="font-size: 18px; font-weight: 700; color: var(--ink-muted);">✕</button>
|
||||
</div>
|
||||
<div style="display: grid; gap: 0.85rem; font-size: var(--step--1); line-height: 1.6;">
|
||||
<div><strong>프로젝트명:</strong> <span id="mProjName" style="color:var(--accent); font-weight:700;"></span></div>
|
||||
<div><strong>공간 면적:</strong> <span id="mProjArea" class="mono"></span></div>
|
||||
<div><strong>주요 마감재:</strong> <span id="mProjMaterials"></span></div>
|
||||
<div style="margin-top: 4px; padding: 12px; background: var(--surface-card); border-radius: var(--radius-sm); border: 1px solid var(--line);">
|
||||
<strong>설계 의도:</strong><br />
|
||||
<span id="mProjNotes" style="color:var(--ink-muted);"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 1.5rem; text-align: right;">
|
||||
<button type="button" class="btn-materia" style="padding: 6px 20px; font-size: 13px;" onclick="document.getElementById('projectModal').close();">닫기</button>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!-- 푸터 (.site-foot SSOT) -->
|
||||
<footer class="site-foot">
|
||||
<div class="wrap foot-inner">
|
||||
<p>마테리아 스튜디오 · 서울 강남구 압구정로 72길 14</p>
|
||||
<p class="muted">월요일부터 금요일까지 (사전 예약제)</p>
|
||||
<p class="muted">studio@materia.kr</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- 인터랙티브 스크립트 -->
|
||||
<script>
|
||||
(function () {
|
||||
// 1. 조도 앰비언스 모드 스위처 (자연광 Day vs 야간 Night)
|
||||
const btnDay = document.getElementById("btnAmbianceDay");
|
||||
const btnNight = document.getElementById("btnAmbianceNight");
|
||||
|
||||
function setAmbiance(mode) {
|
||||
document.body.setAttribute("data-ambiance", mode);
|
||||
if (mode === "night") {
|
||||
btnNight.classList.add("is-active");
|
||||
btnDay.classList.remove("is-active");
|
||||
} else {
|
||||
btnDay.classList.add("is-active");
|
||||
btnNight.classList.remove("is-active");
|
||||
}
|
||||
}
|
||||
|
||||
btnDay.addEventListener("click", () => setAmbiance("day"));
|
||||
btnNight.addEventListener("click", () => setAmbiance("night"));
|
||||
|
||||
// 2. 상담 신청 폼
|
||||
const btnConsult = document.getElementById("btnSubmitConsult");
|
||||
if (btnConsult) {
|
||||
btnConsult.addEventListener("click", () => {
|
||||
const name = document.getElementById("clientName").value || "고객님";
|
||||
const spaceType = document.getElementById("spaceType").value;
|
||||
const area = document.getElementById("spaceArea").value;
|
||||
alert(`[마테리아 스튜디오] ${name}님의 프라이빗 공간 컨설팅 신청(${spaceType} / ${area})이 접수되었습니다.\n담당 수석 디렉터가 24시간 이내에 포트폴리오 자료와 함께 직접 연락드리겠습니다.`);
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
// 프로젝트 모달 팝업 함수
|
||||
function openProjectModal(name, area, materials, notes) {
|
||||
document.getElementById("mProjName").textContent = name;
|
||||
document.getElementById("mProjArea").textContent = area;
|
||||
document.getElementById("mProjMaterials").textContent = materials;
|
||||
document.getElementById("mProjNotes").textContent = notes;
|
||||
document.getElementById("projectModal").showModal();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,952 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>한남 듀플렉스 펜트하우스 (86평) — MATERIA Project Archive</title>
|
||||
<meta name="description" content="마테리아 스튜디오의 한남 듀플렉스 펜트하우스 86평 프로젝트 아카이브. 5.8m 보이드 천장고, 로만 트래버틴과 3,000년 훈증 오크, 자연광 조도 시뮬레이션 및 24개 공간 갤러리." />
|
||||
|
||||
<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;700&display=swap"
|
||||
/>
|
||||
<link rel="stylesheet" href="../../styles/tokens.css" />
|
||||
<link rel="stylesheet" href="../../styles/main.css" />
|
||||
<style>
|
||||
/* Detail Page Specific Styles */
|
||||
.breadcrumb-bar {
|
||||
padding-top: var(--space-4);
|
||||
padding-bottom: var(--space-3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.breadcrumb-bar a {
|
||||
color: var(--ink-muted);
|
||||
text-decoration: none;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
.breadcrumb-bar a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
.breadcrumb-bar .sep {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.breadcrumb-bar .current {
|
||||
color: var(--ink);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.project-hero-section {
|
||||
padding-block: var(--space-4) var(--space-7);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.project-hero-head {
|
||||
padding-top: var(--space-5);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
.project-hero-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-3);
|
||||
font-weight: 700;
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-4);
|
||||
word-break: keep-all;
|
||||
}
|
||||
.project-hero-title .hero-sub {
|
||||
display: block;
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-1);
|
||||
font-weight: 400;
|
||||
color: var(--ink-muted);
|
||||
margin-top: var(--space-2);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.project-meta-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
|
||||
gap: var(--space-3);
|
||||
margin-top: var(--space-5);
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-4) var(--space-5);
|
||||
}
|
||||
.meta-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
.meta-item .label {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.meta-item .value {
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.project-hero-media {
|
||||
position: relative;
|
||||
margin-top: var(--space-6);
|
||||
}
|
||||
.hero-frame {
|
||||
border-radius: calc(var(--radius-md) - 6px);
|
||||
overflow: hidden;
|
||||
background: var(--surface-subtle);
|
||||
}
|
||||
.hero-frame img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
aspect-ratio: 16 / 9;
|
||||
object-fit: cover;
|
||||
}
|
||||
.hero-caption-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
margin-top: var(--space-3);
|
||||
padding: 6px 14px;
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: var(--step--1);
|
||||
}
|
||||
.hero-caption-name {
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
}
|
||||
.hero-caption-meta {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.narrative-section {
|
||||
padding-block: var(--space-7);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.narrative-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
|
||||
gap: var(--space-7);
|
||||
align-items: start;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.narrative-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
}
|
||||
.narrative-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
color: var(--ink-muted);
|
||||
line-height: var(--leading-normal);
|
||||
font-size: var(--step-0);
|
||||
}
|
||||
|
||||
/* Gallery Architecture */
|
||||
.gallery-section {
|
||||
padding-block: var(--space-7) var(--space-8);
|
||||
}
|
||||
.gallery-head {
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
.gallery-filter-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
margin-bottom: var(--space-5);
|
||||
}
|
||||
.gallery-chip {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
padding: 8px 16px;
|
||||
border-radius: var(--radius-xs);
|
||||
border: 1px solid var(--line);
|
||||
background: var(--surface);
|
||||
color: var(--ink-muted);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.gallery-chip:hover {
|
||||
border-color: var(--accent);
|
||||
color: var(--ink);
|
||||
}
|
||||
.gallery-chip.active {
|
||||
background: var(--accent);
|
||||
border-color: var(--accent);
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.spatial-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: var(--space-4);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
.spatial-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.gallery-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
.gallery-card:hover {
|
||||
transform: translateY(-3px);
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 12px 28px rgba(0,0,0,0.06);
|
||||
}
|
||||
.gallery-card-img-wrap {
|
||||
aspect-ratio: 16 / 10;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: var(--surface-sunken);
|
||||
}
|
||||
.gallery-card img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.4s ease;
|
||||
}
|
||||
.gallery-card:hover img {
|
||||
transform: scale(1.03);
|
||||
}
|
||||
.gallery-card-body {
|
||||
padding: var(--space-4);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.gallery-card-zone {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
color: var(--accent);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
.gallery-card-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
.gallery-card-desc {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Lightbox Dialog */
|
||||
.lightbox-dialog {
|
||||
background: rgba(14, 14, 16, 0.96);
|
||||
color: #ffffff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
border-radius: var(--radius-sm);
|
||||
max-width: 1200px;
|
||||
width: 95vw;
|
||||
max-height: 92dvh;
|
||||
padding: 0;
|
||||
box-shadow: 0 32px 80px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
.lightbox-dialog::backdrop {
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.lightbox-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
@media (min-width: 900px) {
|
||||
.lightbox-layout {
|
||||
grid-template-columns: 1.8fr 1fr;
|
||||
}
|
||||
}
|
||||
.lightbox-media {
|
||||
background: #000000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--space-4);
|
||||
max-height: 80vh;
|
||||
}
|
||||
.lightbox-media img {
|
||||
max-width: 100%;
|
||||
max-height: 75vh;
|
||||
object-fit: contain;
|
||||
border-radius: var(--radius-xs);
|
||||
}
|
||||
.lightbox-info {
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-4);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Blueprint interactive section */
|
||||
.blueprint-section {
|
||||
background: var(--surface-sunken);
|
||||
border-top: 1px solid var(--line);
|
||||
border-bottom: 1px solid var(--line);
|
||||
padding: var(--space-7) 0;
|
||||
}
|
||||
.blueprint-viewer {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-6);
|
||||
align-items: center;
|
||||
}
|
||||
@media (min-width: 960px) {
|
||||
.blueprint-viewer {
|
||||
grid-template-columns: 1.4fr 1fr;
|
||||
}
|
||||
}
|
||||
.blueprint-frame {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
background: #ECE7DE;
|
||||
box-shadow: 0 16px 36px rgba(0,0,0,0.06);
|
||||
}
|
||||
.blueprint-frame img {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-ambiance="day">
|
||||
<!-- 상단 헤더 (.site-head SSOT) -->
|
||||
<header class="site-head">
|
||||
<div class="wrap head-inner">
|
||||
<a href="../../index.html" class="wordmark" aria-label="MATERIA 홈">
|
||||
MATERIA <span class="wordmark-han">空間素材</span>
|
||||
</a>
|
||||
<nav class="nav" aria-label="주요 메뉴">
|
||||
<a href="./index.html" class="active" style="color: var(--accent); font-weight: 600;">24개 공간 갤러리</a>
|
||||
<a href="../../index.html#works">엄선 프로젝트</a>
|
||||
<a href="../../index.html#materials">물성 아카이브</a>
|
||||
<a href="../../index.html#process">설계 프로세스</a>
|
||||
<a href="../../index.html#contact">프라이빗 상담</a>
|
||||
</nav>
|
||||
<div class="head-actions">
|
||||
<div class="ambiance-switcher" role="group" aria-label="공간 조도 앰비언스 모드">
|
||||
<button type="button" class="ambiance-btn is-active" id="btnAmbianceDay">Day</button>
|
||||
<button type="button" class="ambiance-btn" id="btnAmbianceNight">Night</button>
|
||||
</div>
|
||||
<a href="../../index.html#contact" class="btn">
|
||||
상담 신청
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="main-content">
|
||||
<!-- Project Hero Section -->
|
||||
<section class="section project-hero" style="border-top: none; padding-top: var(--space-5);">
|
||||
<div class="wrap">
|
||||
<div class="breadcrumb-bar" style="margin-bottom: var(--space-4); display: flex; align-items: center; gap: var(--space-2); font-family: var(--font-mono); font-size: 12px; color: var(--ink-muted); letter-spacing: 0.04em;">
|
||||
<a href="../../index.html">MATERIA</a>
|
||||
<span class="sep">/</span>
|
||||
<a href="../../index.html#works">PROJECT ARCHIVE</a>
|
||||
<span class="sep">/</span>
|
||||
<span class="current" style="color: var(--ink); font-weight: 600;">HANNAM DUPLEX PENTHOUSE (86PY)</span>
|
||||
</div>
|
||||
|
||||
<div class="project-hero-head">
|
||||
<p class="hero-label">CASE STUDY · RESIDENTIAL ARCHITECTURE · 86PY</p>
|
||||
<h1 class="hero-title" style="margin-bottom: var(--space-2);">한남 듀플렉스 펜트하우스</h1>
|
||||
<p class="hero-lead" style="font-size: var(--step-0); color: var(--ink-muted); max-width: var(--measure); margin-bottom: var(--space-5);">
|
||||
5.8m 보이드 천장고와 로만 트래버틴, 3,000년 훈증 오크가 빚어낸 침묵의 공간.
|
||||
</p>
|
||||
|
||||
<dl class="project-specs" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-4); background: var(--surface-card); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-4) var(--space-5); margin-bottom: var(--space-6);">
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">위치</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">서울시 용산구 한남동</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">면적</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">284㎡ (86평형 복층)</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">천장고</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">5.8m Void Ceiling</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">공사기간</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">14주 (2026.04 준공)</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">핵심 소재</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">Roman Navona Travertine</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="spec-label" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px;">목공 마감</dt>
|
||||
<dd class="spec-val" style="font-family: var(--font-serif); font-size: var(--step-0); font-weight: 700; color: var(--ink);">3,000Y Smoked Bog Oak</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<!-- Hero Image in Frame -->
|
||||
<figure class="hero-photo" style="border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--surface-card);">
|
||||
<img
|
||||
src="../../assets/hannam-01-living-void.webp"
|
||||
alt="한남 듀플렉스 펜트하우스 5.8m 보이드 거실 전경과 트래버틴 벽체"
|
||||
width="1600"
|
||||
height="900"
|
||||
style="width: 100%; aspect-ratio: 16/9; object-fit: cover;"
|
||||
/>
|
||||
<figcaption style="padding: 10px 16px; font-family: var(--font-mono); font-size: 12px; color: var(--ink-muted); border-top: 1px solid var(--line); background: var(--surface-raised);">
|
||||
Zone A · 5.8m 보이드 거실 & 20mm 로만 나보나 트래버틴 아트월
|
||||
</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Architectural Narrative Section -->
|
||||
<section class="narrative-section">
|
||||
<div class="wrap">
|
||||
<div class="narrative-grid">
|
||||
<div>
|
||||
<div class="eyebrow">DESIGN PHILOSOPHY</div>
|
||||
<h2 class="section-title" style="font-family: var(--font-serif); font-size: var(--step-2); font-weight: 700; line-height: 1.25;">
|
||||
비움으로 완성한<br />빛과 물성의 교감
|
||||
</h2>
|
||||
</div>
|
||||
<div class="narrative-text">
|
||||
<p>
|
||||
한남 듀플렉스 펜트하우스는 장식적 기교를 배제하고, 자연광의 궤적과 거대한 석재의 물성이 공간의 주인이 되도록 설계된 프로젝트입니다.
|
||||
남향으로 열린 한강 조망과 5.8미터 복층 보이드 구조를 관통하는 자연광을 수학적으로 계산하여, 시간에 따라 석재 표면의 음영이 시시각각 변화하도록 유도했습니다.
|
||||
</p>
|
||||
<p>
|
||||
벽체를 감싸는 20mm 로만 나보나 트래버틴은 이탈리아 티볼리 채석장에서 원판을 엄선하여 이음매의 결을 무지향성으로 연결했으며,
|
||||
3,000년 세월 동안 탄화된 훈증 오크(Bog Oak)와 수공예 파티나 브론즈를 접합하여 시각적 깊이와 촉각적 정숙함을 부여했습니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Interactive 24-Piece Spatial Gallery Architecture -->
|
||||
<section class="gallery-section" id="spatial-gallery">
|
||||
<div class="wrap">
|
||||
<div class="gallery-head">
|
||||
<div class="eyebrow">SPATIAL EXPLORATION · 24 SHOTS</div>
|
||||
<h2 class="section-title" style="font-family: var(--font-serif); font-size: var(--step-2); font-weight: 700;">공간별 심층 아카이브 갤러리</h2>
|
||||
<p class="section-sub" style="font-size: var(--step--1); color: var(--ink-muted); margin-top: 4px;">
|
||||
각 카드를 클릭하시면 고해상도 확대 뷰어와 설계 물성 상세 명세를 확인하실 수 있습니다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Zone Filters -->
|
||||
<div class="gallery-filter-chips" role="tablist" aria-label="공간 존별 필터">
|
||||
<button type="button" class="gallery-chip active" data-zone="all">전체 공간 (24)</button>
|
||||
<button type="button" class="gallery-chip" data-zone="living">Zone A: 거실 & 다이닝 (4)</button>
|
||||
<button type="button" class="gallery-chip" data-zone="master">Zone B: 마스터 스위트 & 스파 (4)</button>
|
||||
<button type="button" class="gallery-chip" data-zone="study">Zone C: 서재 & 와인 & 드레스룸 (4)</button>
|
||||
<button type="button" class="gallery-chip" data-zone="garden">Zone D: 테라스 & 중정 & 현관 (4)</button>
|
||||
<button type="button" class="gallery-chip" data-zone="materials">Zone E: 물성 매크로 접사 (4)</button>
|
||||
<button type="button" class="gallery-chip" data-zone="analysis">Zone F: 도면 & 광학 분석 & 디테일 (4)</button>
|
||||
</div>
|
||||
|
||||
<!-- 24 Gallery Cards Grid -->
|
||||
<div class="spatial-grid" id="spatialGrid">
|
||||
<!-- Card 1 -->
|
||||
<div class="gallery-card" data-zone="living" onclick="openLightbox(0)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-01-living-void.webp" alt="5.8m 보이드 거실" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone A · Living</span>
|
||||
<h3 class="gallery-card-title">5.8m 보이드 그레이트 룸</h3>
|
||||
<p class="gallery-card-desc">로만 트래버틴 일체형 벽난로와 2개 층을 관통하는 통창 채광 설계.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 2 -->
|
||||
<div class="gallery-card" data-zone="living" onclick="openLightbox(1)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-03-dining.webp" alt="다이닝 룸" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone A · Dining</span>
|
||||
<h3 class="gallery-card-title">월넛 원목 슬랩 다이닝</h3>
|
||||
<p class="gallery-card-desc">수제 브러시드 브론즈 펜던트 조명과 한강 파노라마 야경 조망.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 3 -->
|
||||
<div class="gallery-card" data-zone="living" onclick="openLightbox(2)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-04-kitchen.webp" alt="셰프 키친 아일랜드" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone A · Kitchen</span>
|
||||
<h3 class="gallery-card-title">석재 통판 셰프 키친</h3>
|
||||
<p class="gallery-card-desc">그레이 쿼츠자이트 아일랜드와 히든 플러시 훈증 오크 수납 시스템.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 4 -->
|
||||
<div class="gallery-card" data-zone="living" onclick="openLightbox(3)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-10-staircase.webp" alt="부유형 캔틸레버 계단" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone A · Staircase</span>
|
||||
<h3 class="gallery-card-title">캔틸레버 부유식 오크 계단</h3>
|
||||
<p class="gallery-card-desc">트래버틴 벽체에서 돌출된 무지주 솔리드 오크 디딤판과 매립 핸드레일.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 5 -->
|
||||
<div class="gallery-card" data-zone="master" onclick="openLightbox(4)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-05-master-bedroom.webp" alt="마스터 침실" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone B · Master Suite</span>
|
||||
<h3 class="gallery-card-title">마스터 베드룸 스위트</h3>
|
||||
<p class="gallery-card-desc">천연 리넨 헤드보드 월과 간접 라인 조명으로 완성한 정숙한 침실.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 6 -->
|
||||
<div class="gallery-card" data-zone="master" onclick="openLightbox(5)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-06-spa-bathroom.webp" alt="스파 욕실" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone B · Spa Bath</span>
|
||||
<h3 class="gallery-card-title">화산석 통원석 스파 배스</h3>
|
||||
<p class="gallery-card-desc">자연석을 통째로 깎아낸 원석 욕조와 독립형 파티나 브론즈 수전.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 7 -->
|
||||
<div class="gallery-card" data-zone="master" onclick="openLightbox(6)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-13-powder-room.webp" alt="파우더룸" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone B · Powder Room</span>
|
||||
<h3 class="gallery-card-title">석재 세면대 파우더룸</h3>
|
||||
<p class="gallery-card-desc">조각적인 통라임스톤 세면대와 수직 슬릿 조명이 빚은 명암.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 8 -->
|
||||
<div class="gallery-card" data-zone="master" onclick="openLightbox(7)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-14-guest-suite.webp" alt="게스트 침실" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone B · Guest Suite</span>
|
||||
<h3 class="gallery-card-title">게스트 침실 스위트</h3>
|
||||
<p class="gallery-card-desc">따뜻한 라임워시 도장 벽체와 천연 원목 가구의 안락한 조화.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 9 -->
|
||||
<div class="gallery-card" data-zone="study" onclick="openLightbox(8)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-07-library-audio.webp" alt="서재 및 오디오 룸" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone C · Library</span>
|
||||
<h3 class="gallery-card-title">서재 & 하이파이 오디오 룸</h3>
|
||||
<p class="gallery-card-desc">음향 반사를 고려한 훈증 오크 책장과 아날로그 턴테이블 석재 콘솔.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 10 -->
|
||||
<div class="gallery-card" data-zone="study" onclick="openLightbox(9)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-11-dressing-room.webp" alt="드레스룸" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone C · Dressing Room</span>
|
||||
<h3 class="gallery-card-title">비스포크 워크인 드레스룸</h3>
|
||||
<p class="gallery-card-desc">플루티드 브론즈 유리장과 시계/주얼리 수납 아일랜드 쇼케이스.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 11 -->
|
||||
<div class="gallery-card" data-zone="study" onclick="openLightbox(10)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-12-wine-cellar.webp" alt="와인 셀러 룸" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone C · Wine Cellar</span>
|
||||
<h3 class="gallery-card-title">항온항습 글래스 와인 셀러</h3>
|
||||
<p class="gallery-card-desc">백라이트 트래버틴 벽체와 브론즈 프레임 유리 파티션 셀러.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 12 -->
|
||||
<div class="gallery-card" data-zone="study" onclick="openLightbox(11)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-20-tea-room.webp" alt="티 룸 알코브" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone C · Tea Alcove</span>
|
||||
<h3 class="gallery-card-title">명상 다도실 (Tea Room)</h3>
|
||||
<p class="gallery-card-desc">천연 한지 스크린을 투과하는 부드러운 격자 채광과 원목 다도상.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 13 -->
|
||||
<div class="gallery-card" data-zone="garden" onclick="openLightbox(12)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-08-terrace.webp" alt="프라이빗 테라스" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone D · Terrace</span>
|
||||
<h3 class="gallery-card-title">루프탑 프라이빗 테라스</h3>
|
||||
<p class="gallery-card-desc">대형 트래버틴 페이버와 조형 소나무 분재, 한강 석양 조망.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 14 -->
|
||||
<div class="gallery-card" data-zone="garden" onclick="openLightbox(13)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-09-foyer.webp" alt="입구 현관 전경" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone D · Entrance</span>
|
||||
<h3 class="gallery-card-title">미니멀 입구 현관 (Foyer)</h3>
|
||||
<p class="gallery-card-desc">거대한 화강석 벤치 원석과 플러시 히든 피벗 도어 시스템.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 15 -->
|
||||
<div class="gallery-card" data-zone="garden" onclick="openLightbox(14)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-22-lightwell.webp" alt="실내 석경 중정" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone D · Lightwell</span>
|
||||
<h3 class="gallery-card-title">실내 석경 중정 (Zen Lightwell)</h3>
|
||||
<p class="gallery-card-desc">천장 보이드에서 쏟아지는 수직 채광과 백자갈 디딤돌 정원.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 16 -->
|
||||
<div class="gallery-card" data-zone="garden" onclick="openLightbox(15)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-21-art-niche.webp" alt="갤러리 아트 니치" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone D · Art Niche</span>
|
||||
<h3 class="gallery-card-title">뮤지엄 갤러리 아트 니치</h3>
|
||||
<p class="gallery-card-desc">트래버틴 조각 좌대와 정밀 프레이밍 조명으로 연출된 조각품.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 17 -->
|
||||
<div class="gallery-card" data-zone="materials" onclick="openLightbox(16)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-15-mat-travertine.webp" alt="로만 트래버틴 매크로" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone E · Material</span>
|
||||
<h3 class="gallery-card-title">로만 나보나 트래버틴 접사</h3>
|
||||
<p class="gallery-card-desc">자연이 형성한 미세한 다공성 기공과 따뜻한 꿀빛 석재 층위.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 18 -->
|
||||
<div class="gallery-card" data-zone="materials" onclick="openLightbox(17)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-16-mat-bogoak.webp" alt="3000년 훈증 오크 매크로" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone E · Material</span>
|
||||
<h3 class="gallery-card-title">3,000년 탄화 훈증 오크</h3>
|
||||
<p class="gallery-card-desc">시간이 빚어낸 깊은 차콜 에스프레소 나뭇결과 실키 매트 피니시.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 19 -->
|
||||
<div class="gallery-card" data-zone="materials" onclick="openLightbox(18)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-17-mat-linen.webp" alt="벨기에 리넨 매크로" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone E · Material</span>
|
||||
<h3 class="gallery-card-title">벨기에 무표백 천연 리넨</h3>
|
||||
<p class="gallery-card-desc">불규칙한 천연 실타래 슬럽 조직이 주는 촉각적 안도감과 빛 흡수력.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 20 -->
|
||||
<div class="gallery-card" data-zone="materials" onclick="openLightbox(19)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-18-mat-bronze.webp" alt="파티나 브론즈 매크로" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone E · Material</span>
|
||||
<h3 class="gallery-card-title">수공예 파티나 브러시드 브론즈</h3>
|
||||
<p class="gallery-card-desc">손길이 닿을수록 깊어지는 유기적 산화 피막의 은은한 광채.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 21 -->
|
||||
<div class="gallery-card" data-zone="analysis" onclick="openLightbox(20)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-02-blueprint.webp" alt="건축 평면 설계도면" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone F · Blueprint</span>
|
||||
<h3 class="gallery-card-title">86평 복층 건축 평면 설계도</h3>
|
||||
<p class="gallery-card-desc">동선 효율과 채광축을 정밀하게 구획한 마스터 아키텍처 드래프트.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 22 -->
|
||||
<div class="gallery-card" data-zone="analysis" onclick="openLightbox(21)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-23-light-simulation.webp" alt="3D 일조 광학 시뮬레이션" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone F · Analysis</span>
|
||||
<h3 class="gallery-card-title">3D 태양광 입사 조도 분석</h3>
|
||||
<p class="gallery-card-desc">하지 및 춘분 정오 55° 고도각에 따른 Lux 분포 및 음영 계산도.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 23 -->
|
||||
<div class="gallery-card" data-zone="analysis" onclick="openLightbox(22)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-19-joinery.webp" alt="5mm 섀도우 갭 조인트" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone F · Detail</span>
|
||||
<h3 class="gallery-card-title">5mm 음각 섀도우 갭 조인트</h3>
|
||||
<p class="gallery-card-desc">석재와 원목 패널 사이의 0.5mm 오차 없는 스위스 규격 결합부.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 24 -->
|
||||
<div class="gallery-card" data-zone="analysis" onclick="openLightbox(23)">
|
||||
<div class="gallery-card-img-wrap">
|
||||
<img src="../../assets/hannam-24-timber-joinery.webp" alt="장인 장부 맞춤 목공" loading="lazy" />
|
||||
</div>
|
||||
<div class="gallery-card-body">
|
||||
<span class="gallery-card-zone">Zone F · Detail</span>
|
||||
<h3 class="gallery-card-title">전통 장부 맞춤 마스터 목공</h3>
|
||||
<p class="gallery-card-desc">못 없이 체결되는 장인 직영 정밀 결구 구조의 하드웨어.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Interactive Blueprint & Spec Analysis Viewer -->
|
||||
<section class="blueprint-section">
|
||||
<div class="wrap">
|
||||
<div class="blueprint-viewer">
|
||||
<div class="blueprint-frame">
|
||||
<img src="../../assets/hannam-02-blueprint.webp" alt="한남 듀플렉스 펜트하우스 평면도" />
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: var(--space-4);">
|
||||
<div class="eyebrow" style="color: var(--accent);">TECHNICAL SPECIFICATION</div>
|
||||
<h2 style="font-size: var(--step-2); font-weight: 800; line-height: 1.25;">
|
||||
수치로 입증하는<br />하이엔드 시공 규격
|
||||
</h2>
|
||||
<div style="display: flex; flex-direction: column; gap: var(--space-3); font-size: var(--step--1);">
|
||||
<div style="padding: var(--space-3); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);">
|
||||
<strong style="color: var(--ink);">단차 허용 공차</strong>: 0.3mm 이내 (레이저 레벨링 및 통석재 현장 가공)
|
||||
</div>
|
||||
<div style="padding: var(--space-3); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);">
|
||||
<strong style="color: var(--ink);">조명 색온도 제어</strong>: 2200K (석양 캔들) ~ 5500K (자연 주광) DALI 스마트 디밍
|
||||
</div>
|
||||
<div style="padding: var(--space-3); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);">
|
||||
<strong style="color: var(--ink);">공조 매립 규격</strong>: 무몰딩 트림리스 선형 디퓨저 & 히든 점검구 100% 설계
|
||||
</div>
|
||||
</div>
|
||||
<a href="../../index.html#consultation" class="btn-primary" style="display: inline-block; text-align: center; text-decoration: none; margin-top: var(--space-2);">
|
||||
이 프로젝트 스타일로 상담 신청하기 →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Fullscreen Lightbox Modal Dialog -->
|
||||
<dialog id="lightboxDialog" class="lightbox-dialog">
|
||||
<div class="lightbox-layout">
|
||||
<div class="lightbox-media">
|
||||
<img id="lightboxImg" src="../../assets/hannam-01-living-void.webp" alt="확대 이미지" />
|
||||
</div>
|
||||
<div class="lightbox-info">
|
||||
<div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-3);">
|
||||
<span id="lightboxZone" style="font-family: var(--font-mono); font-size: 11px; color: var(--accent); font-weight: 700; text-transform: uppercase;"></span>
|
||||
<button type="button" onclick="document.getElementById('lightboxDialog').close();" aria-label="닫기" style="background: none; border: none; color: #fff; font-size: 24px; cursor: pointer;">✕</button>
|
||||
</div>
|
||||
<h3 id="lightboxTitle" style="font-size: var(--step-1); font-weight: 700; margin-bottom: var(--space-2); color: #fff;"></h3>
|
||||
<p id="lightboxDesc" style="font-size: var(--step--1); color: #a1a1aa; line-height: 1.6;"></p>
|
||||
</div>
|
||||
<div style="border-top: 1px solid rgba(255,255,255,0.1); padding-top: var(--space-4); display: flex; justify-content: space-between; align-items: center;">
|
||||
<span id="lightboxIndex" style="font-family: var(--font-mono); font-size: 12px; color: #71717a;"></span>
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<button type="button" onclick="prevLightbox()" style="padding: 6px 14px; background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); color: #fff; border-radius: 4px; cursor: pointer;">← 이전</button>
|
||||
<button type="button" onclick="nextLightbox()" style="padding: 6px 14px; background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); color: #fff; border-radius: 4px; cursor: pointer;">다음 →</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!-- 푸터 (.site-foot SSOT) -->
|
||||
<footer class="site-foot">
|
||||
<div class="wrap foot-inner">
|
||||
<p>마테리아 스튜디오 · 서울 강남구 압구정로 72길 14</p>
|
||||
<p class="muted">월요일부터 금요일까지 (사전 예약제)</p>
|
||||
<p class="muted">studio@materia.kr</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Interactive Scripts -->
|
||||
<script>
|
||||
// 1. Ambiance Day/Night Switcher
|
||||
const btnDay = document.getElementById('btnAmbianceDay');
|
||||
const btnNight = document.getElementById('btnAmbianceNight');
|
||||
btnDay?.addEventListener('click', () => {
|
||||
document.documentElement.removeAttribute('data-theme');
|
||||
btnDay.classList.add('active');
|
||||
btnNight.classList.remove('active');
|
||||
});
|
||||
btnNight?.addEventListener('click', () => {
|
||||
document.documentElement.setAttribute('data-theme', 'night');
|
||||
btnNight.classList.add('active');
|
||||
btnDay.classList.remove('active');
|
||||
});
|
||||
|
||||
// 2. 24 Gallery Items Data Store
|
||||
const galleryData = [
|
||||
{ img: '../../assets/hannam-01-living-void.webp', zone: 'Zone A · Living', title: '5.8m 보이드 그레이트 룸', desc: '로만 나보나 트래버틴 원판 벽체와 2개 층을 관통하는 통창 채광 설계.' },
|
||||
{ img: '../../assets/hannam-03-dining.webp', zone: 'Zone A · Dining', title: '월넛 원목 슬랩 다이닝', desc: '수제 브러시드 브론즈 펜던트 조명과 한강 파노라마 야경 조망.' },
|
||||
{ img: '../../assets/hannam-04-kitchen.webp', zone: 'Zone A · Kitchen', title: '석재 통판 셰프 키친', desc: '그레이 쿼츠자이트 아일랜드와 히든 플러시 훈증 오크 수납 시스템.' },
|
||||
{ img: '../../assets/hannam-10-staircase.webp', zone: 'Zone A · Staircase', title: '캔틸레버 부유식 오크 계단', desc: '트래버틴 벽체에서 돌출된 무지주 솔리드 오크 디딤판과 매립 핸드레일.' },
|
||||
{ img: '../../assets/hannam-05-master-bedroom.webp', zone: 'Zone B · Master Suite', title: '마스터 베드룸 스위트', desc: '천연 리넨 헤드보드 월과 간접 라인 조명으로 완성한 정숙한 침실.' },
|
||||
{ img: '../../assets/hannam-06-spa-bathroom.webp', zone: 'Zone B · Spa Bath', title: '화산석 통원석 스파 배스', desc: '자연석을 통째로 깎아낸 원석 욕조와 독립형 파티나 브론즈 수전.' },
|
||||
{ img: '../../assets/hannam-13-powder-room.webp', zone: 'Zone B · Powder Room', title: '석재 세면대 파우더룸', desc: '조각적인 통라임스톤 세면대와 수직 슬릿 조명이 빚은 명암.' },
|
||||
{ img: '../../assets/hannam-14-guest-suite.webp', zone: 'Zone B · Guest Suite', title: '게스트 침실 스위트', desc: '따뜻한 라임워시 도장 벽체와 천연 원목 가구의 안락한 조화.' },
|
||||
{ img: '../../assets/hannam-07-library-audio.webp', zone: 'Zone C · Library', title: '서재 & 하이파이 오디오 룸', desc: '음향 반사를 고려한 훈증 오크 책장과 아날로그 턴테이블 석재 콘솔.' },
|
||||
{ img: '../../assets/hannam-11-dressing-room.webp', zone: 'Zone C · Dressing Room', title: '비스포크 워크인 드레스룸', desc: '플루티드 브론즈 유리장과 시계/주얼리 수납 아일랜드 쇼케이스.' },
|
||||
{ img: '../../assets/hannam-12-wine-cellar.webp', zone: 'Zone C · Wine Cellar', title: '항온항습 글래스 와인 셀러', desc: '백라이트 트래버틴 벽체와 브론즈 프레임 유리 파티션 셀러.' },
|
||||
{ img: '../../assets/hannam-20-tea-room.webp', zone: 'Zone C · Tea Alcove', title: '명상 다도실 (Tea Room)', desc: '천연 한지 스크린을 투과하는 부드러운 격자 채광과 원목 다도상.' },
|
||||
{ img: '../../assets/hannam-08-terrace.webp', zone: 'Zone D · Terrace', title: '루프탑 프라이빗 테라스', desc: '대형 트래버틴 페이버와 조형 소나무 분재, 한강 석양 조망.' },
|
||||
{ img: '../../assets/hannam-09-foyer.webp', zone: 'Zone D · Entrance', title: '미니멀 입구 현관 (Foyer)', desc: '거대한 화강석 벤치 원석과 플러시 히든 피벗 도어 시스템.' },
|
||||
{ img: '../../assets/hannam-22-lightwell.webp', zone: 'Zone D · Lightwell', title: '실내 석경 중정 (Zen Lightwell)', desc: '천장 보이드에서 쏟아지는 수직 채광과 백자갈 디딤돌 정원.' },
|
||||
{ img: '../../assets/hannam-21-art-niche.webp', zone: 'Zone D · Art Niche', title: '뮤지엄 갤러리 아트 니치', desc: '트래버틴 조각 좌대와 정밀 프레이밍 조명으로 연출된 조각품.' },
|
||||
{ img: '../../assets/hannam-15-mat-travertine.webp', zone: 'Zone E · Material', title: '로만 나보나 트래버틴 접사', desc: '자연이 형성한 미세한 다공성 기공과 따뜻한 꿀빛 석재 층위.' },
|
||||
{ img: '../../assets/hannam-16-mat-bogoak.webp', zone: 'Zone E · Material', title: '3,000년 탄화 훈증 오크', desc: '시간이 빚어낸 깊은 차콜 에스프레소 나뭇결과 실키 매트 피니시.' },
|
||||
{ img: '../../assets/hannam-17-mat-linen.webp', zone: 'Zone E · Material', title: '벨기에 무표백 천연 리넨', desc: '불규칙한 천연 실타래 슬럽 조직이 주는 촉각적 안도감과 빛 흡수력.' },
|
||||
{ img: '../../assets/hannam-18-mat-bronze.webp', zone: 'Zone E · Material', title: '수공예 파티나 브러시드 브론즈', desc: '손길이 닿을수록 깊어지는 유기적 산화 피막의 은은한 광채.' },
|
||||
{ img: '../../assets/hannam-02-blueprint.webp', zone: 'Zone F · Blueprint', title: '86평 복층 건축 평면 설계도', desc: '동선 효율과 채광축을 정밀하게 구획한 마스터 아키텍처 드래프트.' },
|
||||
{ img: '../../assets/hannam-23-light-simulation.webp', zone: 'Zone F · Analysis', title: '3D 태양광 입사 조도 분석', desc: '하지 및 춘분 정오 55° 고도각에 따른 Lux 분포 및 음영 계산도.' },
|
||||
{ img: '../../assets/hannam-19-joinery.webp', zone: 'Zone F · Detail', title: '5mm 음각 섀도우 갭 조인트', desc: '석재와 원목 패널 사이의 0.5mm 오차 없는 스위스 규격 결합부.' },
|
||||
{ img: '../../assets/hannam-24-timber-joinery.webp', zone: 'Zone F · Detail', title: '전통 장부 맞춤 마스터 목공', desc: '못 없이 체결되는 장인 직영 정밀 결구 구조의 하드웨어.' }
|
||||
];
|
||||
|
||||
// 3. Filter Chips Logic
|
||||
const filterChips = document.querySelectorAll('.gallery-chip');
|
||||
const galleryCards = document.querySelectorAll('.gallery-card');
|
||||
|
||||
filterChips.forEach(chip => {
|
||||
chip.addEventListener('click', () => {
|
||||
filterChips.forEach(c => c.classList.remove('active'));
|
||||
chip.classList.add('active');
|
||||
const zone = chip.getAttribute('data-zone');
|
||||
galleryCards.forEach(card => {
|
||||
if (zone === 'all' || card.getAttribute('data-zone') === zone) {
|
||||
card.style.display = 'flex';
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 4. Lightbox Modal Logic
|
||||
let currentLightboxIdx = 0;
|
||||
const lightboxModal = document.getElementById('lightboxDialog');
|
||||
const lightboxImg = document.getElementById('lightboxImg');
|
||||
const lightboxZone = document.getElementById('lightboxZone');
|
||||
const lightboxTitle = document.getElementById('lightboxTitle');
|
||||
const lightboxDesc = document.getElementById('lightboxDesc');
|
||||
const lightboxIndex = document.getElementById('lightboxIndex');
|
||||
|
||||
function openLightbox(idx) {
|
||||
currentLightboxIdx = idx;
|
||||
renderLightbox();
|
||||
lightboxModal.showModal();
|
||||
}
|
||||
|
||||
function renderLightbox() {
|
||||
const item = galleryData[currentLightboxIdx];
|
||||
if (!item) return;
|
||||
lightboxImg.src = item.img;
|
||||
lightboxImg.alt = item.title;
|
||||
lightboxZone.textContent = item.zone;
|
||||
lightboxTitle.textContent = item.title;
|
||||
lightboxDesc.textContent = item.desc;
|
||||
lightboxIndex.textContent = `${currentLightboxIdx + 1} / ${galleryData.length}`;
|
||||
}
|
||||
|
||||
function prevLightbox() {
|
||||
currentLightboxIdx = (currentLightboxIdx - 1 + galleryData.length) % galleryData.length;
|
||||
renderLightbox();
|
||||
}
|
||||
|
||||
function nextLightbox() {
|
||||
currentLightboxIdx = (currentLightboxIdx + 1) % galleryData.length;
|
||||
renderLightbox();
|
||||
}
|
||||
|
||||
lightboxModal.addEventListener('click', (e) => {
|
||||
if (e.target === lightboxModal) lightboxModal.close();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
684
apps/site/public/work/materia-interior/styles/main.css
Normal file
|
|
@ -0,0 +1,684 @@
|
|||
@import "./tokens.css";
|
||||
|
||||
/* ==========================================================================
|
||||
마테리아 스튜디오 (MATERIA Spatial Design) — 메인 스타일시트 SSOT
|
||||
프리셋: editorial + high-end-visual-design
|
||||
========================================================================== */
|
||||
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
scroll-behavior: smooth;
|
||||
background-color: var(--surface);
|
||||
color: var(--ink);
|
||||
font-family: var(--font-body);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
transition: background-color var(--dur-normal), color var(--dur-normal);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100dvh;
|
||||
line-height: var(--leading-normal);
|
||||
overflow-x: hidden;
|
||||
background: var(--surface);
|
||||
transition: background-color var(--dur-normal);
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: color var(--dur-fast);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
button, input, select, textarea {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.serif {
|
||||
font-family: var(--font-serif);
|
||||
}
|
||||
|
||||
.italic {
|
||||
font-family: var(--font-serif);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
width: min(100% - 2 * var(--pad-inline), var(--container));
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
/* ── 접근성 스킵 링크 ── */
|
||||
.skip-link {
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
z-index: 1000;
|
||||
padding: 0.5rem 1.25rem;
|
||||
background: var(--surface-inverse);
|
||||
color: var(--ink-inverse);
|
||||
border-radius: var(--radius-xs);
|
||||
transform: translateY(-200%);
|
||||
transition: transform var(--dur-fast);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
.skip-link:focus {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* ── 상단 헤더 & 조도 스위처 (GNB SSOT) ── */
|
||||
.site-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
background: rgba(245, 243, 239, 0.94);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border-bottom: 1px solid var(--line);
|
||||
min-height: 64px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: background-color var(--dur-normal), border-color var(--dur-normal);
|
||||
}
|
||||
|
||||
body[data-ambiance="night"] .site-header {
|
||||
background: rgba(20, 19, 18, 0.94);
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
text-decoration: none;
|
||||
color: var(--ink);
|
||||
font-family: var(--font-serif);
|
||||
font-weight: 700;
|
||||
font-size: var(--step-1);
|
||||
letter-spacing: 0.08em;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.brand-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--radius-xs);
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
color: var(--accent);
|
||||
font-family: var(--font-serif);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.brand-han {
|
||||
font-size: var(--step--1);
|
||||
color: var(--accent);
|
||||
margin-left: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
text-decoration: none;
|
||||
color: var(--ink-muted);
|
||||
font-size: var(--step--1);
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.01em;
|
||||
transition: color var(--dur-fast);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-links a:hover,
|
||||
.nav-links a.active {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 조도 앰비언스 모드 스위처 (Day vs Night) */
|
||||
.ambiance-switcher,
|
||||
.ambiance-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
background: var(--surface-card);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-xs);
|
||||
padding: 2px;
|
||||
gap: 2px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ambiance-btn {
|
||||
padding: 4px 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--ink-muted);
|
||||
transition: all var(--dur-fast);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ambiance-btn.is-active,
|
||||
.ambiance-btn.active {
|
||||
background: var(--surface-raised);
|
||||
color: var(--ink);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* ── 버튼 시스템 & 더블 베젤 ── */
|
||||
.btn-materia {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
background: var(--surface-inverse);
|
||||
color: var(--ink-inverse);
|
||||
padding: 8px 16px;
|
||||
border-radius: var(--radius-xs);
|
||||
font-weight: 600;
|
||||
font-size: var(--step--1);
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
transition: transform var(--dur-fast), background var(--dur-fast), color var(--dur-fast);
|
||||
}
|
||||
|
||||
.btn-materia:hover {
|
||||
background: var(--accent);
|
||||
color: var(--accent-ink);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-materia:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* 더블 베젤 프레임 (Double-Bezel) */
|
||||
.bezel-outer,
|
||||
.frame.double-bezel {
|
||||
background: rgba(158, 128, 98, 0.06);
|
||||
border: 1px solid var(--line);
|
||||
padding: 6px;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.bezel-inner {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line-subtle);
|
||||
border-radius: calc(var(--radius-md) - 4px);
|
||||
padding: var(--space-6);
|
||||
}
|
||||
|
||||
/* ── 히어로 섹션 ── */
|
||||
.hero-section {
|
||||
padding-block: var(--space-6) var(--space-7);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
|
||||
gap: var(--space-6);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 3px 10px;
|
||||
border-radius: var(--radius-xs);
|
||||
background: var(--accent-light);
|
||||
color: var(--accent);
|
||||
font-size: var(--step--1);
|
||||
font-family: var(--font-mono);
|
||||
font-weight: 600;
|
||||
margin-bottom: var(--space-3);
|
||||
border: 1px solid var(--accent-surface);
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-3);
|
||||
font-weight: 700;
|
||||
line-height: var(--leading-tight);
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-3);
|
||||
text-wrap: balance;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-desc {
|
||||
font-size: var(--step-0);
|
||||
color: var(--ink-muted);
|
||||
max-width: var(--measure);
|
||||
line-height: var(--leading-normal);
|
||||
margin-bottom: var(--space-5);
|
||||
text-wrap: pretty;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.hero-ctas {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.hero-visual {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hero-frame {
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--line);
|
||||
box-shadow: 0 12px 32px -10px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.hero-frame img {
|
||||
width: 100%;
|
||||
aspect-ratio: 4/3;
|
||||
object-fit: cover;
|
||||
transition: transform var(--dur-slow);
|
||||
}
|
||||
|
||||
.hero-spec-tag {
|
||||
position: absolute;
|
||||
bottom: -14px;
|
||||
left: 16px;
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-xs);
|
||||
padding: 8px 14px;
|
||||
box-shadow: 0 8px 20px -4px rgba(0, 0, 0, 0.06);
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.spec-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.spec-sub {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── 엄선 프로젝트 섹션 ── */
|
||||
.works-section {
|
||||
padding-block: var(--space-7);
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.section-head {
|
||||
text-align: center;
|
||||
max-width: 640px;
|
||||
margin-inline: auto;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-2);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-2);
|
||||
text-wrap: balance;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.section-sub {
|
||||
font-size: var(--step-0);
|
||||
color: var(--ink-muted);
|
||||
text-wrap: pretty;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.works-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: var(--space-5);
|
||||
}
|
||||
|
||||
.work-card {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: transform var(--dur-normal), box-shadow var(--dur-normal), border-color var(--dur-normal);
|
||||
}
|
||||
|
||||
.work-card:hover {
|
||||
transform: translateY(-4px);
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 16px 36px -10px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.work-card-media {
|
||||
width: 100%;
|
||||
aspect-ratio: 16 / 11;
|
||||
overflow: hidden;
|
||||
background: var(--surface-subtle);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.work-card-media img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
.work-card:hover .work-card-media img {
|
||||
transform: scale(1.04);
|
||||
}
|
||||
|
||||
/* 🚀 텍스트 영역 내부 패딩을 24px로 넉넉하게 부여하여 0px 패딩 버그 완전 해결 */
|
||||
.work-card-body {
|
||||
padding: var(--space-5);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.work-card-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-1);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.work-card-type {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
color: var(--accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.work-card-desc {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
line-height: 1.65;
|
||||
margin-block: var(--space-1) var(--space-4);
|
||||
flex-grow: 1;
|
||||
text-wrap: pretty;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.work-card-actions {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.work-card-actions .btn-materia {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
padding: 10px 16px;
|
||||
font-size: var(--step--1);
|
||||
}
|
||||
|
||||
/* ── 물성 아카이브 섹션 ── */
|
||||
.material-section {
|
||||
padding-block: var(--space-7);
|
||||
background: var(--surface-card);
|
||||
border-top: 1px solid var(--line);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.material-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
|
||||
gap: var(--space-6);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mat-list {
|
||||
display: grid;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.mat-item {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-xs);
|
||||
padding: var(--space-4);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.mat-item-name {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.mat-item-desc {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
line-height: var(--leading-normal);
|
||||
text-wrap: pretty;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* ── 설계 프로세스 섹션 ── */
|
||||
.process-section {
|
||||
padding-block: var(--space-7);
|
||||
}
|
||||
|
||||
.process-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.process-card {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-xs);
|
||||
padding: var(--space-4);
|
||||
}
|
||||
|
||||
.process-num {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--step--1);
|
||||
color: var(--accent);
|
||||
font-weight: 700;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.process-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--step-0);
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.process-desc {
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
line-height: var(--leading-normal);
|
||||
text-wrap: pretty;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
/* ── 프라이빗 상담 섹션 ── */
|
||||
.contact-section {
|
||||
padding-block: var(--space-7);
|
||||
background: var(--surface-card);
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.contact-card {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-sm);
|
||||
padding: var(--space-5);
|
||||
max-width: 680px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: var(--step--1);
|
||||
font-weight: 600;
|
||||
color: var(--ink);
|
||||
margin-bottom: var(--space-2);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.form-select, .form-input, .form-textarea {
|
||||
width: 100%;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-xs);
|
||||
padding: 10px 14px;
|
||||
color: var(--ink);
|
||||
font-size: var(--step-0);
|
||||
transition: border-color var(--dur-fast);
|
||||
}
|
||||
|
||||
.form-select:focus, .form-input:focus, .form-textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── 푸터 ── */
|
||||
.site-footer {
|
||||
border-top: 1px solid var(--line);
|
||||
padding-block: var(--space-5);
|
||||
background: var(--surface);
|
||||
font-size: var(--step--1);
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.footer-inner {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
/* ── 반응형 미디어 쿼리 ── */
|
||||
@media (max-width: 860px) {
|
||||
.nav-links {
|
||||
display: none;
|
||||
}
|
||||
.hero-grid, .works-grid, .material-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
.process-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
.brand-han {
|
||||
display: none;
|
||||
}
|
||||
.header-actions .btn-materia {
|
||||
display: none;
|
||||
}
|
||||
.site-header {
|
||||
min-height: 56px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.process-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* SSOT Aliases */
|
||||
.site-head { position: sticky; top: 0; z-index: 50; background: rgba(245, 243, 239, 0.94); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid var(--line); padding-block: var(--space-3); }
|
||||
body[data-ambiance="night"] .site-head { background: rgba(20, 19, 18, 0.94); }
|
||||
.head-inner { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); }
|
||||
.wordmark { display: inline-flex; align-items: baseline; gap: var(--space-2); font-family: var(--font-serif); font-size: var(--step-1); font-weight: 700; color: var(--ink); text-decoration: none; }
|
||||
.wordmark-han { font-size: var(--step--1); color: var(--accent); font-weight: 500; }
|
||||
.nav { display: flex; align-items: center; gap: var(--space-5); }
|
||||
.nav a { font-size: var(--step--1); font-weight: 500; color: var(--ink-muted); text-decoration: none; }
|
||||
.nav a:hover, .nav a.active { color: var(--ink); }
|
||||
.head-actions { display: flex; align-items: center; gap: var(--space-3); flex-shrink: 0; }
|
||||
.site-foot { border-top: 1px solid var(--line); padding-block: var(--space-6); background: var(--surface); font-size: var(--step--1); color: var(--ink-muted); }
|
||||
.foot-inner { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-4); }
|
||||
94
apps/site/public/work/materia-interior/styles/tokens.css
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/* ==========================================================================
|
||||
마테리아 스튜디오 (MATERIA Spatial Design) — 디자인 토큰 SSOT
|
||||
프리셋: editorial + quiet-architecture
|
||||
컨셉: 트래버틴과 빛의 건축 — 물성과 침묵이 빚어내는 하이엔드 공간
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
/* 타이포그래피 스케일 */
|
||||
--step--1: 0.8125rem; /* 13px — 캡션·치수 */
|
||||
--step-0: 1rem; /* 16px — 본문 */
|
||||
--step-1: 1.1875rem; /* 19px — 소제목 */
|
||||
--step-2: clamp(1.375rem, 1.2rem + 0.9vw, 1.875rem); /* 30px — 섹션 제목 */
|
||||
--step-3: clamp(2.25rem, 1.5rem + 3vw, 3.8rem); /* 60px — 메인 표제 */
|
||||
|
||||
--leading-tight: 1.18;
|
||||
--leading-normal: 1.75;
|
||||
--measure: 54ch;
|
||||
|
||||
--font-serif: "MaruBuri", "Noto Serif KR", serif;
|
||||
--font-display: "MaruBuri", "Noto Serif KR", serif;
|
||||
--font-body: "Pretendard Variable", Pretendard, -apple-system, sans-serif;
|
||||
--font-mono: "JetBrains Mono", monospace;
|
||||
|
||||
/* 웜 트래버틴 스톤 색상 (Day 기본) */
|
||||
--surface: #f5f3ef;
|
||||
--surface-raised: #faf9f6;
|
||||
--surface-card: #ece8e1;
|
||||
--surface-sunken: #e4dfd6;
|
||||
--surface-inverse: #161514;
|
||||
|
||||
--ink: #161514;
|
||||
--ink-muted: #524f4b;
|
||||
--ink-faint: #8c8780;
|
||||
--ink-inverse: #f5f3ef;
|
||||
--ink-inverse-muted: #a39e96;
|
||||
|
||||
--line: #ddd8cf;
|
||||
--line-strong: #bfb8ab;
|
||||
--line-subtle: #eae5dc;
|
||||
--line-inverse: #33312f;
|
||||
|
||||
/* 단일 강조색 — 브러시드 브론즈 */
|
||||
--accent: #9e8062;
|
||||
--accent-hover: #856a4f;
|
||||
--accent-light: rgba(158, 128, 98, 0.12);
|
||||
--accent-surface: rgba(158, 128, 98, 0.2);
|
||||
--accent-ink: #ffffff;
|
||||
|
||||
--radius: 2px;
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 8px;
|
||||
|
||||
/* 간격 — SSOT 표준 */
|
||||
--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);
|
||||
|
||||
/* 컨테이너 및 패딩 — 전체 쇼케이스 절대 통일 SSOT */
|
||||
--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);
|
||||
}
|
||||
|
||||
/* ── 나이트 무드 앰비언스 ── */
|
||||
body[data-ambiance="night"] {
|
||||
--surface: #141312;
|
||||
--surface-raised: #1c1b19;
|
||||
--surface-card: #22201e;
|
||||
--surface-sunken: #2b2926;
|
||||
--surface-inverse: #f5f3ef;
|
||||
|
||||
--ink: #f5f3ef;
|
||||
--ink-muted: #a39e96;
|
||||
--ink-faint: #736e67;
|
||||
--ink-inverse: #141312;
|
||||
|
||||
--line: #2e2b27;
|
||||
--line-strong: #45413c;
|
||||
--line-subtle: #242220;
|
||||
|
||||
--accent: #c4a482;
|
||||
--accent-hover: #dbbe9d;
|
||||
--accent-light: rgba(196, 164, 130, 0.15);
|
||||
--accent-ink: #141312;
|
||||
}
|
||||
BIN
apps/site/src/assets/shots/work-cask-archive-2.png
Normal file
|
After Width: | Height: | Size: 560 KiB |
BIN
apps/site/src/assets/shots/work-cask-archive.png
Normal file
|
After Width: | Height: | Size: 438 KiB |
BIN
apps/site/src/assets/shots/work-cheongon-care-2.png
Normal file
|
After Width: | Height: | Size: 378 KiB |
BIN
apps/site/src/assets/shots/work-cheongon-care.png
Normal file
|
After Width: | Height: | Size: 449 KiB |
BIN
apps/site/src/assets/shots/work-materia-interior-2.png
Normal file
|
After Width: | Height: | Size: 561 KiB |
BIN
apps/site/src/assets/shots/work-materia-interior.png
Normal file
|
After Width: | Height: | Size: 474 KiB |
64
apps/site/src/components/ShowcaseHeroCanvas.astro
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
interface Props {
|
||||
class?: string;
|
||||
}
|
||||
const { class: className } = Astro.props;
|
||||
---
|
||||
|
||||
<div class:list={["hero-gl-wrap", className]} aria-hidden="true">
|
||||
<div class="hero-gl-fallback"></div>
|
||||
<canvas id="showcase-gl" class="hero-gl-canvas" style="opacity: 0;"></canvas>
|
||||
<div class="hero-gl-scrim"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import { boot } from "../gl/boot.ts";
|
||||
|
||||
const canvas = document.getElementById("showcase-gl") as HTMLCanvasElement | null;
|
||||
if (canvas) {
|
||||
boot(canvas, () => import("../gl/scenes/showcase-hero.ts"));
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.hero-gl-wrap {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
mask-image: linear-gradient(to bottom, black 70%, transparent 100%);
|
||||
-webkit-mask-image: linear-gradient(to bottom, black 70%, transparent 100%);
|
||||
}
|
||||
|
||||
.hero-gl-fallback {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(85% 60% at 50% -10%, color-mix(in oklab, var(--accent) 18%, transparent) 0%, transparent 70%),
|
||||
radial-gradient(60% 50% at 85% 20%, rgba(217, 155, 56, 0.12) 0%, transparent 60%),
|
||||
linear-gradient(180deg, var(--surface-sunken) 0%, var(--surface) 100%);
|
||||
}
|
||||
|
||||
.hero-gl-canvas {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
max-width: none !important;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hero-gl-scrim {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(circle at 50% 30%, rgba(12, 16, 23, 0.35) 0%, rgba(12, 16, 23, 0.8) 100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.hero-gl-canvas {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -34,6 +34,12 @@ import gaonLms from "../assets/shots/work-gaon-lms.png";
|
|||
import gaonLms2 from "../assets/shots/work-gaon-lms-2.png";
|
||||
import dureEnrollment from "../assets/shots/work-dure-enrollment.png";
|
||||
import dureEnrollment2 from "../assets/shots/work-dure-enrollment-2.png";
|
||||
import cheongonCare from "../assets/shots/work-cheongon-care.png";
|
||||
import cheongonCare2 from "../assets/shots/work-cheongon-care-2.png";
|
||||
import caskArchive from "../assets/shots/work-cask-archive.png";
|
||||
import caskArchive2 from "../assets/shots/work-cask-archive-2.png";
|
||||
import materiaInterior from "../assets/shots/work-materia-interior.png";
|
||||
import materiaInterior2 from "../assets/shots/work-materia-interior-2.png";
|
||||
|
||||
export interface WorkItem {
|
||||
slug: string;
|
||||
|
|
@ -45,6 +51,7 @@ export interface WorkItem {
|
|||
date: string;
|
||||
metrics: string[];
|
||||
href: string;
|
||||
subLinks?: { label: string; href: string }[];
|
||||
shot: ImageMetadata;
|
||||
shotAlt?: ImageMetadata;
|
||||
alt: string;
|
||||
|
|
@ -258,4 +265,60 @@ export const WORK: WorkItem[] = [
|
|||
alt: "두레대학 수강신청 — 과목 원장 목록과 주홍 도장 블록이 놓이는 주간 시간표 격자",
|
||||
size: "md",
|
||||
},
|
||||
|
||||
/* ── 7행: 신규 쇼케이스 3종 (2 + 2 + 2) ── */
|
||||
{
|
||||
slug: "cheongon-care",
|
||||
name: "청온 케어 (淸溫)",
|
||||
kind: "위생 케어 & 관제 콘솔 · 2모드",
|
||||
concept: "임상 수준의 6단계 위생 프로토콜 — 정찰제 견적과 실시간 배차 관제 콘솔",
|
||||
risk: "고객용 견적 신청 폼과 관리자용 관제 대시보드가 단일 웹앱에서 실시간 상태를 공유하는 풀-루프 인터랙션",
|
||||
preset: "ledger-console",
|
||||
date: "2026-08",
|
||||
metrics: ["고객·관리자 2모드", "실시간 정찰제 견적기", "32개 QC 체크리스트", "에메랄드 1색", "하드 게이트 14/14"],
|
||||
href: "/work/cheongon-care/",
|
||||
subLinks: [
|
||||
{ label: "임상 6단계 위생 프로토콜 & ATP 리포트", href: "/work/cheongon-care/protocol/" }
|
||||
],
|
||||
shot: cheongonCare,
|
||||
shotAlt: cheongonCare2,
|
||||
alt: "청온 케어 — 정밀 입주 케어가 완료된 거실 전경과 독일 카처 고온 스팀 위생 장비",
|
||||
size: "sm",
|
||||
},
|
||||
{
|
||||
slug: "cask-archive",
|
||||
name: "캐스크 아카이브 (樽室)",
|
||||
kind: "독립병입자 위스키바 & 도슨트",
|
||||
concept: "시간과 배럴이 빚어낸 단 하나의 원액 — 독립병입자 공식 인증 원장과 1:1 도슨트",
|
||||
risk: "일반 메뉴판 대신 단일 캐스크 넘버와 통관 필증이 기록된 캐스크 원장 및 향미 필터를 첫 화면에 배치",
|
||||
preset: "editorial-archival",
|
||||
date: "2026-08",
|
||||
metrics: ["독립병입자 4종 인증", "실시간 캐스크 원장 검색", "1:1 도슨트 예약", "앰버 골드 1색", "하드 게이트 14/14"],
|
||||
href: "/work/cask-archive/",
|
||||
subLinks: [
|
||||
{ label: "1:1 위스키 도슨트 테이스팅 마스터클래스", href: "/work/cask-archive/docent/" }
|
||||
],
|
||||
shot: caskArchive,
|
||||
shotAlt: caskArchive2,
|
||||
alt: "캐스크 아카이브 — 오크 배럴 상판 위 싱글 캐스크 위스키 보틀과 스코틀랜드 숙성고 전경",
|
||||
size: "sm",
|
||||
},
|
||||
{
|
||||
slug: "materia-interior",
|
||||
name: "마테리아 스튜디오 (空間素材)",
|
||||
kind: "하이엔드 공간 인테리어 건축",
|
||||
concept: "빛과 트래버틴이 빚어내는 침묵 — 물성과 자연광의 궤적을 설계하는 아틀리에",
|
||||
risk: "썸네일 그리드를 버리고 트래버틴·오크·리넨의 실측 물성 스펙과 자연광/야간 조도 앰비언스 실시간 전환을 제공",
|
||||
preset: "editorial",
|
||||
date: "2026-08",
|
||||
metrics: ["자연광·야간 조도 전환", "트래버틴 물성 스펙", "더블 베젤 갤러리", "브론즈 1색", "하드 게이트 14/14"],
|
||||
href: "/work/materia-interior/",
|
||||
subLinks: [
|
||||
{ label: "24개 공간 심층 아카이브 갤러리 (한남 듀플렉스)", href: "/work/materia-interior/projects/hannam-duplex/" }
|
||||
],
|
||||
shot: materiaInterior,
|
||||
shotAlt: materiaInterior2,
|
||||
alt: "마테리아 스튜디오 — 트래버틴 벽체 펜트하우스 거실 전경과 천연 마감재 플랫레이",
|
||||
size: "sm",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
71
apps/site/src/gl/boot.ts
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* Three.js 지연 로드 부트스트랩
|
||||
* designpaca/references/three.md 코드 A 준수
|
||||
*/
|
||||
export async function boot(
|
||||
canvas: HTMLCanvasElement | null,
|
||||
loader: () => Promise<{ default: (canvas: HTMLCanvasElement, opts: any) => () => void }>
|
||||
) {
|
||||
if (!canvas || !gate()) {
|
||||
canvas?.remove();
|
||||
return null;
|
||||
}
|
||||
|
||||
await inViewport(canvas);
|
||||
|
||||
try {
|
||||
const { default: mount } = await loader();
|
||||
const css = getComputedStyle(document.documentElement);
|
||||
const dispose = mount(canvas, { css });
|
||||
|
||||
const dur = css.getPropertyValue("--dur-normal").trim() || "350ms";
|
||||
const ease = css.getPropertyValue("--ease-out").trim() || "ease";
|
||||
canvas.style.transition = `opacity ${dur} ${ease}`;
|
||||
requestAnimationFrame(() => {
|
||||
canvas.style.opacity = "1";
|
||||
});
|
||||
|
||||
window.addEventListener("pagehide", dispose, { once: true });
|
||||
return dispose;
|
||||
} catch (err) {
|
||||
console.warn("[designpaca:three] WebGL init fallback:", err);
|
||||
canvas.remove();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function gate(): boolean {
|
||||
if (typeof window === "undefined") return false;
|
||||
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return false;
|
||||
if ((navigator as any).connection?.saveData) return false;
|
||||
if (((navigator as any).deviceMemory ?? 8) < 4 || (navigator.hardwareConcurrency ?? 8) < 4) return false;
|
||||
|
||||
try {
|
||||
const probe = document.createElement("canvas");
|
||||
const gl = probe.getContext("webgl2") || probe.getContext("webgl");
|
||||
if (!gl) return false;
|
||||
gl.getExtension("WEBGL_lose_context")?.loseContext();
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function inViewport(el: HTMLElement): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (typeof IntersectionObserver === "undefined") {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const io = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
io.disconnect();
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
{ rootMargin: "200px" }
|
||||
);
|
||||
io.observe(el);
|
||||
});
|
||||
}
|
||||
166
apps/site/src/gl/scenes/showcase-hero.ts
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
import * as THREE from "three";
|
||||
import { createStage } from "../stage.ts";
|
||||
|
||||
const VERT = /* glsl */ `
|
||||
void main() {
|
||||
gl_Position = vec4(position.xy, 0.0, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
const FRAG = /* glsl */ `
|
||||
precision highp float;
|
||||
uniform float uTime;
|
||||
uniform float uScroll;
|
||||
uniform vec2 uResolution;
|
||||
uniform vec2 uPointer;
|
||||
uniform vec3 uSurface;
|
||||
uniform vec3 uRaised;
|
||||
uniform vec3 uAccent;
|
||||
uniform vec3 uAccent2;
|
||||
|
||||
// Simplex 2D noise
|
||||
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
|
||||
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
|
||||
vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }
|
||||
|
||||
float snoise(vec2 v) {
|
||||
const vec4 C = vec4(0.211324865405187,
|
||||
0.366025403784439,
|
||||
-0.577350269189626,
|
||||
0.024390243902439);
|
||||
vec2 i = floor(v + dot(v, C.yy));
|
||||
vec2 x0 = v - i + dot(i, C.xx);
|
||||
vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
|
||||
vec4 x12 = x0.xyxy + C.xxzz;
|
||||
x12.xy -= i1;
|
||||
i = mod289(i);
|
||||
vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));
|
||||
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
|
||||
m = m*m;
|
||||
m = m*m;
|
||||
vec3 x = 2.0 * fract(p * C.www) - 1.0;
|
||||
vec3 h = abs(x) - 0.5;
|
||||
vec3 ox = floor(x + 0.5);
|
||||
vec3 a0 = x - ox;
|
||||
m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);
|
||||
vec3 g;
|
||||
g.x = a0.x * x0.x + h.x * x0.y;
|
||||
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
|
||||
return 130.0 * dot(m, g);
|
||||
}
|
||||
|
||||
float fbm(vec2 p) {
|
||||
float v = 0.0;
|
||||
float a = 0.5;
|
||||
mat2 rot = mat2(cos(0.35), sin(0.35), -sin(0.35), cos(0.35));
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
v += a * snoise(p);
|
||||
p = rot * p * 1.75 + vec2(10.0);
|
||||
a *= 0.5;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Normalise coordinates to center, maintaining aspect ratio
|
||||
vec2 st = (gl_FragCoord.xy * 2.0 - uResolution) / max(uResolution.x, uResolution.y);
|
||||
|
||||
// Very gentle, slow breathing tempo (ambient silk light wave, no storm vortex)
|
||||
float t = uTime * 0.035;
|
||||
|
||||
// Gentle pointer glow displacement
|
||||
vec2 pc = (uPointer - 0.5) * 1.5;
|
||||
float pDist = length(st - pc);
|
||||
vec2 pDrift = normalize(st - pc + 1e-4) * exp(-pDist * 2.8) * 0.06;
|
||||
|
||||
// Broad, calm rolling ambient wave
|
||||
vec2 waveCoords = st * 1.1 + pDrift;
|
||||
float n1 = fbm(waveCoords + vec2(t * 0.1, t * 0.07));
|
||||
float n2 = fbm(waveCoords * 1.3 - vec2(t * 0.05, n1 * 0.35));
|
||||
|
||||
float lightField = fbm(waveCoords + vec2(n2 * 0.5, t * 0.04));
|
||||
|
||||
// Base background colors
|
||||
vec3 col = mix(uSurface, uRaised, clamp(lightField * 0.65 + 0.35, 0.0, 1.0));
|
||||
|
||||
// Subtle, elegant emerald & amber mineral glows in soft ambient pockets
|
||||
float accentGlow = smoothstep(-0.25, 0.65, n1) * 0.28;
|
||||
float goldGlow = smoothstep(-0.15, 0.7, n2) * 0.14;
|
||||
|
||||
col = mix(col, uAccent, accentGlow);
|
||||
col = mix(col, uAccent2, goldGlow);
|
||||
|
||||
// Soft vignette
|
||||
float vignette = smoothstep(1.35, 0.35, length(st));
|
||||
col *= (0.75 + 0.25 * vignette);
|
||||
|
||||
// Grain dither to eliminate banding
|
||||
float grain = (fract(sin(dot(gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453) - 0.5) * (1.2 / 255.0);
|
||||
col += grain;
|
||||
|
||||
gl_FragColor = vec4(col, 0.92);
|
||||
}
|
||||
`;
|
||||
|
||||
export default function mount(canvas: HTMLCanvasElement, { css }: { css: CSSStyleDeclaration }) {
|
||||
const stage = createStage(canvas, { dprMax: Math.min(window.devicePixelRatio || 1, 1.5), alpha: true });
|
||||
|
||||
const getColor = (token: string, fallback: string) => {
|
||||
const val = css.getPropertyValue(token).trim();
|
||||
return new THREE.Color(val || fallback);
|
||||
};
|
||||
|
||||
// Fullscreen Triangle
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array([-1, -1, 0, 3, -1, 0, -1, 3, 0]), 3));
|
||||
|
||||
const uniforms = {
|
||||
uTime: { value: 0 },
|
||||
uScroll: { value: 0 },
|
||||
uResolution: { value: new THREE.Vector2(1, 1) },
|
||||
uPointer: { value: new THREE.Vector2(0.5, 0.5) },
|
||||
uSurface: { value: getColor("--surface-raised", "#121820") },
|
||||
uRaised: { value: getColor("--surface-sunken", "#080c11") },
|
||||
uAccent: { value: getColor("--accent", "#3ee5b3") },
|
||||
uAccent2: { value: new THREE.Color("#d99b38") }, // Warm gold mineral glow
|
||||
};
|
||||
|
||||
const mesh = new THREE.Mesh(
|
||||
geometry,
|
||||
new THREE.ShaderMaterial({
|
||||
vertexShader: VERT,
|
||||
fragmentShader: FRAG,
|
||||
uniforms,
|
||||
depthTest: false,
|
||||
depthWrite: false,
|
||||
transparent: true,
|
||||
})
|
||||
);
|
||||
mesh.frustumCulled = false;
|
||||
stage.scene.add(mesh);
|
||||
|
||||
stage.onResize = (w: number, h: number, dpr: number) => {
|
||||
uniforms.uResolution.value.set(w * dpr, h * dpr);
|
||||
};
|
||||
stage.onResize(stage.size.w, stage.size.h, stage.size.dpr);
|
||||
|
||||
const targetPointer = new THREE.Vector2(0.5, 0.5);
|
||||
const onPointerMove = (e: MouseEvent) => {
|
||||
targetPointer.set(e.clientX / window.innerWidth, 1 - e.clientY / window.innerHeight);
|
||||
};
|
||||
window.addEventListener("pointermove", onPointerMove, { passive: true });
|
||||
|
||||
stage.add((t: number, dt: number) => {
|
||||
uniforms.uTime.value = t;
|
||||
uniforms.uScroll.value = window.scrollY || 0;
|
||||
|
||||
// Smooth pointer lerp
|
||||
uniforms.uPointer.value.lerp(targetPointer, Math.min(1, dt * 2.5));
|
||||
});
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("pointermove", onPointerMove);
|
||||
geometry.dispose();
|
||||
(mesh.material as THREE.Material).dispose();
|
||||
};
|
||||
}
|
||||
133
apps/site/src/gl/stage.ts
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import * as THREE from "three";
|
||||
|
||||
export interface StageOptions {
|
||||
dprMax?: number;
|
||||
alpha?: boolean;
|
||||
}
|
||||
|
||||
export function createStage(canvas: HTMLCanvasElement, { dprMax = 1.5, alpha = true }: StageOptions = {}) {
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
canvas,
|
||||
alpha,
|
||||
antialias: false,
|
||||
stencil: false,
|
||||
powerPreference: "high-performance",
|
||||
});
|
||||
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||
renderer.toneMapping = THREE.NoToneMapping;
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
|
||||
camera.position.z = 5;
|
||||
|
||||
const size = { w: 0, h: 0, dpr: 1 };
|
||||
const updaters = new Set<(t: number, dt: number) => void>();
|
||||
let running = false;
|
||||
let last = 0;
|
||||
const t0 = performance.now();
|
||||
|
||||
const draw = (t: number, dt: number) => {
|
||||
for (const f of updaters) f(t, dt);
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
|
||||
const tick = (now: number) => {
|
||||
const dt = Math.min((now - last) / 1000, 1 / 20);
|
||||
last = now;
|
||||
draw((now - t0) / 1000, dt);
|
||||
};
|
||||
|
||||
const start = () => {
|
||||
if (!running) {
|
||||
running = true;
|
||||
last = performance.now();
|
||||
renderer.setAnimationLoop(tick);
|
||||
}
|
||||
};
|
||||
|
||||
const stop = () => {
|
||||
running = false;
|
||||
renderer.setAnimationLoop(null);
|
||||
};
|
||||
|
||||
function resize() {
|
||||
const r = canvas.getBoundingClientRect();
|
||||
const w = Math.max(1, Math.round(r.width));
|
||||
const h = Math.max(1, Math.round(r.height));
|
||||
const dpr = Math.min(window.devicePixelRatio || 1, dprMax);
|
||||
|
||||
if (w === size.w && h === size.h && dpr === size.dpr) return;
|
||||
Object.assign(size, { w, h, dpr });
|
||||
|
||||
renderer.setPixelRatio(dpr);
|
||||
renderer.setSize(w, h, false);
|
||||
camera.aspect = w / h;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
stage.onResize?.(w, h, dpr);
|
||||
if (!running) draw(0, 0);
|
||||
}
|
||||
|
||||
const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(resize) : null;
|
||||
ro?.observe(canvas);
|
||||
|
||||
const io =
|
||||
typeof IntersectionObserver !== "undefined"
|
||||
? new IntersectionObserver(([e]) => (e.isIntersecting ? start() : stop()), { rootMargin: "10%" })
|
||||
: null;
|
||||
io?.observe(canvas);
|
||||
|
||||
const onVis = () => (document.hidden ? stop() : start());
|
||||
document.addEventListener("visibilitychange", onVis);
|
||||
|
||||
const onLost = (e: Event) => {
|
||||
e.preventDefault();
|
||||
stop();
|
||||
};
|
||||
canvas.addEventListener("webglcontextlost", onLost);
|
||||
|
||||
const stage = {
|
||||
renderer,
|
||||
scene,
|
||||
camera,
|
||||
size,
|
||||
start,
|
||||
stop,
|
||||
onResize: null as ((w: number, h: number, dpr: number) => void) | null,
|
||||
renderOnce: () => draw(0, 0),
|
||||
add(f: (t: number, dt: number) => void) {
|
||||
updaters.add(f);
|
||||
return () => updaters.delete(f);
|
||||
},
|
||||
setDprMax(v: number) {
|
||||
dprMax = v;
|
||||
size.dpr = -1;
|
||||
resize();
|
||||
},
|
||||
dispose() {
|
||||
stop();
|
||||
ro?.disconnect();
|
||||
io?.disconnect();
|
||||
document.removeEventListener("visibilitychange", onVis);
|
||||
canvas.removeEventListener("webglcontextlost", onLost);
|
||||
scene.traverse((o: any) => {
|
||||
o.geometry?.dispose();
|
||||
const mats = [o.material].flat().filter(Boolean);
|
||||
for (const m of mats) {
|
||||
for (const u of Object.values(m.uniforms ?? {}) as any[]) {
|
||||
if (u?.value?.isTexture) u.value.dispose();
|
||||
}
|
||||
m.dispose();
|
||||
}
|
||||
});
|
||||
scene.clear();
|
||||
renderer.dispose();
|
||||
renderer.forceContextLoss();
|
||||
updaters.clear();
|
||||
},
|
||||
};
|
||||
|
||||
resize();
|
||||
return stage;
|
||||
}
|
||||
|
|
@ -7,10 +7,21 @@
|
|||
*::before,
|
||||
*::after { box-sizing: border-box; }
|
||||
|
||||
img,
|
||||
picture,
|
||||
video,
|
||||
canvas,
|
||||
svg {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
html {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
scroll-behavior: smooth;
|
||||
background: var(--surface);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html { scroll-behavior: auto; }
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
import puppeteer from "puppeteer-core";
|
||||
import path from "node:path";
|
||||
import url from "node:url";
|
||||
|
||||
const here = path.dirname(url.fileURLToPath(import.meta.url));
|
||||
const CHROME = "C:/Program Files/Google/Chrome/Application/chrome.exe";
|
||||
|
||||
const browser = await puppeteer.launch({ executablePath: CHROME, headless: "new", args: ["--force-device-scale-factor=1"] });
|
||||
const page = await browser.newPage();
|
||||
await page.setCacheEnabled(false);
|
||||
|
||||
// 라이브 배포 URL — 사용자가 보는 그대로
|
||||
for (const w of [360, 390, 412]) {
|
||||
await page.setViewport({ width: w, height: 844, isMobile: true, hasTouch: true });
|
||||
await page.goto("https://designpaca.chanpaca.net/work/dure-enrollment/", { waitUntil: "networkidle0" });
|
||||
await page.evaluate(() => document.fonts.ready);
|
||||
await new Promise((r) => setTimeout(r, 250));
|
||||
const m = await page.evaluate(() => {
|
||||
const layout = document.querySelector(".layout");
|
||||
const h2 = document.querySelector("#cat-h");
|
||||
const card = document.querySelector(".course-row");
|
||||
const appbar = document.querySelector(".appbar-inner");
|
||||
const rl = (el) => (el ? Math.round(el.getBoundingClientRect().left) : null);
|
||||
return {
|
||||
cssV: (document.querySelector('link[rel="stylesheet"]')?.getAttribute("href") || "").match(/v=\d+/)?.[0],
|
||||
layoutPad: getComputedStyle(layout).padding,
|
||||
h2Left: rl(h2),
|
||||
cardLeft: rl(card),
|
||||
appbarPadLeft: getComputedStyle(appbar).paddingLeft,
|
||||
over: document.documentElement.scrollWidth - document.documentElement.clientWidth,
|
||||
};
|
||||
});
|
||||
console.log(`[${w}] css=${m.cssV} layoutPad="${m.layoutPad}" h2Left=${m.h2Left} cardLeft=${m.cardLeft} appbarPadL=${m.appbarPadLeft} over=+${m.over}`);
|
||||
if (w === 390) await page.screenshot({ path: path.join(here, "__shots__", "diag3-dure-live-390.png") });
|
||||
}
|
||||
await browser.close();
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
// 임시 구문 스캐너 — 괄호·템플릿 리터럴 균형 줄 단위 추적
|
||||
import fs from "node:fs";
|
||||
const src = fs.readFileSync(process.argv[2], "utf8");
|
||||
let inTpl = false, inStr = null, inInterp = 0, line = 1;
|
||||
const stack = [];
|
||||
const push = (t) => stack.push(t + "@" + line);
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
const c = src[i], n = src[i + 1];
|
||||
if (c === "\n") line++;
|
||||
if (inStr) {
|
||||
if (c === "\\") { i++; continue; }
|
||||
if (c === inStr) inStr = null;
|
||||
continue;
|
||||
}
|
||||
if (inTpl) {
|
||||
if (c === "\\") { i++; continue; }
|
||||
if (c === "$" && n === "{") { push("${"); inInterp++; i++; continue; }
|
||||
if (c === "`") { inTpl = false; const m = stack.pop(); }
|
||||
continue;
|
||||
}
|
||||
if (c === "`") { inTpl = true; push("tpl"); continue; }
|
||||
if (c === "'" || c === '"') { inStr = c; continue; }
|
||||
if (c === "/" && n === "/") { while (i < src.length && src[i] !== "\n") i++; continue; }
|
||||
if (c === "(" || c === "[" || c === "{") push(c);
|
||||
else if (c === ")" || c === "]" || c === "}") {
|
||||
const m = stack.pop();
|
||||
if (!m) { console.log("여분의 닫기", c, "줄", line); process.exit(0); }
|
||||
}
|
||||
}
|
||||
console.log("미닫힘:", stack.slice(-8).join(", ") || "없음");
|
||||
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
|
@ -1,4 +1,4 @@
|
|||
# E2E 시나리오 게이트 — 2026-08-23 06:30
|
||||
# E2E 시나리오 게이트 — 2026-08-23 12:48
|
||||
|
||||
단언 1805 · 통과 1805 · 실패 0 — **GREEN — 전 단언 통과**
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
# 검증 리포트 — 2026-08-23 06:30
|
||||
# 검증 리포트 — 2026-08-23 12:48
|
||||
|
||||
게이트: **전 계층 통과 — 배포 가능** · 총 103.6초
|
||||
게이트: **전 계층 통과 — 배포 가능** · 총 96.5초
|
||||
|
||||
| 계층 | 결과 | 항목 | 소요 |
|
||||
|---|---|---|---|
|
||||
| L0-정적/stylelint | PASS | PASS — | 8.0s |
|
||||
| L0-정적/stylelint | PASS | PASS — | 1.6s |
|
||||
| L0-정식/html-validate | PASS | PASS — | 1.3s |
|
||||
| L1-단위/계산로직 | PASS | PASS 41 | 0.1s |
|
||||
| L2-기능/감사 | PASS | PASS 72 | 9.7s |
|
||||
| L2-불변식/렌더 | PASS | PASS 10 | 17.2s |
|
||||
| L3-시각회귀/diff | PASS | PASS 30 | 11.7s |
|
||||
| L4-WebKit | PASS | PASS 8 | 3.9s |
|
||||
| L5-탐색/키보드 | PASS | PASS 14 | 6.3s |
|
||||
| L6-시나리오/E2E | PASS | PASS — | 45.4s |
|
||||
| L2-기능/감사 | PASS | PASS 72 | 10.2s |
|
||||
| L2-불변식/렌더 | PASS | PASS 10 | 17.5s |
|
||||
| L3-시각회귀/diff | PASS | PASS 30 | 12.2s |
|
||||
| L4-WebKit | PASS | PASS 8 | 4.7s |
|
||||
| L5-탐색/키보드 | PASS | PASS 14 | 6.4s |
|
||||
| L6-시나리오/E2E | PASS | PASS — | 42.6s |
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
# designpaca
|
||||
|
||||
## 0.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- CSS 변수 및 토큰 안전 폴백 의무화 (`var(--step-4, clamp(...))`) — 토큰 누락 시 16px 축소 및 위계 역전 방지
|
||||
- 서브페이지 및 에셋 경로 무결성 게이트 — 404 브로큰 링크 차단 및 안전 리다이렉트 동봉
|
||||
- 다단 데이터 테이블 1120px 컨테이너 핏 및 테마 맞춤 앰버/다크 커스텀 스크롤바 표준화
|
||||
- 완료 선언 전 헤드리스 렌더링 실측 게이트 (`getComputedStyle` 폰트/패딩/오버플로) 강화
|
||||
|
||||
## 0.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "designpaca",
|
||||
"version": "0.9.0",
|
||||
"version": "0.9.1",
|
||||
"description": "웹 디자인 파이프라인 스킬 — Claude Code · Codex · Cursor 에 한 줄로 설치한다",
|
||||
"keywords": [
|
||||
"design",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
# @designpaca/core
|
||||
|
||||
## 0.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Internal core engine synchronization for 0.9.1 release.
|
||||
|
||||
## 0.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@designpaca/core",
|
||||
"version": "0.9.0",
|
||||
"version": "0.9.1",
|
||||
"private": true,
|
||||
"description": "designpaca 설치 엔진 — 타깃 어댑터, 매니페스트, 드리프트 감지",
|
||||
"type": "module",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
# CHANGELOG
|
||||
|
||||
## 0.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- CSS 변수 및 토큰 안전 폴백 의무화 (`var(--step-4, clamp(...))`) — 토큰 누락 시 16px 축소 및 위계 역전 방지
|
||||
- 서브페이지 및 에셋 경로 무결성 게이트 — 404 브로큰 링크 차단 및 안전 리다이렉트 동봉
|
||||
- 다단 데이터 테이블 1120px 컨테이너 핏 및 테마 맞춤 앰버/다크 커스텀 스크롤바 표준화
|
||||
- 완료 선언 전 헤드리스 렌더링 실측 게이트 (`getComputedStyle` 폰트/패딩/오버플로) 강화
|
||||
|
||||
## 0.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@designpaca/skill",
|
||||
"version": "0.9.0",
|
||||
"version": "0.9.1",
|
||||
"private": true,
|
||||
"description": "designpaca 스킬 원본 — SKILL.md 와 참조 문서",
|
||||
"scripts": {
|
||||
|
|
|
|||