o2o-site-AEO/solution/site/src/index.css
Mina Choi 00e13bca7f [feat] solution/site,shared: 발행본을 /s/stay 목업에 맞춘다 — 잃어버린 CSS 토큰 복원 + 섹션 마크업 이식
목업(/s/stay)이 참조하는 스타일시트가 서버에서 사라져(404) 그 화면을 기준으로 삼을 수
없었다. 브라우저 캐시에 남아 있던 규칙을 꺼내 레포에 되돌리고, 섹션 마크업을 목업 HTML
에서 그대로 옮겼다. Playwright 대조로 섹션 래퍼·제목 16/17, 안쪽 구조 14/17 일치.

- index.css: --fs-display~--fs-xs(유동 타이포 7) · --section-space · --color-line/muted ·
  .h2 .h3 .panel .paper .measure .border-line .text-muted .divide-line .slider-viewport/track
  ★ 이 토큰이 없던 동안 컴포넌트가 var(--fs-display)를 써도 브라우저가 조용히 무시했다 —
    히어로 제목이 본문 크기로 나오던 원인
- HeroSection: 가운데 → 좌하단. 사진 위에 글자를 한가운데 얹으면 피사체를 정확히 가린다
- AnswerBlock·EssentialInfo·Units·Gallery·Location·Faq·LocalGuide·Weather·About:
  목업 마크업 그대로. embla 를 scroll-snap 으로 바꿔 스크립트 없이도 레일이 밀린다
- FestivalSection(계절 탭) · StorySection(이야기 탭 래퍼) · items/TripMap(OSM 타일 지도) 신설
  ★ 지도는 iframe 이 아니라 타일을 직접 깐다 — iframe 은 핀을 하나밖에 못 찍어
    "어떤 순서로 도는가" 를 그릴 수 없다
- items: itinerary·event·video kind 추가(파서에 없어 payload 까지 실려 오고도 화면에서
  사라지던 것) · Rail 을 slider-viewport/track 으로 · SongsSection 을 턴테이블로
- color.ts: 선 색을 secondary → mix(bg, text, .2). secondary 는 '본문 다음으로 진한
  글자색' 이라 선으로 쓰면 표와 카드가 격자무늬처럼 새까맣게 그어진다
- seo/head.ts: --tpl-texture. 없으면 색만 갱지고 면은 매끈해서 인쇄물로 안 보인다
- seo/verify.ts: unitCode·numberOfRooms 를 화면 대조에서 뺀다
  ★ unitCode 는 ㎡의 ISO 코드로 priceCurrency 와 같은 성격인데 예외에 없었다. 그래서
    room_size 가 있는 사업장은 발행 게이트가 전부 막았다(실측: 가은채 객실 12개).
    stay 는 객실 2개 + room_size 없음이라 우연히 통과했다
- shared: LocalPlace.imageUrl/distanceMeters · FestivalEntry.imageUrl ·
  ItineraryStop 좌표 · TemplateLook.texture · people/chronicle/postcard imageUrl
  ★ 좌표·사진은 모델이 만드는 칸이 아니다. 공식 API 로 조회해 채운다

검증: tsc 통과 · Playwright 대조(목업 CSS 주입) 섹션 래퍼·제목 16/17, 안쪽 14/17.
남은 차이는 데이터 한계다 — people 사진은 위키에 원본이 없고(original:false),
weather.note 는 정적 페이지에 날씨 문장을 박는 문제라 보류.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP1ykMnWZFtLFpm2mow1Sw
2026-09-08 09:53:19 +09:00

181 lines
6.1 KiB
CSS

