@charset "utf-8";
/* layout.css - 페이지 레이아웃 골격 (수치 미확정, Placeholder 상태) */

/* 콘텐츠 최대 폭 래퍼 */
.container {
  /* TODO: max-width, padding 확정 후 작성 */
}

/* 헤더/푸터를 제외한 페이지 전체 영역 */
.page {
  /* TODO: 상하 여백 확정 후 작성 */
}

/* 본문 콘텐츠 영역 */
.page-content {
  /* TODO: 폭, 컬럼 구조 확정 후 작성 */
}

/* 사이드 영역 (필터/네비게이션 등) */
.sidebar {
  /* TODO: 폭, gap 확정 후 작성 */
}

/* 콘텐츠 내부 구획 단위 */
.section {
  /* TODO: 섹션 간 간격 확정 후 작성 */
}


/* ==================================================
   Header Layout (v4)
   구조: header(배경 100%) > header__inner(Service Frame 1680px, 중앙 정렬)

   - Header는 Sticky / Fixed가 아니다. 일반 Document Flow에 위치한다.
   - Header Content Frame은 Service Frame(1680)이 아니라
     Main Content Column(1400)에 정렬한다.

   Border Box는 계속 1680px(= Frame)이지만 우측에 Gap(40) + Wing(240) = 280px
   Padding을 두어 실제 Content Box가 1400px가 된다.

     Border Box  : Frame Left ----------------------- Frame Right (1680)
     Content Box : Frame Left ------- +1400 ------|   280px padding

   결과적으로
     Header Left  = Hero Left  = Category Left  = Main Section Left
     Header Right = Hero Right = Category Right = Main Section Right
   이 되어 Header가 Main Content의 일부처럼 읽힌다.

   좌측 Padding은 두지 않는다. .main-layout__inner 에도 좌우 Padding이 없어
   Content Column이 Frame Edge에서 시작하므로, Header만 24px 들여쓰면
   Logo가 Hero보다 24px 안쪽으로 밀려 정렬이 깨지기 때문이다.
================================================== */

.header {
  /* Intro Visual Integration (v1)
     Header는 자체 Surface(White Background)와 Border-Bottom을 갖지 않는다.
     Intro Background Layer(.hero__background)가 Header 뒤까지 올라와
     Header <-> Hero 가 하나의 배경 위에 놓이기 때문이다.

     position: relative 는 Flow에서 빼지 않으므로
     Header Height / Logo / GNB / Utility 위치는 그대로다.
     z-index 만 명시해 절대배치된 Intro Background Layer 위에 그려지게 한다.

     Header 자체에는 Shadow를 사용하지 않는다. */
  position: relative;
  z-index: var(--z-header);
}

.header__inner {
  display: flex;
  align-items: stretch; /* GNB Active Indicator를 위해 자식이 Header 높이를 채운다 */
  height: var(--header-height);
  max-width: var(--service-frame-width);
  margin: 0 auto;
  /* Padding 2단 구성 (box-sizing: border-box)

     1) 우측 Gap(40) + Wing(240) = 280px
        -> Border Box 1680 안에서 시각 Frame을 Main Content 1400px에 맞춘다.
     2) 그 1400px 안쪽으로 다시 좌우 40px Safe Padding (v6: 28 -> 40)
        -> Logo / Utility가 Hero Background Edge에 달라붙지 않게 한다.
        -> --space-10(40px) Token을 그대로 재사용한다.

     Border Box   : Frame Left ------------------------------- +1680
     시각 Frame   : Frame Left ------------- +1400 -----|  (Hero와 동일)
     Content Box  : Frame Left +40 ---- +1320 ----| +40 |  280

     Frame 자체를 1320px로 줄이지 않는다. Header Frame Left/Right는
     계속 Hero / Category / Main Section과 같은 x를 유지한다. */
  padding-left: var(--space-10);
  padding-right: calc(var(--content-wing-gap) + var(--wing-width) + var(--space-10));
}

/* Logo : 실제 asset 교체가 쉽도록 크기를 가진 독립 wrapper */
.header__logo {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  align-self: center;
  width: 160px;  /* TODO: 실제 Logo asset 확정 후 Token 승격 검토 */
  height: 30px;  /* TODO: 실제 Logo asset 확정 후 Token 승격 검토 */
}

.header__nav {
  display: flex;
  margin-left: 56px; /* Logo ↔ GNB 간격. TODO: 화면 검토 후 Token 승격 검토 */
}

/* Utility : Flexible Space 이후 오른쪽 끝 배치 */
.header__utility {
  display: flex;
  align-items: stretch; /* Dropdown 기준점을 Header 하단에 맞추기 위해 높이를 채운다 */
  margin-left: auto;    /* space-between을 쓰지 않고 여백을 흡수한다 */
  /* 기능 그룹 ↔ Account 그룹.
     v4: Header Frame이 1400으로 좁아지며 32 -> 28px (-12.5%) 압축.
     TODO: 화면 검토 후 Token 승격 검토 */
  gap: 28px;
}

/* 기능 그룹 (위치 설정 / 알림) */
.header__actions {
  display: flex;
  align-items: stretch;
  gap: 14px; /* v4: 16 -> 14px (-12.5%). TODO: 화면 검토 후 Token 승격 검토 */
}

/* Account 그룹 (로그인 / 회원가입) */
/* Account 그룹 (로그인).
   v5에서 회원가입 CTA를 제거해 자식이 로그인 하나뿐이므로 gap을 삭제했다.
   (Dead 규칙 제거. display / align-items는 Utility의 stretch 안에서
   로그인 Text를 세로 중앙에 두는 역할이라 유지한다)
   알림 ↔ 로그인 간격은 .header__utility 의 gap(28px)이 담당한다. */
.header__account {
  display: flex;
  align-items: center;
}


/* ==================================================
   Header Variant (v7)
   Header Component는 하나이고, "Surface를 갖는지"만 Variant로 나눈다.

     Base    : .header
               Surface(배경 / Border)를 갖지 않는 골격.
               Logo / GNB / Utility 배치와 높이만 담당한다.

     Main    : .header (Class 추가 없음)
               메인페이지는 Intro Background Layer(.hero__background)가
               Header 뒤까지 올라와 Header <-> Hero 가 하나의 배경 위에 놓인다.
               따라서 Header가 자기 Surface를 가지면 안 되므로 Base 그대로 쓴다.
               (기존 index.html Markup을 바꾸지 않기 위해 --main Modifier를
                새로 부여하지 않는다. Main = Base 라는 관계를 유지한다)

     Subpage : .header.header--sub
               Hero Background가 없으므로 Header가 스스로 White Surface를 갖고
               본문과 분리되어야 Navigation 영역으로 인식된다.

   Subpage Variant가 추가하는 것은 다음 두 줄뿐이다.
     - background-color : #FFFFFF (--bg-page)
     - border-bottom    : 1px --border-light

   Gray Background / Shadow / Sticky / 높이 변경 / Padding 변경을 넣지 않는다.
   Logo / GNB / Location / Notification / Login 은 전부 Base 규칙을 그대로
   상속하므로 Markup도 Main과 동일하다. (Color가 이미 Dark on Light 기준이라
   White Surface 위에서 대비 문제가 없다)

   1400 Alignment / 좌우 Safe Padding 40px 은 .header__inner 가 담당하므로
   Variant에서 다시 정의하지 않는다.
================================================== */

.header--sub {
  background-color: var(--bg-page); /* #FFFFFF */
  /* Header <-> 본문 구분. Gray Band나 Shadow 대신 가장 약한 Border Token만 쓴다. */
  border-bottom: 1px solid var(--border-light);
}


/* ==================================================
   Subpage Main Layout Variant
   .main-layout--sub

   Main Layout(1400 + 40 + 240) 골격 자체는 메인페이지와 동일하게 재사용하고,
   Wing의 Initial Y 보정만 되돌린다.

   메인페이지의 .main-wing 은 Header가 투명해서 Wing Column 상단 90px가
   "아무것도 담지 않는 예약 공백"이었기 때문에 margin-top: -90px 로 끌어올렸다.
   Subpage Header는 White Surface + Border를 가진 실체이므로 같은 값을 쓰면
   Wing Banner가 Header 뒤로 90px 파고들어 가려진다.

   Wing Sticky(top 32) / Slot Height / Gap 은 그대로 둔다.
================================================== */

.main-layout--sub .main-wing {
  margin-top: 0;
}


/* ==================================================
   Main Layout
   메인페이지 Service Frame 골격.

   구조: main-layout > __inner(1680px grid) > __content(1400px) + main-wing(240px)
   계산: 1400 + 40 + 240 = 1680

   1680px 내부에 다시 좌우 Padding을 넣지 않는다.
   (Content가 1400보다 작아지면 안 되기 때문)

   TODO(responsive): Viewport < 1680 구간의 Wing 노출 / Breakpoint 정책은
                     docs/ui-policy.md 기준 미확정이므로 이번 단계에서 확정하지 않는다.
                     현재는 Content가 줄고 Wing은 240px를 유지하는 최소 방어만 한다.
================================================== */