@import "tailwindcss";
@import "@o2o/shared/styles/base.css";
/*
* 발행 사이트의 색은 사장님이 고른 템플릿에서 온다.
* 프리렌더가 <head> 에 --tpl-* 를 심고(`seo/head.ts` themeStyle), 여기서 Tailwind 색으로 연결한다.
* 관리자 토큰(tokens.css)은 이 앱에 들어오지 않는다 — 두 색 체계를 섞지 않는다.
*
* 개발 서버에서는 <head> 주입이 없으므로 아래 :root 기본값이 쓰인다.
*/
:root {
--tpl-primary: #18181b;
--tpl-secondary: #52525b;
--tpl-bg: #ffffff;
--tpl-card: #fafafa;
--tpl-text: #09090b;
--tpl-accent: #2563eb;
/*
* 유동 타이포 — 화면 폭에 따라 자라는 글자 크기.
*
* ★ 이 토큰이 없던 동안 히어로 제목이 본문과 같은 크기로 나왔다. 섹션 컴포넌트들이
* var(--fs-display) 를 쓰는데 정의가 어디에도 없어 그냥 무시됐다(브라우저는 조용히 넘어간다).
* ★ 값은 목업(/s/stay)이 쓰던 것을 그대로 옮겼다 — 화면이 달라지면 목업과 어긋난다.
*/
--fs-display: clamp(1.75rem, 1.25rem + 2.2vw, 3rem);
--fs-h2: clamp(1.3125rem, 1.15rem + 0.7vw, 1.75rem);
--fs-h3: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
--fs-lead: clamp(0.9375rem, 0.9rem + 0.22vw, 1.0625rem);
--fs-body: clamp(0.9375rem, 0.91rem + 0.15vw, 1rem);
--fs-sm: clamp(0.8125rem, 0.8rem + 0.1vw, 0.875rem);
--fs-xs: clamp(0.75rem, 0.74rem + 0.06vw, 0.78125rem);
/* 섹션 세로 여백. 템플릿의 sectionSpace 를 상한으로 두고 좁은 화면에서만 줄인다. */
--section-space: clamp(2.25rem, 5vw, var(--tpl-section-space, 3.5rem));
/* 선·흐린 글자 — 템플릿 색에서 유도한다. 고정 회색을 쓰면 갱지 바탕에서 뜬다. */
--color-line: var(--tpl-border, color-mix(in oklab, var(--tpl-text, #09090b) 14%, transparent));
--color-muted: color-mix(in oklab, var(--tpl-text, #09090b) 60%, transparent);
}
@theme inline {
--color-brand: var(--tpl-primary);
--color-brand-soft: var(--tpl-secondary);
--color-surface: var(--tpl-bg);
--color-surface-alt: var(--tpl-card);
--color-ink: var(--tpl-text);
--color-accent: var(--tpl-accent);
--font-sans: 'Pretendard Variable', 'Noto Sans KR', system-ui, sans-serif;
--font-serif: 'Noto Serif KR', 'Batang', 'Times New Roman', serif;
}
html {
scroll-behavior: smooth;
/* 고정 헤더에 앵커가 가리지 않게. */
scroll-padding-top: 5rem;
}
body {
background-color: var(--color-surface);
color: var(--color-ink);
/* ★ 본문 서체도 템플릿이 정한다(theme.look → seo/head.ts). 토큰이 없는 옛 payload 에서는
지금까지와 똑같이 Noto Sans KR 로 떨어진다. */
font-family: var(--tpl-font-body, var(--font-sans));
font-feature-settings: "tnum" 1;
}
@layer components {
/* 제목 서체. 이름은 'serif' 로 남아 있지만 값은 템플릿이 정한다 —
레트로면 간판체, 심플이면 고딕이다. 토큰이 없으면 예전처럼 명조로 떨어진다. */
.serif {
font-family: var(--tpl-font-heading, var(--font-serif));
letter-spacing: var(--tpl-heading-tracking, normal);
}
/* 카드·패널 테두리 두께도 템플릿이 정한다. 레트로는 2px 라야 인쇄물처럼 보인다. */
.tpl-border {
border-width: var(--tpl-border-width, 1px);
}
/* 섹션 공통 폭 — 본문이 한 줄에 너무 길어지지 않게. */
.shell {
width: 100%;
max-width: 1120px;
margin-inline: auto;
padding-inline: 1rem;
}
@media (min-width: 640px) {
.shell {
padding-inline: 1.5rem;
}
}
/* 본문 한 줄 길이 상한. 68자를 넘기면 눈이 다음 줄을 못 찾는다. */
.measure {
max-width: 68ch;
}
/* 종이 질감 — 템플릿이 texture 를 주면 깔린다(레트로 갱지). 없으면 아무것도 안 깔린다. */
.paper {
background-image: var(--tpl-texture, none);
}
/* 카드·패널. 바탕보다 한 겹 앞으로 나온 면. */
.panel {
background-color: color-mix(in oklab, currentcolor 5%, transparent);
border: var(--tpl-border-width, 1px) solid var(--color-line);
border-radius: var(--tpl-radius, 0.75rem);
box-shadow: var(--tpl-shadow, none);
}
.panel-sunken {
background-color: color-mix(in oklab, currentcolor 6%, transparent);
}
.border-line {
border-color: var(--color-line);
}
/* divide-y 의 사이 선도 같은 색으로. Tailwind 기본은 회색이라 갱지 위에서 뜬다. */
.divide-line > :not([hidden]) ~ :not([hidden]) {
border-color: var(--color-line);
}
.text-muted {
color: var(--color-muted);
}
/* 소제목. h1 은 히어로가 인라인으로 쓰고, 그 아래 단계는 이 두 클래스가 맡는다. */
.h2 {
font-family: var(--tpl-font-heading, var(--font-serif));
font-size: var(--fs-h2);
font-weight: var(--tpl-heading-weight, 700);
letter-spacing: var(--tpl-heading-tracking, -0.01em);
line-height: 1.2;
}
.h3 {
font-family: var(--tpl-font-heading, var(--font-serif));
font-size: var(--fs-h3);
font-weight: var(--tpl-heading-weight, 700);
letter-spacing: var(--tpl-heading-tracking, -0.005em);
line-height: 1.35;
}
/* 간판체처럼 굵기가 한 벌뿐인 서체에 가짜 볼드가 씌워지는 것을 막는다. */
.serif,
.h2,
.h3 {
font-synthesis-weight: none;
}
.label {
font-size: var(--fs-xs);
color: var(--color-muted);
font-weight: 600;
}
.tpl-shadow {
box-shadow: var(--tpl-shadow, none);
}
}
@layer components {
/*
* 가로 레일 — 목업과 같은 클래스 이름. 캐러셀 라이브러리 없이 스크롤 스냅으로만 만든다.
* ★ 스크립트가 없어도 손가락·트랙패드로 밀린다. 라이브러리를 얹으면 그게 죽었을 때
* 레일 전체가 한 줄로 굳는다.
*/
.slider-viewport {
overflow-x: auto;
scrollbar-width: none;
padding-bottom: 0.75rem;
}
.slider-viewport::-webkit-scrollbar {
display: none;
}
.slider-track {
display: flex;
scroll-snap-type: x mandatory;
}
.slider-track > * {
scroll-snap-align: center;
}
}