.main-layout__inner {
  display: grid;
  grid-template-columns: minmax(0, var(--content-width)) var(--wing-width);
  column-gap: var(--content-wing-gap);
  max-width: var(--service-frame-width);
  margin: 0 auto;
}

.main-layout__content {
  min-width: 0;
}


/* ==================================================
   Wing Layout
   Wing Stack 높이 = 320 x 3 + 16 x 2 = 992px

   역할 분리:
     .main-wing        → Grid Item / 상하 여백(32px / 32px)
     .main-wing__inner → Sticky 동작만 담당

   Sticky는 Main Layout 영역 안에서만 동작하고 Footer와 겹치지 않는다.
   position: fixed 를 사용하지 않는다.

   .main-wing 은 stretch(Grid 기본)를 유지해야 한다.
   align-self: start 로 두면 .main-wing 높이가 콘텐츠(32 + 992 + 32)에 딱 맞아
   Sticky 자식의 이동 가능 범위가 0이 되어 고정이 전혀 동작하지 않는다.
   stretch 상태에서 Grid Row 전체 높이를 차지해야 __inner 가 움직일 여지가 생긴다.
================================================== */

.main-wing {
  align-self: stretch; /* Grid 기본값. __inner Sticky의 이동 범위를 확보한다 */
  /* Wing Initial Y (v6)
     .main-wing 은 <main class="main-layout"> 안의 Grid Item이고,
     main-layout 은 <header> 다음 Normal Flow에 있으므로 Grid Row Top이
     항상 Header Height(90px) 아래에서 시작했다.
     (.main-layout 자체의 padding-top / margin-top 은 0이었다)

     그런데 Wing Column에는 Header가 존재하지 않으므로
     그 90px는 아무것도 담지 않는 예약 공백이었다.
     Header Height만큼 끌어올려 공백을 제거한다.

       Before : Row Top 90 + padding-top 32 = Banner Top 122
       After  : Row Top  0 + padding-top 32 = Banner Top  32

     32px는 __inner 의 sticky top(32px)과 정확히 같은 값이라
     최초 렌더 위치와 Sticky 고정 위치가 일치한다 -> 스크롤 시 Jump 0.
     sticky top 은 "스크롤 이후 고정 위치"이므로 건드리지 않았다.

     Grid Item에 음수 margin을 주면 stretch 상태에서 Box가 위로 90px
     늘어날 뿐, Row 높이 / Column x / Width / Footer 위치는 바뀌지 않는다. */
  margin-top: calc(var(--header-height) * -1);
  /* Header ↔ Wing 32px / Wing ↔ Footer 32px 대칭 여백.
     Spacing은 .main-wing(Grid Item)이 담당하고 Sticky는 __inner가 담당한다.
     padding-bottom이 Sticky의 이동 가능 범위 끝을 32px 앞당기므로
     Banner Stack이 Footer에 붙지 않고 항상 32px 위에서 멈춘다.
     이동 범위 = Grid Row Height - 32(top) - 32(bottom) - 992(Stack) */
  padding-top: var(--space-8);
  padding-bottom: var(--space-8);
}

.main-wing__inner {
  position: sticky;
  top: var(--space-8); /* 스크롤 시 Viewport 상단에서 32px */
  display: flex;
  flex-direction: column;
  gap: var(--space-4); /* Banner 간 16px */
}

.wing-slot {
  height: 320px; /* TODO: Token 승격 검토 */
}

/* 향후 Fade 확장 시 이 Track에 position:relative 를 주고
   내부 .wing-banner 를 absolute/inset:0 으로 겹치면 된다. */
.wing-slot__track {
  height: 100%;
}


/* ==================================================
   Hero Layout / Intro Background Geometry
   메인페이지 첫 번째 섹션.
   구조: hero > hero__background + hero__overlay > hero__content

   Hero는 Main Content 내부 Component이므로 자체 Width를 제어하지 않는다.
   실제 폭은 .main-layout__content(1400px)가 결정한다.

   ---- Intro Visual Integration (v1) ----
   Header(body 직계, inner 1680px)와 Hero(main-layout__content 1400px 내부)는
   DOM Branch가 다르므로 둘을 함께 감싸는 Wrapper를 만들 수 없다.
   (Hero를 밖으로 빼면 .main-category 의 -32px Overlap 기준 형제가 사라지고,
   Header를 main 안으로 넣으면 1680px Grid의 Item이 되어 Layout이 깨진다.)

   그래서 DOM은 그대로 두고 "공통 Background Layer" 방식을 사용한다.
   .hero__background 가 Intro(Header + Hero) 전체의 Background를 소유하며
   top 을 -(--header-height) 만큼 끌어올려 Header 뒤까지 덮는다.

     y   0 +---------------- Intro Background Layer 시작 (Header 뒤)
           |  Header (transparent, z-index --z-header)
     y  90 +---------------- Header Bottom (Border 제거 -> 이음새 없음)
           |  Hero
     y 490 +---------------- Intro Background Layer 끝
              Category (-32px Overlap, z-index 2)

   Layer가 Hero의 자식이므로 가로 폭 / 좌측 Edge가 Main Content Column과
   자동으로 일치한다. Wing(240px) / Gap(40px) 영역은 침범하지 않는다.

   Background Image / Overlay Gradient 의 표현은 components.css 가 담당한다.
   (이 Block은 Geometry만 담당한다)

   아래 수치는 실제 화면 검토 전 초기 구현값이며 Token으로 승격하지 않았다.
   - Hero Height 400px / Content Width 780px
================================================== */

.hero {
  position: relative;
  width: 100%;
  /* Hero Height (v4) : 560px -> 620px
     Background 하단의 제주 도로 / 차량 / 카페·상가 / 주택을 더 노출시켜
     "제주 관광"이 아니라 "제주 생활"로 읽히게 한다.
     Intro Background Layer는 inset 기반이므로 이 값만 바꾸면
     Layer Height(90 + 620 = 710px)가 자동으로 따라간다.
     TODO: Token 승격 검토 (Hero 전용 구현값) */
  height: 620px;
}

/* Intro Background Layer (Header + Hero 공용)
   Geometry만 담당한다. Image / Overlay Gradient 는 components.css.

   top: -(--header-height) 로 Header 뒤까지 확장한다.
   Header가 Border-Bottom을 갖지 않으므로 Header <-> Hero 경계선이 생기지 않는다.
   Height = --header-height(90) + Hero Height(400) = 490px */
/* Intro Background Layer (v4)
   Header + Hero 공용 Background. Main Content Column(1400px) 안에서만 그린다.

     top   : -(--header-height) -> Header 뒤까지 (Header는 transparent)
     right : 0                  -> Content Column 우측 Edge에서 끝난다

   v3에서 right를 -280px로 두어 Service Frame(1680)까지 넓혔던 실험은 종료했다.
   Wing 뒤로 Landscape가 깔리면 40px Gap이 경계 기능을 잃어
   Main Content와 광고 영역이 하나로 읽혔기 때문이다.
   이제 Wing은 다시 Page 기본 Background 위의 독립 광고 Column이다.

     [ Hero / Background 1400 ] [ Gap 40 ] [ Wing 240 ]

   v4에서 Header Content Frame도 1400으로 들어왔으므로
   Header 우측 Utility가 Background 밖으로 삐져나가지 않는다.
   따라서 v2의 Header Right Sky Continuation(280x90 Patch)도 필요 없다.
   (해당 코드는 v3에서 이미 제거되었고 복구하지 않는다)

   Layer Height = --header-height(90) + Hero Height(620) = 710px
   Background Image / Overlay Gradient 표현은 components.css. */
.hero__background {
  position: absolute;
  inset: calc(var(--header-height) * -1) 0 0 0;
}

/* 콘텐츠 세로 가운데 정렬 Container.
   기존의 Dark Overlay(180deg rgba(17,24,39,...))는 제거했다.
   Overlay는 Header까지 이어져야 하므로 Hero 높이(400px)에만 걸리는
   이 Element가 아니라 Intro Background Layer(490px)가 소유한다.
   이 Element는 Hero Content의 위치만 결정하므로
   Hero Content Alignment / Padding / Height는 그대로다. */
.hero__overlay {
  position: relative; /* Intro Background Layer 위에 쌓이도록 */
  display: flex;
  align-items: center;
  height: 100%;
  /* Vertical Rebalancing (v4)
     Hero 560 -> 620px(+60) 이면서 Title이 50 -> 52px(Block +3.56px)가 되므로
     하단 Padding을 122 -> 154px로 키워 Content Top 이동량을 +12px로 묶는다.
     (최초 400px 기준 누적 +44px)
     나머지 +48px는 전부 하단 Landscape 노출 영역으로 남는다.
     Content Group 자체의 구조 / 간격은 건드리지 않는다.
     TODO: Token 승격 검토 */
  padding: 40px 80px 154px;
}

.hero__content {
  width: 780px; /* TODO: Token 승격 검토 */
  max-width: 100%;
}


/* ==================================================
   Main Section Panel
   Recommend / Popular / Today Jeju 를 각각 독립 Container로 만든다.

   적용 : Recommend / Popular / Today Jeju
   제외 : Header / Hero / Category / Footer (기존 Style 그대로)

   Width 원칙 (가장 중요):
     Section Wrapper 자체가 곧 Main Content Column(1400px)이다.
     Panel Outer Width 1400px는 고정이며, Panel을 1400px보다 넓혀
     내부 Content를 되돌리는 방법은 Content/Wing Gap(40px)을 침범하므로
     사용하지 않는다. (1400 + 40 + 240 = 1680 유지)

     대신 Border와 내부 콘텐츠가 붙어 보이지 않도록 좌우 30px Padding을 둔다.
     box-sizing: border-box 이므로 실제 Content Width는

       1400 - Border(1 x 2) - Padding(30 x 2) = 1338px

     이다. (이전: 좌우 Padding 0, Content 1398px)
     내부 Grid는 모두 이 1338px 기준으로 재계산한다.

       Recommend : repeat(4, 1fr) + gap 20   → Card 319.5px
       Popular   : 1fr + gap 24 + 328        → Ranking 986px
       Today     : 400 + gap 28 + 1fr        → Recommendation 910px

     세 Section 모두 고정 px Column을 최소화(Popular Stats 328 / Today Weather 400)
     하고 나머지를 Flexible로 두어, Padding 값이 바뀌어도 Overflow가 나지 않게 한다.

   Vertical:
     Border ─ 32px ─ Section Header / Content ─ 32px ─ Border

   Section 간 Gap (16px 통일):
     Panel의 Border + Radius 자체가 이미 Section 경계를 만들므로
     기존의 80 / 96px 같은 큰 공백을 유지하지 않는다.
     Gap은 각 Panel의 margin-bottom 하나만으로 만들고
     다음 Section에 margin-top을 주지 않는다.
     (양쪽에 margin을 두면 Grid Item 내부에서 인접 형제 margin이
      상쇄되는지 여부를 매번 따져야 하므로, 한 방향으로만 고정한다)

     이 규칙은 세 Panel의 공통 Selector에 있으므로
     향후 Main Section Panel이 추가되어도 Selector에 이름만 더하면
     동일한 16px Rhythm이 자동으로 적용된다.

   Utility Section 제외:
     .main-utility 는 Vertical Padding이 24px로 다르므로 아래 Selector에
     넣지 않고 자기 Block(Main Utility Layout)에서 Padding과 margin-bottom을
     직접 관리한다. Border / Radius / Background / Shadow 는 components.css 의
     공통 Selector를 함께 사용한다.

   Border / Radius / Background / Shadow 는 components.css 가 담당한다.
================================================== */

.main-recommend,
.main-popular,
.main-today-jeju,
.main-event {
  /* 상하 32px / 좌우 30px.
     30px에 해당하는 Spacing Token이 없어 구현값을 사용한다.
     TODO: Section horizontal padding token 승격 검토 */
  padding: var(--space-8) 30px;
  margin-bottom: var(--space-4); /* 다음 Section Panel까지 16px */
}


/* ==================================================
   Main Category Layout (v2.1)
   Hero와 결합된 Quick Navigation Panel.

   Header / Footer 는 Service Frame(1680px)을 사용하지만
   Main 내부 섹션(Hero / Category / Recommend)은 Main Content(1400px) 기준이다.
   Category Panel만 v2.1에서 1370px로 좁혀 Hero 안쪽에 들어오게 한다(아래 Panel Width).

   Hero Overlap (v2.1):
     Hero 위로 32px 겹치게 하되 transform이 아니라 negative margin을 사용한다.
     transform은 문서 흐름을 바꾸지 않아 아래 Section 간격이 어긋나지만,
     negative margin은 이후 흐름까지 함께 당겨져 Category → Recommend 80px이
     Panel 하단 기준으로 그대로 유지된다.

     Hero 하단 ──(-32px overlap)── Panel 상단
     Panel 하단 ──(80px)── Recommend

   Stacking:
     Hero(position:relative / z-index:auto) 위에 올라오도록
     .main-category 에만 최소 stacking(z-index:2)을 준다.
     Header / Wing / Hero 의 z-index는 수정하지 않는다.

   Panel Width (v2.1):
     Main Content(1400px) Edge에 맞추지 않고 좌우 15px씩 안쪽으로 들여
     Hero 안에 얹힌 Floating Quick Navigation처럼 보이게 한다.
     1400 - 30 = 1370px
     Hero / Recommend / Popular 는 계속 1400px Edge를 사용한다.
     calc(100% - 30px)를 함께 두어 부모가 1400px보다 좁아져도
     좌우 15px inset이 유지되게 한다.

   아래 수치는 실제 화면 검토 전 초기 구현값이며 Token으로 승격하지 않았다.
   - Item Height 144px / Item 상하 Padding 12px / Panel Width 1370px
================================================== */

.main-category {
  position: relative;
  z-index: 2; /* Hero 위. Header(--z-header 100)와 경쟁하지 않는 최소값 */
  margin-top: calc(var(--space-8) * -1); /* Hero Overlap -32px */
  margin-bottom: var(--space-4);         /* 다음 Section까지 16px */
}

/* Panel 표현(Border / Radius / Shadow)은 components.css 가 담당한다. */
.main-category__panel {
  width: calc(100% - 30px); /* 좌우 15px inset. TODO: Token 승격 검토 */
  max-width: 1370px;        /* TODO: Token 승격 검토 */
  margin: 0 auto;
}

/* 통합 Panel 내부 6분할. Item 사이 Divider를 쓰므로 gap을 두지 않는다.
   Panel 1370px 기준 Item 1개 = (1370 - border 2) / 6 = 228px
   TODO(responsive): Breakpoint 미확정이라 @media를 추가하지 않았다.
                     향후 Tablet/Mobile 에서는 이 값만 repeat(3, ...) 등으로
                     바꾸면 3 x 2 배치로 전환된다. */
.category-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

/* Divider 기준점. 첫 Item에는 Divider가 없으므로 5개만 생성된다. */
.category-grid__item {
  position: relative;
}

/* Item Size : Width는 Grid가 결정한다 (1400px 기준 233.33px) */
.category-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 144px; /* TODO: Token 승격 검토 */
  padding: var(--space-3) var(--space-4);
}


/* ==================================================
   Main Recommend Layout
   메인페이지 세 번째 섹션(지금, 추천 매물).

   Category Section이 이미 margin-bottom 16px를 가지므로
   여기에 Top Margin을 중복으로 넣지 않는다. (Category → Recommend = 16px)
   Section Panel 공통 margin-bottom(16px)은 위 Main Section Panel 블록에 있다.

   아래 수치는 실제 화면 검토 전 초기 구현값이며 Token으로 승격하지 않았다.
   - Card Gap 20px
================================================== */

/* Section Panel의 Content Box(1400 - Border 2 - Padding 60 = 1338px)를 그대로 채운다.
   max-width(1400)는 Panel 밖에서 단독으로 쓰일 때를 위한 상한이며
   Panel 내부에서는 Padding이 이미 폭을 결정하므로 실제로 작동하지 않는다. */
.main-recommend__inner {
  width: 100%;
  max-width: var(--content-width);
  margin: 0 auto;
}

/* Section Header : 좌측 제목 그룹 / 우측 컨트롤 그룹 */
.main-recommend__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
}

.main-recommend__heading {
  display: flex;
  align-items: center;
  gap: var(--space-4); /* Title ↔ Subtitle 16px */
  min-width: 0;
}

.main-recommend__controls {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: var(--space-5); /* Filter Group ↔ 전체보기 20px */
}

.recommend-filter {
  display: flex;
  align-items: center;
  gap: var(--space-2); /* Filter 간 8px */
}

/* Card Area : 추후 Carousel 전환이 쉽도록 viewport / track 을 분리해 둔다 */
.main-recommend__viewport {
  position: relative;
  margin-top: var(--space-6); /* Header → Cards 24px */
}

/* v2 : 1338 = Card 316.5 x 4 + Gap 24 x 3
   Card Image를 키우면서 Card 사이 여백도 함께 넓혔다(20 -> 24px).
   구현값 20px 대신 --space-6(24px) Token을 재사용한다.
   Card에 고정 px을 두지 않아 Section Padding이 바뀌어도 4-Column이 유지된다. */
.main-recommend__track {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-6);
}

/* Carousel Arrow : Card Grid 오른쪽 중앙에 걸치는 형태
   40px 버튼의 절반이 Grid 바깥으로 나가도록 right: -20px,
   세로 중앙은 margin-top으로 맞춘다. (transform 미사용)

   좌우 30px Padding 도입 후에도 이 값을 유지한다.
   Arrow Center = Content Right Edge 이고 Button 오른쪽 끝은
   Content Edge + 20px = Section Border 안쪽 10px 지점이라
   Border를 넘지 않으면서 Content Edge 기준으로 자연스럽게 걸친다.
   (이전 1398px Layout에서는 Button 절반이 Border 밖으로 나갔다) */
.recommend-nav {
  position: absolute;
  top: 50%;
  right: -20px;
  margin-top: -20px;
}


/* ==================================================
   Main Popular Layout
   메인페이지 네 번째 섹션(지금 많이 보고 있어요).

   구조: main-popular > __inner(1338px) > __header + popular-layout
   계산: Ranking 986 + Gap 24 + Stats 328 = 1338
         (1fr = 1338 - 24 - 328 = 986 이므로 Ranking에 고정 px을 두지 않는다)
         Section 좌우 Padding 30px 도입으로 Content가 1398 → 1338px가 되었지만
         Ranking이 Flexible이라 Stats 328 / Gap 24 를 그대로 유지할 수 있다.

   Vertical Rhythm:
     Recommend → Popular 16px. 모든 Section Panel Gap이 16px로 통일되면서
     "Popular이 뒤에 붙을 때만 80px" 였던 .main-recommend:has(+ .main-popular)
     예외 규칙은 존재 이유가 사라져 제거했다.
     Gap은 공통 Selector의 margin-bottom 하나로만 만들고
     .main-popular 에는 margin-top을 두지 않는다.

   TODO(responsive): Breakpoint 정책이 미확정이라 @media를 추가하지 않았다.
                     향후 Tablet / Mobile 에서는 .popular-layout 의
                     grid-template-columns 를 1fr 로 바꾸고 row-gap만 주면
                     Ranking → Stats 세로 배치로 전환된다.
                     (DOM 순서가 이미 Ranking → Stats 다)

   아래 수치는 실제 화면 검토 전 초기 구현값이며 Token으로 승격하지 않았다.
   - Stats Panel 328px / Row Min Height 88px
   - Ranking Footer Height 56px / Thumbnail 112x72px
================================================== */

/* Recommend와 동일하게 Section Panel의 Content Box(1338px)를 그대로 채운다.
   내부에서 다시 width 계산을 하지 않아 세 Section의 좌우 Edge가 정확히 일치한다. */
.main-popular__inner {
  width: 100%;
  max-width: var(--content-width);
  margin: 0 auto;
}


/* ---------- Section Header ----------
   Recommend Section Header와 동일한 배치 규칙을 사용한다. */

.main-popular__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
}

.main-popular__heading {
  display: flex;
  align-items: center;
  gap: var(--space-4); /* Title ↔ Subtitle 16px */
  min-width: 0;
}

.main-popular__controls {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: var(--space-5);
}

.popular-period {
  display: flex;
  align-items: center;
  gap: var(--space-2); /* Period Button 간 8px */
}


/* ---------- Body Grid ----------
   두 Panel 높이는 Grid 기본 stretch로 맞춘다. 고정 height를 주지 않는다. */

/* v2 : 우측이 Donut Panel -> 인기 검색어 List로 바뀌었다.
   1338 = Ranking 974 + Gap 24 + Search 340
   좌 72.8% / 우 25.4% 로 §비율 목표(72~75 / 25~28) 안에 들어온다.
   align-items: start 로 두어 각 Column이 자기 콘텐츠 높이만 갖게 한다.
   (stretch를 유지하면 짧은 우측 Column이 억지로 늘어나 Divider 길이가 어긋난다) */
.popular-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px; /* TODO: Token 승격 검토 */
  column-gap: var(--space-6);                  /* 24px */
  align-items: start;
  margin-top: var(--space-6);                  /* Header → Body 24px */
}


/* ---------- Ranking Panel ---------- */

.popular-ranking {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Panel이 우측 Panel보다 짧아지는 경우에도 Footer는 Panel 하단에 붙는다 */
.popular-ranking__footer {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: auto;
  height: 56px; /* TODO: Token 승격 검토 */
}


/* ---------- Ranking Item (v2) ----------
   기존 문제: Info Column이 414px로 지나치게 넓어 Title 뒤에 죽은 공간이 생기고
   Location / Views / Trend 가 우측 끝에 몰려 Row 가운데가 비어 보였다.

   v2에서는 Panel Border와 Row 좌우 Padding을 없애 Row 실폭을 넓히고
   Column Gap을 16 → 24px로 키워 각 정보가 자기 Column을 쓰도록 분산시켰다.

     Row 실폭 = Ranking 974 - List padding-right 24 = 950px
     40 + 110 + Info + 140 + 120 + 70 + (24 x 5) = 950  →  Info = 350px

   Info만 1fr이라 Section Padding이 바뀌어도 이 Column이 흡수한다.
   Row 높이는 Thumbnail 74 + 상하 Padding 16 = 90px 이지만
   min-height 88px 선언을 유지해 기존 Vertical Rhythm 기준을 그대로 둔다.

   Location / Views 를 고정 px이 아니라 minmax(0, N) 으로 둔 이유:
   Breakpoint 정책이 없는 프로젝트라 Viewport가 좁아지면 Ranking Column도
   함께 줄어드는데, 고정 px이면 Row가 Divider를 넘어 우측 검색어 영역을
   침범한다. minmax(0, N)이면 여유가 있을 때는 N(140/120)을 그대로 쓰고
   부족할 때만 축소되어 Row가 자기 Column 밖으로 나가지 않는다.
   1728 / 1680 에서는 항상 최대값이 적용되므로 의도한 Layout 그대로다. */

.popular-item {
  display: grid;
  grid-template-columns:
    40px             /* Rank */
    110px            /* Thumbnail */
    minmax(0, 1fr)   /* Core Info */
    minmax(0, 140px) /* Location */
    minmax(0, 120px) /* Views */
    70px;            /* Trend */
  align-items: center;
  column-gap: var(--space-6); /* v2: 16 -> 24px. 정보를 Column별로 분산시킨다 */
  min-height: 88px;
  padding: var(--space-2) 0; /* v2: Panel Box 제거로 좌우 Padding 불필요 */
}

/* Location은 내용 폭만 차지하는 Pill이므로 Cell을 채우지 않는다 */
.popular-item__location {
  justify-self: start;
  max-width: 100%;
}

.popular-item__views {
  justify-self: end;
}

.popular-item__change {
  justify-self: center;
}

.popular-item__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-1); /* Category / Title / Meta 간 4px */
  min-width: 0;
}


/* ---------- Vertical Divider (v2) ----------
   좌우를 각각 Card Box로 만들지 않고, 좌측 List의 오른쪽 Border 하나로만 나눈다.
   Border를 Column(.popular-ranking)이 아니라 List(.popular-list)에 두는 이유:
   Divider가 Sub Heading 위나 Footer("인기 정보 더보기") 아래까지 내려가지 않고
   정확히 1~5위 Row 구간에서만 시작하고 끝나게 하기 위함이다.
   padding-right 24px 로 Trend Column과 Divider 사이 여백을 만든다.
   (Divider 오른쪽 여백은 .popular-layout 의 column-gap 24px가 담당해 좌우 대칭) */

.popular-list {
  border-right: 1px solid var(--border-light);
  padding-right: var(--space-6);
}


/* ---------- Popular Search Panel (v2) ----------
   기존 Donut Chart Panel을 대체한다. 별도 Card Box를 만들지 않는다.
   Row Height를 좌측 Ranking Row(88px)와 동일하게 두어
   좌우 List 높이가 자연스럽게 맞고 우측 하단에 큰 빈 공간이 생기지 않게 한다. */

.popular-search {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.popular-search__list {
  display: flex;
  flex-direction: column;
}

/* Rank / Keyword / Trend 3 Column.
   Trend Column 폭을 좌측 Ranking의 Trend(70px)와 맞춰
   좌우가 하나의 Trend Section으로 읽히게 한다. */
.popular-search__link {
  display: grid;
  grid-template-columns:
    32px           /* Rank */
    minmax(0, 1fr) /* Keyword */
    70px;          /* Trend */
  align-items: center;
  column-gap: var(--space-4); /* 16px */
  /* 좌측 Ranking Row 실높이(Thumbnail 74 + 상하 Padding 16 = 90px)와 같게 둔다.
     좌우 List 높이가 정확히 일치해야 Vertical Divider가 우측 List와 같은 지점에서
     끝나고, 우측 하단에 큰 빈 공간이 생기지 않는다. */
  min-height: 90px;
  padding: var(--space-2) 0;
}


/* ==================================================
   Main Today Jeju Layout
   메인페이지 다섯 번째 섹션(오늘, 제주 어때요?).

   구조: main-today-jeju > __inner(1338px) > __header + today-layout + today-shortcuts
   계산: Weather 400 + Gap 28 + Recommendation 910 = 1338
         Section 좌우 Padding 30px 도입으로 Content가 1398 → 1338px가 되면서
         Weather를 420 → 400px로 줄이고 Recommendation은 1fr로 흡수시켰다.

   Popular Section이 이미 margin-bottom 16px를 가지므로
   여기에 Top Margin을 중복으로 넣지 않는다. (Popular → Today Jeju = 16px)

   Section 전체 높이 (v2.0) :
     Header 36 + 32 + Main 520 + 32 + Shortcut 138.5 ≈ 759px
     Section 아래 16px(다음 영역까지)을 포함하면 시각 높이 약 775px다.
     고정 height를 쓰지 않고 콘텐츠 + Gap의 합으로만 만든다.
     (v1.0: Header 36 + 24 + Main 412 + 32 + Shortcut 107 ≈ 611px)

   TODO(responsive): Breakpoint 정책이 미확정이라 @media를 추가하지 않았다.
                     향후 Tablet / Mobile 에서는 .today-layout 의
                     grid-template-columns 를 1fr 로 바꾸고 row-gap만 주면
                     Weather → Recommendation 세로 배치로 전환된다.
                     .today-recommend__grid 도 repeat(2, ...) 로만 바꾸면 된다.
                     (DOM 순서가 이미 Weather → Recommendation → Shortcuts 다)

   Today Jeju 는 현재 Main Content의 마지막 Section이지만
   Footer 직전이라고 Bottom Margin을 따로 키우지 않는다.
   향후 Today ↔ Footer 사이에 Main Section이 추가될 예정이라
   공통 규칙인 16px을 그대로 사용한다. (Today → Footer = 16px)

   아래 수치는 실제 화면 검토 전 초기 구현값이며 Token으로 승격하지 않았다.
   - Weather 400px / Column Gap 28px / Notice Icon 16px
   - Weather Min Height 480px / Weather Icon 120px
   - Place Card Image 1:1 (v2.0) / Shortcut Item 40px

   Weather Column(400) / Column Gap(28) / Recommendation(1fr = 910)은
   v3.1에서도 그대로 둔다. Weather UI만 v2.1 구조로 되돌리는 작업이다.
================================================== */

/* Recommend / Popular 와 동일하게 Section Panel의 Content Box(1338px)를 그대로 채운다. */
.main-today-jeju__inner {
  width: 100%;
  max-width: var(--content-width);
  margin: 0 auto;
}


/* ---------- Section Header ----------
   Recommend / Popular Section Header와 동일한 배치 규칙을 사용한다. */

.main-today-jeju__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
}

.main-today-jeju__heading {
  display: flex;
  align-items: center;
  gap: var(--space-4); /* Title ↔ Subtitle 16px */
  min-width: 0;
}

/* 날씨 기준 지역 : Header의 전역 검색 지역과는 별개 Context다 */
.today-location {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: var(--space-2);
}

.today-location__icon {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 18px; /* TODO: Token 승격 검토 */
  height: 18px;
}

.today-location__icon-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}


/* ---------- Body Grid ----------
   두 Column 높이는 Grid 기본 stretch로 맞춘다. 고정 height를 주지 않는다. */

.today-layout {
  display: grid;
  grid-template-columns: 400px minmax(0, 1fr); /* 400 + 910. TODO: Token 승격 검토 */
  column-gap: 28px;                            /* TODO: Token 승격 검토 */
  align-items: stretch;
  margin-top: var(--space-8);                  /* Header → Body 32px (v2.0) */
}


/* ---------- Weather Card ----------
   status(상단) / summary(중앙) / metrics(하단) 3블록을 space-between으로 배분한다.
   Card 높이가 우측 Column에 맞춰 늘어나도 여백이 한쪽에 몰리지 않는다.

   v3.1 : v3.0에서 이 Card를 4요소(Icon / Temperature / Status / 추천 이유)로
          단순화했으나 400px Column에 비해 정보 밀도가 지나치게 낮아져
          v2.1의 3블록 구조를 그대로 되돌렸다.
          추천 이유 Copy는 우측 Recommendation Heading / Description이 담당한다. */

.today-weather {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 480px; /* v2.0 세로 여유 확장. TODO: Token 승격 검토 */
  padding: var(--space-6);
}

/* Pill이 Column 폭 전체로 늘어나지 않게 한다 */
.today-weather__status {
  align-self: flex-start;
}

/* Summary : Temperature / Feels Like(좌) + Condition Icon(우) + Description(하단)
   v2.1 : 기존 세로 Flow를 2 Column Grid로만 바꾼다.
     - Temperature와 Icon을 같은 Visual Zone에 묶어 좌우로 읽히게 한다.
     - Description은 두 Column을 모두 가로질러 기존과 동일한 폭(350px)을 유지한다.
   Absolute Position / Negative Margin을 쓰지 않으므로
   Icon Size가 바뀌어도 Card 내부 Flow가 깨지지 않는다.
   Row 합(Temperature 91 + Feels 23.5 = 114.5)보다 Icon 120px이 크지만
   Card가 space-between이고 여유 공간이 충분해 Card 높이는 변하지 않는다. */
.today-weather__summary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 170px; /* TODO: Token 승격 검토 */
  grid-template-areas:
    "temperature condition"
    "feels-like  condition"
    "description description";
  align-items: center;
  column-gap: var(--space-4); /* Temperature ↔ Icon 16px */
}

.today-weather__temperature {
  grid-area: temperature;
  align-self: end;
}

.today-weather__feels-like {
  grid-area: feels-like;
  align-self: start;
}

/* 현재 날씨 상태 Visual. 작은 장식 Icon이 아니라 Temperature 다음가는 두 번째 Headline이다.
   Weather Asset의 원본 도형 비율이 정사각이라 Wrapper와 1:1로 맞는다.
   Asset 내부를 수정하지 않고 Wrapper Size + object-fit: contain 으로만 제어한다.
   TODO: Token 승격 검토 */
.today-weather__condition-icon {
  grid-area: condition;
  display: block;
  width: 170px;
  height: 170px;
}

.today-weather__condition-icon-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.today-weather__description {
  grid-area: description;
}

/* Metrics : 개별 Card가 아니라 4등분 Compact Stats */
/* 반투명 Surface를 갖게 되면서 Divider(border-top) 대신 자체 Padding으로 분리한다.
   Card는 space-between이라 이 블록이 커져도 Card 높이는 바뀌지 않는다. */
.today-weather__metrics {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: var(--space-5); /* Description 영역 → Metrics 20px */
  padding: var(--space-4) 0;
}

.today-weather__metric {
  position: relative; /* Divider 기준점 */
  min-width: 0;
  padding: 0 var(--space-2);
  text-align: center;
}


/* ---------- Recommendation ----------
   Heading → Filter → Card 순서. Card Grid가 남는 높이를 흡수한다. */

.today-recommend {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.today-recommend__filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);        /* Filter 간 8px */
  margin-top: var(--space-4); /* Description → Filter 16px (v3.1) */
}

/* 910 = Card 212.5 x 4 + Gap 20 x 3
   v2.0: Card가 더 이상 Box가 아니므로 Grid 높이에 맞춰 늘리지 않는다.
   Title 1줄 / Description 2줄 clamp라 4개 Card 높이는 자연스럽게 동일하다. */
.today-recommend__grid {
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  align-items: start;
  gap: var(--space-5);        /* 20px */
  margin-top: var(--space-5); /* Filter → Card 20px */
}

/* v2.0: 고정 Height를 주지 않는다. Image(1:1) + Content 합으로 결정된다. */
.today-place-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* v2.0: Card Box가 사라졌으므로 Content에 좌우 Padding을 두지 않는다.
   Text Left Edge를 Image Left Edge와 정확히 맞춘다. */
.today-place-card__body {
  display: flex;
  flex-direction: column;
  margin-top: var(--space-4); /* Image → Content 16px */
  padding: 0;
}

.today-place-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin-top: var(--space-3); /* Description → Tags 12px */
}


/* ---------- Life Shortcut ----------
   4개를 독립 Card로 만들지 않고 하나의 Panel + Divider로 묶는다. */

/* v3 : Title과 Shortcut 4개를 같은 Row에 두는 1단 Utility Bar.
   고정 height를 주지 않고 Padding + Link Height(40)로만 결정한다.
     16 + 40 + 16 + border 2 = 74px */
.today-shortcuts {
  display: flex;
  align-items: center;
  margin-top: var(--space-8); /* Body → Shortcut 32px */
  padding: var(--space-4) var(--space-5); /* 16px 20px */
}

/* Title은 Utility Bar Label 역할이라 고정 폭만 차지하고 늘어나지 않는다 */
.today-shortcuts__title {
  flex: 0 0 180px; /* TODO: Token 승격 검토 */
}

.today-shortcuts__list {
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  min-width: 0;
}

.today-shortcuts__item {
  position: relative; /* Divider 기준점 */
  min-width: 0;
}

.today-shortcuts__link {
  display: flex;
  align-items: center;
  gap: var(--space-3); /* Icon ↔ Label 12px */
  height: 40px; /* TODO: Token 승격 검토 */
  padding: 0 var(--space-3);
}

.today-shortcuts__icon {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 24px; /* TODO: Token 승격 검토 */
  height: 24px;
}

/* Chevron은 항상 오른쪽 끝 */
.today-shortcuts__arrow {
  margin-left: auto;
}

/* ---------- Update Notice ----------
   v3 : Shortcut Bar 안이 아니라 Today Section 최하단에 둔다.
   Shortcut 기능의 일부가 아니라 Section 전체의 Data Freshness 안내이기 때문이다.
   absolute로 박지 않고 문서 흐름 안에서 우측 정렬하므로
   문구 길이나 Font가 바뀌어도 Layout이 깨지지 않는다. */

.main-today-jeju__notice {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;                   /* Icon ↔ Text. TODO: Token 승격 검토 */
  margin-top: var(--space-3); /* Shortcut Bar → Notice 12px */
}


/* ==================================================
   Main Event Layout
   메인페이지 여섯 번째 섹션(제주, 이번엔 어디서 즐길까요?).

   구조: main-event > __inner(1338px)
                    > event-layout + event-recap
         event-layout > event-area(__header + __controls + event-grid) + event-app

   v3 : Section Header를 Event Area(890px) 안으로 옮겼다.
        App Panel이 Section Title 라인(Main Grid 첫 Row)부터 시작해
        왼쪽 Discover Column / 오른쪽 App Conversion Column의 2축 구조가 된다.

   계산: Event 890 + Gap 30 + App 418 = 1338
         Gap 30px은 Section 좌우 Horizontal Padding 30px과 같은 값을 사용해
         화면 전체에서 반복되는 Layout Rhythm을 만든다.

   Event Grid: (890 - 16 x 2) / 3 = 286px

   Vertical Rhythm:
     Event Column 내부 : Header ─ 24 ─ Controls ─ 24 ─ Cards
     Main Row ─ 24 ─ Category Recap

   Today Jeju Section이 이미 margin-bottom 16px를 가지므로
   여기에 Top Margin을 중복으로 넣지 않는다. (Today → Event = 16px)
   Section 공통 Padding / margin-bottom(16px)은 위 Main Section Panel 블록에 있다.
   (Event → Footer = 16px)

   Main Row 높이:
     고정 height를 주지 않는다. App Panel의 자연 높이가 Row 높이를 결정하고
     Grid 기본 stretch로 Event Card 3개가 같은 Bottom Line까지 늘어난다.

   TODO(responsive): Breakpoint 정책이 미확정이라 @media를 추가하지 않았다.
                     향후 Tablet / Mobile 에서는 .event-layout 을 1fr로,
                     .event-grid 를 repeat(2, ...) 로 바꾸면 세로 배치로 전환된다.
                     (DOM 순서가 이미 Event → App → Recap 이다)

   아래 수치는 실제 화면 검토 전 초기 구현값이며 Token으로 승격하지 않았다.
   - Header Icon 46px / Event Area 890px / Main Gap 30px / App Panel 418px
   - Event Card Image 4:3 / Filter 40px·padding 20px / Region 128x40px
   - Phone 175px / QR 68px / Store Button 128x38px / Recap Title 160px
================================================== */

/* Recommend / Popular / Today 와 동일하게 Section Panel의 Content Box(1338px)를 그대로 채운다. */
.main-event__inner {
  width: 100%;
  max-width: var(--content-width);
  margin: 0 auto;
}


/* ---------- Section Header ----------
   Recommend / Popular / Today는 Title ↔ Subtitle을 가로로 두지만
   이 Section은 Icon + 세로 Title/Subtitle Group을 사용한다.

   v4 : Icon은 Section Header 전체가 아니라 H2 Title을 보조하는 Title Icon이므로
        Text Group(Subtitle 포함) 세로 중앙이 아니라 Title 라인에 정렬한다.
        flex-start로 Icon Top = H2 Top이 되고, Icon(46) Center가
        H2 첫 줄(line-height 41.6) Center와 2px 이내로 맞는다. */

.main-event__header {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4); /* Icon → Text Group 16px */
}

.main-event__icon {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 46px; /* TODO: Token 승격 검토 */
  height: 46px;
}

.main-event__icon-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.main-event__heading {
  min-width: 0;
}


/* ---------- Event Controls ----------
   좌측 기간 Filter / 우측 지역 Selector.

   v2 : Section 전체 Controls Row가 아니라 Event Area(890px) 내부에 둔다.
        Section Row로 두면 우측 지역 Selector 때문에 App Panel도 Controls
        아래에서 시작해 App 상단 40px + Gap 24px이 빈 공간이 되기 때문이다.
   v3 : Section Header도 같은 Event Area 안으로 들어와 Header 아래에 놓인다.

   이 Section에는 "전체보기"가 없다. (의도된 미구현) */

.event-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  margin-top: var(--space-6); /* Header → Controls 24px */
}

.event-filter {
  display: flex;
  align-items: center;
  gap: var(--space-3); /* Filter 간 12px */
}


/* ---------- Main Grid ----------
   v3 : Section Header가 Event Area 안으로 들어가 Main Grid가
        Section Content의 첫 Row다. (Header 위 별도 Row 없음)

   두 Column 높이는 Grid 기본 stretch로 맞춘다. 고정 height를 주지 않는다.
   Row 높이는 Event Area(Header + 24 + Controls + 24 + Card Natural Height)가 결정하고
   App Panel이 거기에 맞춰 stretch된다.
   반대로 Event Card Body를 늘려 App 높이에 맞추지 않는다.

   두 번째 Column을 minmax(0, 1fr)로 두어 부모가 1338px보다 좁아져도
   Overflow 없이 축소되게 한다. 1338px에서는 정확히
     1338 - 890 - 30 = 418px
   가 된다. */
.event-layout {
  display: grid;
  grid-template-columns: 890px minmax(0, 1fr); /* 890 + 30 + 418 = 1338 */
  column-gap: 30px;                            /* Section 좌우 Padding과 같은 값 */
  align-items: stretch;
}

/* Controls + Card Grid를 묶는 좌측 Column(890px). */
.event-area {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* 890 = Card 286 x 3 + Gap 16 x 2
   Card는 Natural Height를 사용한다. Row 높이에 맞춰 Body를 늘리지 않으므로
   align-items: stretch(기본)를 쓰지 않고 start로 고정한다. */
.event-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4); /* 16px */
  align-items: start;
  margin-top: var(--space-6); /* Controls → Cards 24px */
  min-width: 0;
}


/* ---------- App Panel Layout ----------
   Badge+Headline(Intro) / Description은 Panel 전체 폭(368px)을 그대로 쓴다.
   Feature List만 Phone 옆 좁은 Column(368-220-12=136px)에 둔다.
   Phone은 Intro~Feature 3개 Row에 걸쳐 배치되는 우측 Product Visual이다.
   CTA는 QR Row ─ 12 ─ Store Row 세로 Stack이며 다시 전체 폭을 사용한다.

   v6 (App Panel 재배치 QA) : Phone을 Description~Feature 옆(row 2/span2)이 아니라
        Intro(Badge+Headline)부터 Feature까지 전체(row 1/span3) 옆으로 확장했다.
        Intro/Description은 grid-column을 1/-1(전체 폭)로 유지해 Headline·Description
        원본 2줄 br 구조가 깨지지 않게 하고, Phone은 같은 Row에서 column 2(220px)만
        차지하도록 두어 두 Box가 같은 Row에 겹쳐도 실제로는 충돌하지 않는다.
        (Headline 최장 폭 175.8px / Description 최장 폭 136.6px 모두 Column1 실폭 136px보다
         넓지만, 전체 폭 Row라 줄바꿈이 늘지 않고, Phone 쪽으로 넘치는 부분은 Phone Asset의
         둥근 모서리 투명 영역과 겹쳐 시각 충돌이 없다 — 실측 스크린샷으로 확인)
        Feature만 Column1(136px)에 남아 있고 v4에서 적용한 keep-all로 2줄까지만 깨진다.
        Grid Row가 전부 auto라 Phone의 초과 높이는 Row 1~3에 나뉘어 배분되고, 그만큼
        Intro→Description, Description→Feature 사이 간격이 소폭(약 8~17px) 늘어난다.
        고정 height로 강제 압축하지 않고 Natural Height로 둔 결과이며, 실측/스크린샷상
        과도한 공백으로 보이지 않는 수준이다. */
.event-app__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 220px; /* Phone 220. TODO: Token 승격 검토 */
  grid-template-rows: auto auto auto auto;
  column-gap: var(--space-3); /* Text Column ↔ Phone 12px */
  row-gap: var(--space-4);
  height: 100%;
}

/* v6 : 전체 폭(1/-1) 유지가 핵심. Phone이 같은 Row(1/span3)의 Column 2를 차지해도
   Headline 최장 줄(175.8px)은 Column 1 경계(136px)를 넘어 Column 2 쪽으로 넘치지만,
   그 지점은 Phone Asset의 둥근 모서리(투명 영역)와 겹쳐 시각 충돌이 없다. */
.event-app__intro {
  grid-column: 1 / -1;
  grid-row: 1;
}

/* v6 : Feature와 달리 전체 폭(1/-1)을 유지한다. Column 1 폭(136px)에 가두면
   두 번째 줄("아이탐라를 만나보세요.", 136.6px)이 아슬아슬하게 넘쳐 3줄로 깨진다.
   전체 폭에서는 두 줄(<br> 기준 131.6 / 136.6px) 모두 여유 있게 들어간다. */
.event-app__description {
  grid-column: 1 / -1;
  grid-row: 2;
}

.event-app__features {
  grid-column: 1;
  grid-row: 3;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: var(--space-6); /* Feature 간 24px */
  min-width: 0;
}

.event-app__feature {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2); /* Icon ↔ Text 8px */
  min-width: 0;
}

.event-app__feature-icon {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 24px; /* TODO: Token 승격 검토 */
  height: 24px;
}

.event-app__feature-icon img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.event-app__feature-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Phone : Description ~ Feature List 두 Row를 세로로 관통한다.
   v4 : absolute + max-height(Cell 높이 추종) 방식을 제거하고 In-flow로 전환.
        Wrapper(210px)의 width가 표시 크기를 결정하고(1:2 → 420px),
        Phone의 고유 높이가 Grid Row / Panel Natural Height를 주도한다.
        고정 height를 새로 만들지 않는다. */
/* v6 : Description~Feature 옆(row 2/span2)이 아니라 Intro(Badge+Headline)부터
   Feature까지(row 1/span3) 옆으로 확장. Phone Top이 Intro Top(Section 최상단)과
   같아져 "Headline과 Phone이 같은 상단 Visual Zone" 요구를 만족한다.
   Intro/Description이 grid-column:1/-1이라 실제로는 Column 2(Phone 자리)에
   겹쳐 배치되는 형태지만, 위 두 Rule의 주석에 설명한 대로 시각 충돌은 없다. */
.event-app__phone {
  grid-column: 2;
  grid-row: 1 / span 3;
  align-self: start;
}

/* v3 : QR / Store를 좌우로 벌리지 않고 하나의 Download Block으로 세로 Stack한다.
   상단 QR Row(QR + 설명) ─ 12 ─ 하단 Store Row(Badge 2개 가로) */
.event-app__cta {
  grid-column: 1 / -1;
  grid-row: 4;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3); /* QR Row → Store Row 12px */
}

.event-app__qr {
  display: flex;
  align-items: center;
  gap: var(--space-3); /* QR ↔ Text 12px */
}

/* v3 : Store Badge 2개를 QR Row 아래 한 줄로 가로 배치한다.
   두 Badge의 원본 폭이 달라도 강제로 맞추지 않는다. (height 기준 정렬) */
.event-app__stores {
  display: flex;
  align-items: center;
  gap: 10px; /* Badge 간 10px. TODO: Token 승격 검토 */
}

/* Badge Image 자체가 CTA Visual이므로 Link는 이미지 크기를 그대로 감싼다.
   (v2의 128 x 38 고정 Shell 제거) */
.event-app__store {
  display: block;
}


/* ---------- Category Recap Layout ----------
   Today Section의 Life Shortcut Bar와 같은 1단 Utility Bar 구조다.
   고정 height를 주지 않고 Padding + Item Height(54)로만 결정한다.
     16 + 54 + 16 + border 2 = 88px

   Inner : 1338 - Border(1 x 2) - Padding(20 x 2) = 1296px
   List  : 1296 - Title 160 - Gap 20 = 1116px
   Item  : (1116 - Gap 10 x 5) / 6 = 177.67px   (v1: 7개 / 150.86px)
   Item 폭을 고정하지 않고 1fr로 균등 분배하므로 항목 수가 바뀌어도 자동 재계산된다. */

.event-recap {
  display: flex;
  align-items: center;
  gap: var(--space-5); /* Title ↔ List 20px */
  margin-top: var(--space-6); /* Main Row → Category Recap 24px */
  padding: var(--space-4) var(--space-5); /* 16px 20px */
}

/* Title은 Utility Bar Label 역할이라 고정 폭만 차지하고 늘어나지 않는다 */
.event-recap__title {
  flex: 0 0 160px; /* TODO: Token 승격 검토 */
}

.event-recap__list {
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 10px; /* TODO: Token 승격 검토 */
  min-width: 0;
}

.event-recap__item {
  min-width: 0;
}

.event-recap__link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2); /* Icon ↔ Label 8px */
  height: 54px; /* TODO: Token 승격 검토 */
  padding: 0 var(--space-2);
  min-width: 0;
}


/* ==================================================
   Main Utility Layout
   메인페이지 마지막 Section(공지사항 / 고객센터 / 매물 등록 CTA).

   구조: main-utility(투명 Wrapper) > __inner(1338px) > utility-layout
         utility-layout > utility-info(910px Panel) + utility-cta(408px Panel)
         utility-info   > utility-notice(430fr) + utility-customer(480fr)

   이 Section은 새로운 콘텐츠를 추천하는 Section이 아니라
   "소식 확인 / 도움 받기 / 직접 등록하기" 로 넘어가는 Utility 영역이다.
   따라서 별도의 대형 Section Title(H2 + Subtitle)을 두지 않고
   3개 기능 Block이 바로 시작한다.

   Panel 문법 끊기 (v3, 이 Section의 핵심):
     Recommend / Popular / Today / Event 는 1400px White Panel이지만
     Utility Section은 Panel이 아니다. Section은 투명 Layout Wrapper가 되고
     Information / CTA 두 Panel이 각각 독립 Panel로 선다.

       [ Information 910 ]  20px  [ CTA 408 ]

     Utility는 콘텐츠 Section이 아니라
       서비스 콘텐츠 종료 → 공지 / 고객지원 / 행동 유도 → Footer
     로 이어지는 Transition 영역이기 때문이다.

     구현은 Override가 아니라 "공통 Selector에서 이름 빼기"로 한다.
     components.css 의 Main Section Panel Selector에서 .main-utility 를 제거하면
     Background / Border / Radius / Shadow 가 애초에 적용되지 않는다.
     !important 나 재선언(background: transparent 등)을 쓰지 않는다.

   계산:
     Inner   1400 - 62 = 1338px      (62 = 다른 Panel의 Border 2 + Padding 60)
                                      margin auto 로 좌우 31px씩 중앙 정렬되어
                                      다른 Section Content Edge와 X축이 일치한다.
     Layout  Info 910 + Gap 20 + CTA 408 = 1338px

   Information Panel 내부 (v3):
     Panel이 자기 Padding(20px)과 Border(1px)를 가지므로
     Content Box = 910 - 2 - 40 = 868px 이다.
     여기에 430px / 480px 고정 Column을 그대로 두면 42px Overflow가 난다.
     그래서 고정 px 대신 같은 비율의 fr Track(430fr / 480fr)으로 바꿔
     "외곽 910px + 430 : 480 비율"을 모두 만족시킨다.

       Notice   Track = 868 x 430/910 = 410.15px → Content 410.15 - 24 = 386.15px
       Customer Track = 868 x 480/910 = 457.85px → Content 457.85 - 1 - 24 = 432.85px

     Notice ↔ Customer Gap 은 계속 0이고 Customer의 border-left 1px Divider만 둔다.
     전역 box-sizing: border-box 이므로 Border와 Padding은 Track 안쪽에서
     소비되고, Information Panel 외곽은 정확히 910px을 유지한다. (911px 아님)

   Row 높이:
     고정 height를 주지 않는다. Outer Padding이 사라졌으므로 Section 높이는
     곧 Row 높이다. Information Panel의 자연 높이
       Border 1 + Padding 20 + Notice Content 132.19 + Padding 20 + Border 1
     가 CTA min-height(150px)보다 크므로 Row 높이를 결정하고,
     CTA는 align-items: stretch 로 같은 높이까지 늘어난다.
     → 두 Panel의 Top / Bottom Edge가 자동으로 일치한다. (고정 height 없음)

   Section 간 Gap 은 공통 정책(16px)을 그대로 쓴다.
     Event ─ 16px ─ Utility ─ 16px ─ Footer
     Event의 margin-bottom이 위쪽 16px을, 이 Section의 margin-bottom이
     아래쪽 16px을 만든다. (한 방향 margin 원칙 유지)

   TODO(responsive): Breakpoint 정책이 미확정이라 @media를 추가하지 않았다.
                     향후 좁은 Viewport에서는 utility-layout 을 1fr로 내리고
                     utility-info 의 Divider를 가로 Divider로 바꾸면 된다.

   아래 수치는 실제 화면 검토 전 초기 구현값이며 Token으로 승격하지 않았다.
   - Info 910 / Notice 430fr / Customer 480fr / CTA 408 / Layout Gap 20
   - Inner 보정값 62 / Customer Icon 40px / CTA min-height 150px / CTA Image 110px
================================================== */

/* v3 : 투명 Layout Wrapper. Padding을 갖지 않는다.
   Background / Border / Radius / Shadow 는 components.css 의 공통 Panel
   Selector에서 .main-utility 이름을 빼는 방식으로 제거했다. (Override 없음)
   Section 간 Rhythm을 만드는 margin-bottom만 남긴다. */
.main-utility {
  margin-bottom: var(--space-4); /* Utility → Footer 16px */
}

/* Utility Content Box(1338px).
   다른 Main Section은 1400px Panel의 Border(1 x 2) + Padding(30 x 2)이
   1338px Content Box를 만들지만, 이 Section은 Panel이 아니므로
   같은 Edge를 Inner Width로 직접 만든다.

     1400 - Border(1 x 2) - Padding(30 x 2) = 1338
     (1400 - 1338) / 2 = 31px → margin auto 로 좌우 31px씩 중앙 정렬

   그 결과 Recommend / Popular / Today / Event 의 Content Left/Right Edge와
   정확히 같은 X축에 놓인다. 1338을 하드코딩하지 않고 --content-width 에서
   유도해 두어, Content Column이 바뀌면 함께 따라간다. */
.main-utility__inner {
  width: 100%;
  /* max-width: calc(var(--content-width) - 62px); */
  margin: 0 auto;
}

/* 910 + 20 + 408 = 1338
   두 번째 Column을 minmax(0, 1fr)로 두어 부모가 1338px보다 좁아져도
   Overflow 없이 축소되게 한다. 1338px에서는 정확히 408px가 된다. */
.utility-layout {
  display: grid;
  grid-template-columns: 910px minmax(0, 1fr);
  column-gap: 20px;
  align-items: stretch;
}

/* Information Panel (v3)
   Outer Section Padding이 사라졌으므로 이 Panel이 자기 Padding을 책임진다.
   CTA와 같은 20px(--space-5)을 써서 두 형제 Panel의 Edge 언어를 맞춘다.

   Width : Padding / Border를 포함해 정확히 910px이다. (box-sizing: border-box)
     Content Box = 910 - Border(1 x 2) - Padding(20 x 2) = 868px

   Column을 430px / 480px 고정으로 두면 868px Content Box에서
   910px를 요구해 42px Overflow가 난다. 그래서 고정 px 대신
   같은 비율의 fr Track으로 바꿔 "430 : 480" 시각 비율만 유지한다.

     Notice   = 868 x 430/910 = 410.15px
     Customer = 868 x 480/910 = 457.85px

   외곽 910px과 두 영역의 비율은 그대로이고, Panel Padding이 커져도
   Overflow 대신 Track이 함께 줄어든다.
   column-gap은 계속 0이다. 두 Block 사이 공백은 Divider가 대신한다.

   Divider는 이 Padding 안쪽까지만 그어져 Panel Edge / Radius에 닿지 않는다. */
.utility-info {
  display: grid;
  grid-template-columns: minmax(0, 430fr) minmax(0, 480fr);
  column-gap: 0;
  align-items: stretch;
  padding: 20px 32px 20px 32px;
}


/* ---------- Notice ----------
   v3 : Panel 좌측 Edge 여백은 이제 Information Panel의 Padding(20px)이 담당하므로
        여기서는 Divider 쪽 여백만 갖는다. (기존 좌측 16px 제거)
   우측 24px : Divider와 본문이 붙지 않게 하는 여백
   (Title 가용폭 386 - Dot 4 - Gap 8 - 12 - Date 75 = 287px, 가장 긴 공지 제목 230px) */

.utility-notice {
  padding-right: var(--space-6); /* 24px = Divider 여백 */
  min-width: 0;
}

.utility-notice__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.utility-notice__list {
  margin-top: var(--space-5); /* Header → List 20px */
}

.utility-notice__item + .utility-notice__item {
  margin-top: var(--space-3); /* Row 간 12px */
}

/* Dot ─ Title ─ Date. Title만 늘어나고 Date는 우측에 고정된다. */
.utility-notice__link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.utility-notice__dot {
  flex-shrink: 0;
  width: 4px;
  height: 4px;
  border-radius: var(--radius-pill);
}

.utility-notice__title {
  min-width: 0;
}

.utility-notice__date {
  flex-shrink: 0;
  margin-left: auto;
  padding-left: var(--space-3); /* Title ↔ Date 최소 12px */
}


/* ---------- Customer Center ----------
   Divider(border-left)는 components.css 가 담당한다.
   v3 : 우측 Edge 여백은 Information Panel Padding(20px)이 담당하므로 제거하고,
        좌측 24px(Divider 여백)만 남긴다.
   Border 1px + Padding 24px 모두 box-sizing: border-box 덕분에
   Customer Track 안쪽에서 소비된다. (Track이 458 → Content 433)
   (Shortcut 1개 폭 (433 - 24 - 119) / 3 - gap = 91.2px, 가장 긴 Label 87px) */

.utility-customer {
  padding-left: var(--space-6); /* 24px = Divider 여백 */
  min-width: 0;
}

/* 좌측 Shortcut 3개 / 우측 전화 정보. 전화 정보는 자기 폭만 차지한다. */
.utility-customer__content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--space-6); /* 24px */
  align-items: start;
  margin-top: var(--space-5); /* Header → Content 20px */
}

.utility-customer__shortcuts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: var(--space-2);
}

/* Icon 위 / Label 아래. 480px Column에서 3개가 같은 폭을 갖는다. */
.utility-customer__link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2); /* Icon → Label 8px */
  padding: var(--space-1) 0;
  min-width: 0;
}

/* Asset(assets/icons/customer/*.svg)이 이미 원형 배경을 포함하므로
   Container Background를 새로 만들지 않는다.
   (Today Shortcut / Event App Feature Icon과 같은 처리) */
.utility-customer__icon {
  display: block;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  object-fit: contain;
}

/* 대표번호 Block은 Shortcut Row와 같은 Grid Row에 있지만,
   시각적으로는 "아이탐라 고객센터" 제목과 같은 높이에서 시작하는 편이
   좌우 두 Column의 시작점이 맞아 읽기 쉽다.

   Heading Line Box(18px x 1.4 = 25.2px) + Content margin-top(20px) = 45.2px 만큼
   아래에서 시작하므로 42px 올려 Label Box를 제목 Box보다 3.2px 아래에 둔다.
   (Half-leading 차이를 포함한 실제 글자 기준 약 2.9px 아래)

   margin이 아니라 position: relative 로 올린다.
   negative margin은 Grid Row 높이를 함께 줄여 Information Panel 전체 높이가
   바뀌지만, relative는 Layout Box를 그대로 두어
   고객센터 / Panel / Section 높이가 전혀 변하지 않는다. */
.utility-customer__phone {
  position: relative;
  top: -32px;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}


/* ---------- 매물 등록 CTA ----------
   좌측 Copy + Button / 우측 Illustration.
   min-height가 Section Row 높이를 결정한다. */

.utility-cta {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--space-4);
  align-items: center;
  min-height: 150px;
  padding: 20px 46px 20px 36px;
}

.utility-cta__body {
  min-width: 0;
}

.utility-cta__button {
  display: inline-flex;
  align-items: center;
  height: 38px;
  margin-top: var(--space-3); /* Copy → Button 12px */
  padding: 0 18px;
}

/* 원본 1246x1262(거의 정사각) Illustration이다.
   비율이 찌그러지지 않도록 정사각 Box + object-fit: contain 으로 표시한다. */
.utility-cta__image {
  display: block;
  flex-shrink: 0;
  width: 110px;
  height: 110px;
  object-fit: contain;
}


/* ==================================================
   Footer Layout
   구조: footer(배경 100%) > footer__inner(max 1680px, 중앙 정렬)
         footer__main = [ footer__info ] ...flexible space... [ footer__customer ]

   - Header와 동일한 X축 Alignment 체계(1680px 내부에 좌우 24px)를 사용한다.
   - 고정 height / min-height를 두지 않고 콘텐츠 높이로 결정한다.
   - Footer 자체에는 Shadow를 사용하지 않는다.
================================================== */

.footer {
  background-color: var(--mono-900);
}

.footer__inner {
  max-width: var(--service-frame-width);
  margin: 0 auto;
  /* Top 40px / 좌우 24px / Bottom 32px */
  padding: var(--space-10) var(--container-padding) var(--space-8);
}

.footer__main {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-10);
}

/* 좌측 정보 영역 : 고정 width를 주지 않고 남는 공간을 사용한다 */
.footer__info {
  min-width: 0;
}

/* 우측 고객센터 : 약 300px. 좁아지면 줄어들 수 있게 max-width로 처리 */
.footer__customer {
  flex-shrink: 0;
  max-width: 300px; /* TODO: 화면 검토 후 Token 승격 검토 */
}
