@charset "utf-8";
/* ==================================================
   real-estate.css
   부동산 목록 페이지 전용 스타일 (pages/real-estate/index.html)

   [Source of Truth]
   1) docs/real-estate/real-estate-domain-spec.md              (Domain Contract)
   2) docs/real-estate/real-estate-web-implementation-guide.md (PC Web Guide)
   3) 기존 아이탐라 Design System / Token
   위 순서가 우선순위다. 시각적 이유로 Domain Contract를 바꾸지 않는다.

   [적용 범위]
   이 파일은 "부동산 Domain 목록 화면"의 Template CSS다.
   Canonical Category 8종(아파트 / 원룸·투룸 / 단독·전원주택 / 상가·사무실 /
   토지 / 공장·창고 / 숙박·펜션 / 분양)은 각각 별도의 HTML Page가 아니라
   같은 Page 안의 Category(State)이므로, 이 파일 하나가 8개 Category를 담당한다.
   (Web Guide §3 — `주거` 같은 임의 상위 카테고리를 새로 정의하지 않는다)

   이번 1차 재설계의 Reference Category는 "아파트" 하나다.
   나머지 7개 Category의 Filter Switching / 기능 구현은 이번 범위가 아니다.

   Category 전환 시 바뀌는 것은 다음 세 지점의 "내용"뿐이고
   Layout / Component 규칙은 바뀌지 않는다.

     1) [data-real-estate-schema] .real-estate-quick-filter  (상단 Quick Filter)
     2) [data-real-estate-schema] .real-estate-filter        (좌측 Detail Filter)
     3) [data-real-estate-card-spec] .real-estate-card__specs (Card Spec Row)

   따라서 Category별 전용 Selector(.real-estate-apartment-* 등)를 만들지 않는다.
   Category 고유 표현이 꼭 필요해지면 .real-estate-* 내부 Modifier / State로 둔다.
   적용되지 않는 항목은 Disabled가 아니라 숨긴다 (Web Guide §20).

   [CSS 책임 분리]
   - 공통 Header / Breadcrumb / Pagination / photo-count 는 이 파일에 없다.
     각각 layout.css / components.css 가 담당하며 여기서 다시 정의하지 않는다.
   - Main Layout(1400 + 40 + 240) 골격도 layout.css 의 .main-layout 을 그대로 쓴다.

   [Wing]
   docs/ui-policy.md 의 "Wing 노출 화면"에 "부동산 목록"이 명시되어 있으므로
   메인페이지와 동일한 Wing(240px)을 노출한다. 임의 판단이 아니다.
   이번 재설계로 Wing Width / Size / Sticky / Gap 을 변경하지 않았다.

   [수치]
   아래 구현값은 실제 화면 검토 전 초기값이며 Token으로 승격하지 않았다.
   tokens.css 에 새 Token을 추가하지 않았다.
================================================== */


/* ==================================================
   00. Category Visibility
   Web Guide §20 : "해당하지 않는 항목은 Disabled가 아니라 숨긴다"

   숨김은 Class State가 아니라 HTML `hidden` 속성으로 표현한다.
   (Screen Reader / 검색 / Tab 이동에서도 동시에 빠진다)

   다만 UA Stylesheet의 [hidden] { display: none } 은 Class Selector보다
   우선순위가 낮아서, display를 직접 지정한 Component에서는 무력화된다.
   해당 Component만 명시적으로 되돌린다.

     .real-estate-quick-filter__field  display: flex
     .real-estate-filter__pending      display: flex

   나머지(__group / __subgroup)는 display를 지정하지 않아 UA 규칙이 그대로 동작한다.
================================================== */

.real-estate-quick-filter__field[hidden],
.real-estate-filter__pending[hidden] {
  display: none;
}


/* ==================================================
   01. Page Shell
   .real-estate-page 는
   <main class="main-layout main-layout--sub real-estate-page"> 에 함께 붙는다.
   Layout 골격은 main-layout 이, Domain Context는 이 Class가 갖는다.

   data-real-estate-category 는 현재 Active Category를 문서에 명시하는 값이다.
   (이번 Reference Category는 apartment. 향후 JS/Server가 이 값만 바꾸면 된다)
================================================== */

.real-estate-page {
  padding-bottom: var(--space-16); /* 목록 하단 ↔ Footer 64px */
}

/* 최상위 1400px Wrapper Padding 정책 (v2 - 재설계)
   =================================================
   [Before]
     .real-estate-page .main-layout__content { padding: 0 40px; }
     -> 1400px Column 안에서 좌우 40px씩 다시 잘려 실제 Content Width가 1320px.
        Header Logo(x=40)에 맞추려는 정렬 목적이었으나, 부동산처럼 정보량이 많은
        화면에서 80px을 상시 소모하는 구조였다.

   [After]
     Padding을 두지 않는다. 실제 Content Width = 1400px.

   Main Content의 좌우 Edge는 Header / Hero가 아니라
   .main-layout__inner 의 첫 번째 Grid Column(--content-width, 1400px)
   그 자체에 정렬된다. (layout.css .main-layout__inner)

     Frame  : |0 ------------------ 1400| 40 |Wing 240| = 1680
     Content: |0 ------------------ 1400|

   여백 책임은 Page Wrapper가 아니라 각 Component가 진다.
   Search Form / Quick Filter Item / Detail Filter Panel / Listing Card /
   Bottom Utility 는 각자 자기 Surface 안쪽 Padding을 그대로 유지한다.
   (이 파일 아래 각 Component Block 참고 — 일괄 제거 대상이 아니다)

   Wing에는 영향이 없다. Padding은 Grid Item 내부 값이라
   Column 폭(1400) / Gap(40) / Wing(240) 계산에 관여하지 않는다. */


/* ==================================================
   02. Page Head
   Breadcrumb → Page Title + Subtitle
   Main Content(1400px) Left Edge에 그대로 정렬한다. 별도 Padding을 두지 않는다.
================================================== */

.real-estate-page__breadcrumb {
  padding-top: var(--space-6); /* Header Border ↔ Breadcrumb 24px */
}

.real-estate-page__head {
  margin-top: var(--space-3);
}

.real-estate-page__title {
  color: var(--text-primary);
  font-size: var(--text-page-title-size); /* 32px */
  font-weight: var(--text-page-title-weight);
  line-height: var(--text-page-title-line-height);
}

.real-estate-page__subtitle {
  margin-top: var(--space-2);
  color: var(--text-secondary);
  font-size: var(--font-size-base); /* 16px */
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-normal);
}


/* ==================================================
   03. Search
   메인의 .hero-search 를 복제하지 않는다.
   Hero Search는 Landscape Background 위에 뜨는 Floating Bar라 Shadow를 갖지만,
   Sub Page Search는 White 배경 위 Inline Control이므로 Shadow 대신 Border를 쓴다.
   (Shadow는 실제로 떠 있는 요소에만 사용한다는 tokens.css 정책을 따른다)

   Search Bar를 Content 전체 폭(1400)으로 늘리지 않는다.
   입력 시작점과 Button이 지나치게 멀어지므로 상한을 둔다.
================================================== */

.real-estate-search {
  margin-top: var(--space-6);
}

.real-estate-search__form {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  max-width: 720px; /* TODO: Token 승격 검토 */
  height: 56px;     /* 8 + 40 + 8 */
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-5);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background-color: var(--surface-default);
}

.real-estate-search__form:focus-within {
  border-color: var(--border-focus);
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

/* Icon wrapper : 공용 Search Asset(assets/icons/search/search-magnifier.svg)을
   그대로 쓴다. 부동산 전용 Icon Asset을 새로 만들지 않는다. */
.real-estate-search__icon {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
}

.real-estate-search__icon-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.real-estate-search__input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  color: var(--text-primary);
  font-size: var(--font-size-base); /* 16px */
  font-weight: var(--font-weight-regular);
  line-height: var(--line-height-normal);
}

.real-estate-search__input::placeholder {
  color: var(--text-tertiary);
}

.real-estate-search__input:focus {
  outline: none; /* Focus Ring은 Form 전체(:focus-within)가 담당한다 */
}

.real-estate-search__button {
  flex-shrink: 0;
  width: 96px;
  height: 40px;
  border-radius: var(--radius-md);
  background-color: var(--brand-secondary);
  color: var(--text-inverse);
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-normal);
  transition: background-color var(--transition-fast);
}

.real-estate-search__button:hover {
  background-color: var(--brand-interaction);
}

.real-estate-search__button:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 3px;
}


/* ---------- 인기검색어 ----------
   메인 Hero의 .hero-keyword 는 Landscape 위 반투명 White Pill이라
   White 배경에서는 읽히지 않는다. 정보 구조(아이콘 + 라벨 + 태그 목록)는
   그대로 두고 Surface / Border만 Sub Page 기준으로 바꾼 Block이다. */

.real-estate-search__keyword {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

.real-estate-search__keyword-title {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-secondary);
  font-size: var(--font-size-sm); /* 13px */
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-normal);
}

/* 공용 Asset(assets/icons/search/search-trending.svg) 재사용. 16x16 */
.real-estate-search__keyword-icon {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
}

.real-estate-search__keyword-icon-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.real-estate-search__keyword-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.real-estate-search__keyword-tag {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 var(--space-3);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-pill);
  background-color: var(--surface-default);
  color: var(--text-secondary);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-normal);
  white-space: nowrap;
  transition: border-color var(--transition-fast), color var(--transition-fast),
              background-color var(--transition-fast);
}

.real-estate-search__keyword-tag:hover {
  border-color: var(--brand-secondary);
  background-color: var(--surface-selected);
  color: var(--brand-secondary);
}

.real-estate-search__keyword-tag:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}


/* ==================================================
   04. Category Navigation
   Domain Contract §1 / Web Guide §3 의 Canonical Category 8종.
   개별 HTML Page가 아니라 같은 Page의 State다.

   [Category vs Quick Filter 위계]
   Category는 "무엇을 찾는가", Quick Filter는 "그 안에서 어떻게 좁히는가"다.
   두 영역을 같은 무게로 그리지 않는다. 어느 쪽도 Card로 만들지 않는다.

     Category     : 18px Bold Tab / Bar 높이 52px / Active Indicator 3px
                    Surface 없음. Bottom Border 1줄만.
     Quick Filter : 14px Chip / 높이 42px / --border-light
                    Category Bar 아래 한 단계 낮은 밀도로 읽힌다.

   GNB(.gnb)를 복제하지 않는다. GNB는 Header 안 서비스 최상위 Navigation이고
   이쪽은 Content 안 Domain Category라 영역 자체가 다르다.
================================================== */

.real-estate-category {
  margin-top: var(--space-8);
  border-bottom: 1px solid var(--border-default);
}

.real-estate-category__list {
  display: flex;
  align-items: stretch;
  gap: var(--space-8); /* 32px */
}

.real-estate-category__item {
  display: flex;
}

/* v3 : Category는 다른 Page로 가지 않고 같은 Page의 State만 바꾸므로
   <a>가 아니라 <button role="tab">이다. reset.css 가 button의 border/background를
   이미 지우므로 Text Tab 표현은 그대로 유지된다.
   Button 기본 가운데 정렬만 Text Tab 기준으로 되돌린다. */
.real-estate-category__link {
  position: relative;
  display: flex;
  align-items: center;
  height: 52px;
  padding: 0;
  text-align: left;
  color: var(--text-secondary);
  font-size: var(--font-size-lg); /* 18px - Quick Filter(14px)보다 명확히 우위 */
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-normal);
  white-space: nowrap;
  transition: color var(--transition-fast);
}

.real-estate-category__link:hover {
  color: var(--brand-secondary);
}

.real-estate-category__link.is-active {
  color: var(--brand-primary);
  font-weight: var(--font-weight-bold);
}

/* Active Indicator : Category Bar의 Bottom Border 위에 정확히 겹친다 */
.real-estate-category__link.is-active::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  height: 3px;
  background-color: var(--brand-secondary);
}

.real-estate-category__link:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
  border-radius: var(--radius-sm);
}


/* ==================================================
   05. Quick Filter
   Web Guide §5.1 / §7.1 — 아파트 Quick Filter Schema:
     지역 / 거래유형 / 상세유형 / 가격 / 면적 / 방 수

   Guide §7.1 마지막 항목 `상세조건`은 PC Web에서 노출하지 않는다.
   좌측 Detail Filter Panel이 항상 열려 있으므로 같은 Panel을 여는 상단
   진입점은 기능 중복이다. Filter 항목 자체를 없앤 것이 아니라
   Desktop에서 진입점이 하나로 충분하다는 배치 판단이다.
   Field 6개는 --space-2(8px) gap으로 균일하게 정렬된다.

   Quick Filter와 Detail Filter는 서로 다른 Data Model을 만들지 않는다
   (Web Guide §5.2). 같은 Domain Filter를 Desktop UX상 어디에 두느냐의 차이다.
   따라서 Quick의 data-real-estate-field 값은 Detail Filter의 name 과 같은
   Domain key 체계를 쓴다.

   가격 / 면적은 Domain Contract §7이 "최소~최대 범위"로 확정한 필터라
   임의 구간(1억 이하 / 3억~5억 …)을 만들지 않고 Range 입력으로 둔다.
   실제 검색 key는 라벨이 아니라 data-* 가 보유한다.
     가격 -> 거래유형별 가격 검색 기준 key (Domain §2)
     면적 -> 아파트는 exclusiveArea (Domain §3 / Web Guide §13)

   Dropdown 동작은 assets/js/common.js 의 initHeaderDropdown() 을 그대로 쓴다.
   해당 함수는 Header 전용이 아니라 document 전체의 [data-dropdown] 을 찾으므로
   같은 data-* 규약만 지키면 신규 JS 없이 동작한다.

   Category 확장:
     이 Block은 data-real-estate-schema 를 갖는다. Category가 바뀌면
     Block 내부 Field 목록만 교체하고 Class / Layout은 그대로 둔다.
     적용되지 않는 Field는 Disabled가 아니라 숨긴다 (Web Guide §20).
================================================== */

.real-estate-quick-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-5) 0;
}

/* Dropdown 기준점. Item 자체가 아니라 Host가 갖는다 */
.real-estate-quick-filter__field {
  position: relative;
  display: flex;
}

/* Chip 표현은 메인 .recommend-filter__item 의 Design Language를 따른다.
   (White Surface + --border-light 1px + radius 10px, Hover 시 Brand Light)
   --border-default 대신 --border-light 를 써서 Category Bar보다 Border를 약하게 둔다. */
.real-estate-quick-filter__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 42px;
  padding: 0 var(--space-4);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  background-color: var(--surface-default);
  font-size: var(--font-size-md); /* 14px */
  line-height: var(--line-height-normal);
  white-space: nowrap;
  transition: border-color var(--transition-fast), background-color var(--transition-fast),
              color var(--transition-fast);
}

.real-estate-quick-filter__item:hover {
  border-color: var(--brand-secondary);
  background-color: var(--bg-brand-light);
  color: var(--brand-secondary);
}

.real-estate-quick-filter__item:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

/* Open 상태 : Header Dropdown(.is-open)과 동일한 상태 문법 */
.real-estate-quick-filter__field.is-open .real-estate-quick-filter__item {
  border-color: var(--brand-secondary);
  background-color: var(--bg-brand-light);
}

.real-estate-quick-filter__label {
  color: var(--text-tertiary);
  font-weight: var(--font-weight-regular);
}

.real-estate-quick-filter__value {
  color: var(--text-primary);
  font-weight: var(--font-weight-semibold);
}

/* 값이 선택된 Item. 이번 Mock은 전부 "전체"라 사용되지 않지만
   State 규칙을 미리 확정해 둔다. */
.real-estate-quick-filter__item.is-selected {
  border-color: var(--brand-secondary);
  background-color: var(--surface-selected);
}

.real-estate-quick-filter__item.is-selected .real-estate-quick-filter__value {
  color: var(--brand-secondary);
}

.real-estate-quick-filter__arrow {
  color: var(--text-tertiary);
  font-size: var(--font-size-xs);
  line-height: 1;
}

/* ---------- Quick Filter Dropdown Panel ----------
   .header-dropdown 을 재사용하지 않는다. Header Dropdown은 Header 하단에
   붙는 Utility Panel(폭 300/380 고정)이고, 이쪽은 Filter Field 폭 기준의
   Option Picker라 Sizing 규칙이 다르다. */

.real-estate-quick-filter__panel {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: 0;
  z-index: var(--z-dropdown);
  min-width: 200px;
  padding: var(--space-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background-color: var(--surface-default);
  /* 실제로 떠 있는 요소이므로 Shadow를 사용한다 */
  box-shadow: var(--shadow-md);
}

.real-estate-quick-filter__panel[hidden] {
  display: none;
}

.real-estate-quick-filter__panel--wide {
  min-width: 260px;
}

.real-estate-quick-filter__option {
  display: block;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: var(--font-size-md);
  line-height: var(--line-height-normal);
  text-align: left;
  white-space: nowrap;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.real-estate-quick-filter__option:hover {
  background-color: var(--surface-hover);
  color: var(--brand-secondary);
}

.real-estate-quick-filter__option.is-selected {
  background-color: var(--surface-selected);
  color: var(--brand-secondary);
  font-weight: var(--font-weight-semibold);
}

.real-estate-quick-filter__option:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}

/* ---------- Range Panel (가격 / 면적) ----------
   Domain Contract §7 이 가격·면적을 "최소~최대 범위"로 확정했으므로
   임의 구간 Chip(1억 이하 / 3억~5억 …)을 만들지 않고 Range 입력을 쓴다.
   실제 검색 key는 Markup의 data-* 가 보유한다. */

.real-estate-range {
  padding: var(--space-2);
}

.real-estate-range__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-2);
}

.real-estate-range__field {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  height: 38px;
  padding: 0 var(--space-3);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background-color: var(--surface-default);
}

.real-estate-range__field:focus-within {
  border-color: var(--border-focus);
}

.real-estate-range__input {
  width: 100%;
  min-width: 0;
  border: 0;
  background: none;
  color: var(--text-primary);
  font-size: var(--font-size-md);
  line-height: var(--line-height-normal);
  text-align: right;
  font-variant-numeric: tabular-nums;
  /* Number Spinner는 Filter 폭을 잡아먹어 숨긴다 */
  appearance: textfield;
}

.real-estate-range__input::-webkit-outer-spin-button,
.real-estate-range__input::-webkit-inner-spin-button {
  margin: 0;
  appearance: none;
}

.real-estate-range__input:focus {
  outline: none; /* Focus Ring은 __field(:focus-within)가 담당 */
}

.real-estate-range__unit {
  flex-shrink: 0;
  color: var(--text-tertiary);
  font-size: var(--font-size-sm);
  line-height: 1;
}

.real-estate-range__dash {
  color: var(--text-tertiary);
  font-size: var(--font-size-sm);
  line-height: 1;
}

/* 검색 기준 key / 단위 환산을 사용자에게 알리는 보조 문구 */
.real-estate-range__note {
  margin-top: var(--space-2);
  color: var(--text-tertiary);
  font-size: var(--font-size-xs);
  line-height: var(--line-height-normal);
}


/* ==================================================
   06. Body Layout (v3 - Visual Comparison)

   우측 Context Sidebar(지도 / 인기검색 TOP5 / 안심 서비스 / 최근 본 매물)를
   제거하고 그 폭을 Listing이 흡수하는 2 Column 구조다.

     [Before] 280 + 24 + 792 + 24 + 280 = 1400   Detail Filter | Result | Sidebar
     [After ] 280 + 24 + 1096            = 1400   Detail Filter | Result

   Sidebar가 쓰던 280 + Gap 24 = 304px 전부가 Listing으로 넘어간다.
     Listing  792 -> 1096 (+304)
     Card 열   2열 386 -> 3열 352

   이 구조는 "우측 Sidebar를 제거했을 때 매물 탐색 화면이 어떻게 보이는지"를
   확인하기 위한 Visual Comparison 단계다. 최종 구조 확정이 아니다.
   Sidebar 기능을 다른 위치로 이동하거나 대체 UI로 보완하지 않았다.

   Filter Column은 기존 --sidebar-width(280px) Token을 그대로 쓴다.
   Gap도 기존 --space-6(24px) 그대로다. 비교 변수를
   "Sidebar 제거 + Listing 3열" 하나로 제한하기 위해 둘 다 건드리지 않는다.

   Sidebar와 Wing은 다른 개념이므로 --wing-width 를 여기에 쓰지 않는다.
   Content Frame(1400) + Gap(40) + Wing(240) = 1680 정책은 그대로다.

   minmax(0, 1fr) : Viewport가 1680보다 좁아져 Content Column이 줄어도
   Result가 먼저 줄고 가로 Overflow가 발생하지 않게 한다.
   docs/ui-policy.md 기준 Breakpoint가 미확정이므로 Media Query를 두지 않는다.
================================================== */

.real-estate-body {
  display: grid;
  grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
  column-gap: var(--space-6);
  align-items: start;
}


/* ==================================================
   07. Detail Filter (좌측)
   Web Guide §10 — 아파트 Detail Filter Policy (9 Group):
     매물 특징 / 방·욕실 / 층 / 방향 / 주차 / 입주가능일 / 관리비 / 난방 / 시설·옵션

   매물 특징은 Web Guide §9 Preference Filter다. Core Filter(지역/거래유형/
   가격/면적)와 같은 시각적 우선순위를 주지 않기 위해 Quick Filter로 올리지 않고
   좌측 첫 Group에 둔다. 항목은 요구사항에 명시된 신축 / 반려동물 가능 2개뿐이며
   임의로 늘리지 않는다.

   Option 값을 문서가 확정하지 않은 Group(방향 / 주차 세대당 N대 / 입주가능일 /
   관리비 구간 / 난방 / 시설·옵션)은 최종 사용자 화면에 개발용 policy-pending
   안내문을 노출하지 않기 위해 `UI Mock` Option으로 채웠다.
   (Domain Spec §12 [LATER] / Web Guide §1.2 - 요구사항이 제거된 것은 아니므로
    Group 자체는 유지한다)

   중요: 이 Mock Option은 Domain Enum / Backend Contract가 아니다.
   Markup의 data-domain-status="ui-mock" 으로 식별하며, 값이 확정되면
   Style / 구조는 그대로 두고 value Mapping만 교체한다.
   .real-estate-filter__pending 은 Panel 전체가 비는 Category(토지 / 공장·창고 /
   숙박·펜션 / 분양)의 Empty State 용도로만 남는다.

   Input 형태:
     `전체` Option이 있는 Group = 단일 선택 -> radio
     `전체` Option이 없는 Group = 다중 선택 -> 기존 Checkbox
     Checkbox / radio 모두 .real-estate-filter__option-input 하나로 그린다.

   Accordion:
     신규 JS를 만들지 않고 <details> / <summary> 를 쓴다.
     - 열림/닫힘, 키보드 조작, Screen Reader 상태가 브라우저 기본 제공이다.
     - 중요 Group(매물 특징 / 방·욕실)만 open 이고 나머지는 접혀 있다.
     - 상태 저장이 필요해지면 그때 JS를 붙이면 되고, 지금 구조를 바꿀 필요가 없다.

   Category 확장:
     이 Panel도 data-real-estate-schema 를 갖는다. Category가 바뀌면
     __group 목록만 통째로 교체하고 Panel Shell / Footer는 재사용한다.
================================================== */

.real-estate-filter {
  position: sticky;
  top: var(--space-5); /* 스크롤 시 상단 20px */
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  background-color: var(--surface-default);
}

/* Header : 좌측 제목 + 선택 개수 / 우측 초기화 Text Action
     상세조건            초기화
     선택 0개                        */
.real-estate-filter__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-5) var(--space-4);
  border-bottom: 1px solid var(--border-light);
}

.real-estate-filter__heading {
  min-width: 0;
}

.real-estate-filter__title {
  color: var(--text-primary);
  font-size: var(--font-size-base); /* 16px */
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-snug);
}

.real-estate-filter__selected {
  margin-top: var(--space-1);
  color: var(--text-tertiary);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-normal);
}

.real-estate-filter__body {
  /* Group이 늘어나도 Panel이 화면을 넘기지 않도록 Panel 안에서만 스크롤한다.
     하단 Footer(약 73px)가 사라졌으므로 그만큼 Body가 더 쓸 수 있다.
     Sticky top(20) + Header(약 78) + 하단 여유(30) 를 뺀 값이다. */
  max-height: calc(100vh - 130px);
  overflow-y: auto;

  /* Scrollbar 시각적 숨김
     Panel이 Content Column 안에 떠 있는 좁은 탐색 도구라서 기본 Scrollbar
     Track/Thumb이 Filter Option 위에 겹쳐 읽히는 노이즈가 된다.

     Scroll "기능"은 그대로 둔다. overflow:hidden 을 쓰지 않으므로
     Mouse Wheel / Trackpad / Keyboard(PageUp·Down, 방향키, Tab Focus 이동) /
     Screen Reader 스크롤이 전부 정상 동작한다.

     프로젝트에 기존 Scrollbar Utility가 없어 이 Panel에만 적용한다.
     다른 화면에서도 필요해지면 common.css 의 Utility로 승격한다. */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* 구형 Edge / IE */
}

/* Chromium / Safari */
.real-estate-filter__body::-webkit-scrollbar {
  display: none;
}

/* ---------- Filter Group (Accordion) ---------- */

.real-estate-filter__group {
  border-bottom: 1px solid var(--border-light);
}

.real-estate-filter__group-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  color: var(--text-primary);
  font-size: var(--font-size-md); /* 14px */
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-normal);
  cursor: pointer;
  list-style: none; /* 기본 삼각형 Marker 제거 (Firefox) */
}

/* 기본 삼각형 Marker 제거 (Chromium / Safari) */
.real-estate-filter__group-title::-webkit-details-marker {
  display: none;
}

.real-estate-filter__group-title:hover {
  color: var(--brand-secondary);
}

.real-estate-filter__group-title:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}

.real-estate-filter__group-arrow {
  flex-shrink: 0;
  color: var(--text-tertiary);
  font-size: var(--font-size-xs);
  line-height: 1;
  transition: transform var(--transition-fast);
}

.real-estate-filter__group[open] .real-estate-filter__group-arrow {
  transform: rotate(180deg);
}

.real-estate-filter__group-body {
  padding: 0 var(--space-5) var(--space-5);
}

/* ---------- Option List ----------
   Label이 짧은 Group은 2열로 두어 Panel 세로 길이를 줄인다.
   Label이 긴 Group(주차 등)은 --single 로 1열을 쓴다. */

.real-estate-filter__options {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3) var(--space-2);
}

.real-estate-filter__options--single {
  grid-template-columns: minmax(0, 1fr);
}

.real-estate-filter__option-item {
  min-width: 0;
}

.real-estate-filter__option-label {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  color: var(--text-secondary);
  font-size: var(--font-size-sm); /* 13px */
  line-height: var(--line-height-normal);
  cursor: pointer;
  transition: color var(--transition-fast);
}

.real-estate-filter__option-label:hover {
  color: var(--brand-secondary);
}

/* Checkbox : 별도 Common Form Component가 아직 없어 Domain Namespace로 둔다.
   Form Control 공통화는 Form 화면 착수 시 components.css 승격 후보다.
   native input을 숨기지 않고 appearance:none 으로 직접 그리므로
   Focus / Keyboard / Screen Reader 동작이 그대로 유지된다. */
.real-estate-filter__option-input {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin: 1px 0 0; /* 13px Text의 첫 줄 중앙에 맞춘다 */
  appearance: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background-color: var(--surface-default);
  transition: border-color var(--transition-fast), background-color var(--transition-fast);
}

.real-estate-filter__option-input:checked {
  border-color: var(--brand-secondary);
  background-color: var(--brand-secondary);
}

.real-estate-filter__option-input:checked::after {
  content: "✓";
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: var(--text-inverse);
  font-size: 11px; /* Checkmark 전용 구현값. TODO: Token 승격 검토 */
  font-weight: var(--font-weight-bold);
  line-height: 1;
}

.real-estate-filter__option-input:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

/* radio : `전체`가 있는 단일 선택 Group(방향 / 주차 / 관리비 / 난방)용.
   Checkbox와 같은 .real-estate-filter__option-input 을 쓰고 모양만 바꾼다.
   별도 Component / 별도 Class를 새로 만들지 않는다. */
.real-estate-filter__option-input[type="radio"] {
  border-radius: var(--radius-pill);
}

.real-estate-filter__option-input[type="radio"]:checked::after {
  content: "";
  display: block;
  /* 18px Box(테두리 1px 포함)의 안쪽 16px 기준 중앙에 6px 점을 둔다.
     Checkbox의 Checkmark(11px)와 같은 성격의 Component 내부 구현값이다.
     TODO: Form Control 공통화 시 Token 승격 검토 */
  width: 6px;
  height: 6px;
  margin: 5px auto;
  border-radius: var(--radius-pill);
  background-color: var(--text-inverse);
}

.real-estate-filter__option-input:checked + .real-estate-filter__option-text {
  color: var(--brand-secondary);
  font-weight: var(--font-weight-medium);
}

.real-estate-filter__option-text {
  min-width: 0;
  word-break: keep-all;
}

/* ---------- Filter Group : Range (층) ----------
   Domain Contract가 구간(저층 / 중층 / 고층)을 정의하지 않은 숫자 key는
   구간을 지어내지 않고 최소~최대 입력으로 둔다. Quick Filter의 Range와
   같은 .real-estate-range Component를 재사용한다. */

.real-estate-filter__group-body .real-estate-range {
  padding: 0;
}

/* ---------- Filter Group : 정책 미확정 안내 ----------
   Option 값이 Domain Contract에 확정되지 않은 Group에서 선택지를 지어내지
   않기 위한 자리 표시다. Group 자체는 요구사항이므로 숨기지 않는다.
   값이 확정되면 이 문구를 __options 목록으로 교체하면 된다. */

.real-estate-filter__pending {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  background-color: var(--bg-muted);
  color: var(--text-tertiary);
  font-size: var(--font-size-xs);
  line-height: var(--line-height-relaxed);
  word-break: keep-all;
}

/* Panel 전체가 비는 Category(토지 / 공장·창고 / 숙박·펜션 / 분양)용.
   __group-body 안이 아니라 __body 직속이라 자체 여백이 필요하다. */
.real-estate-filter__pending--panel {
  margin: var(--space-5);
}

.real-estate-filter__pending-key {
  color: var(--text-secondary);
  font-weight: var(--font-weight-semibold);
}

/* Group 안에서 방 / 욕실처럼 두 축을 나눌 때 쓰는 소제목 */
.real-estate-filter__subgroup + .real-estate-filter__subgroup {
  margin-top: var(--space-4);
}

.real-estate-filter__subgroup-title {
  margin-bottom: var(--space-2);
  color: var(--text-tertiary);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-normal);
}

/* ---------- 초기화 (Header Text Action) ----------
   PC Web은 Filter Option을 선택하는 즉시 결과가 갱신되는 Interaction을 기준으로
   하므로 하단 [적용하기] Action을 두지 않는다.
   초기화 기능은 폐기하지 않고 Header 우측의 작은 Text Action으로만 남긴다.

   Button Surface(배경 / Border / 높이)를 갖지 않는다. Card / Panel을 새로
   만들지 않고 기존 __header 안에 들어간다.

   선택 0개일 때는 disabled 로 두어 강조하지 않는다.
   (숨기지 않는 이유: 개수가 바뀔 때 Header 높이가 흔들리지 않게 하기 위함)
   TODO(js): 선택 개수에 따라 disabled 속성만 토글하면 된다. */

.real-estate-filter__reset {
  flex-shrink: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-secondary);
  font-size: var(--font-size-sm); /* 13px */
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-normal);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color var(--transition-fast);
}

.real-estate-filter__reset:not(:disabled):hover {
  color: var(--brand-secondary);
}

/* 선택 0개 : 사용할 수 없는 상태. 시선을 끌지 않게 가장 약한 Text로 둔다 */
.real-estate-filter__reset:disabled {
  color: var(--text-disabled);
  text-decoration: none;
}

.real-estate-filter__reset:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}


/* ==================================================
   08. Result Area (가운데)
================================================== */

.real-estate-results {
  min-width: 0;
}

/* ---------- Result Header ----------
   읽어야 할 정보 위계는 3개뿐이다.
     현재 Category(지역 + Category명) / Result Count / Sort
   Control을 더 늘리지 않는다. Panel / Card로 감싸지 않는다. */

.real-estate-results__header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-3);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--border-default);
}

.real-estate-results__heading {
  min-width: 0;
}

/* 현재 Category. Page Title(32px)보다 낮고 Card Title(16px)보다 높다 */
.real-estate-results__title {
  color: var(--text-primary);
  font-size: var(--font-size-xl); /* 20px */
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-snug);
}

.real-estate-results__count {
  margin-top: var(--space-1);
  color: var(--text-secondary);
  font-size: var(--font-size-md);
  line-height: var(--line-height-normal);
}

.real-estate-results__count-value {
  color: var(--brand-secondary);
  font-weight: var(--font-weight-bold);
  font-variant-numeric: tabular-nums;
}

.real-estate-results__controls {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* ---------- Sort ----------
   Quick Filter와 같은 [data-dropdown] 규약을 쓰므로 신규 JS가 없다. */

.real-estate-sort {
  position: relative;
  display: flex;
}

.real-estate-sort__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 36px;
  padding: 0 var(--space-3);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background-color: var(--surface-default);
  color: var(--text-primary);
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-normal);
  white-space: nowrap;
  transition: border-color var(--transition-fast), background-color var(--transition-fast);
}

.real-estate-sort__trigger:hover {
  border-color: var(--border-strong);
  background-color: var(--surface-hover);
}

.real-estate-sort.is-open .real-estate-sort__trigger {
  border-color: var(--brand-secondary);
  background-color: var(--bg-brand-light);
}

.real-estate-sort__trigger:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.real-estate-sort__arrow {
  color: var(--text-tertiary);
  font-size: var(--font-size-xs);
  line-height: 1;
}

.real-estate-sort__panel {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: var(--z-dropdown);
  min-width: 160px;
  padding: var(--space-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background-color: var(--surface-default);
  box-shadow: var(--shadow-md);
}

.real-estate-sort__panel[hidden] {
  display: none;
}

.real-estate-sort__option {
  display: block;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: var(--font-size-md);
  line-height: var(--line-height-normal);
  text-align: left;
  white-space: nowrap;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.real-estate-sort__option:hover {
  background-color: var(--surface-hover);
  color: var(--brand-secondary);
}

.real-estate-sort__option.is-selected {
  background-color: var(--surface-selected);
  color: var(--brand-secondary);
  font-weight: var(--font-weight-semibold);
}

.real-estate-sort__option:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}

/* ==================================================
   09. Result Grid / Card
   .recommend-card 를 재사용하지 않는다. 그 Component는 메인 Recommend Section
   전용(4열 319px 기준)이라 목록 화면에서 폭이 바뀌면 양쪽이 함께 깨진다.
   대신 Card 안의 사진 장수 Badge는 공용 .photo-count 를 그대로 쓴다.

   Grid (v3 - Visual Comparison):
     Context Sidebar 제거로 Listing 폭이 792 -> 1096 이 되어 3열로 전환한다.

       (1096 - Gap 20 x 2) / 3 = 352px

     auto-fill 대신 repeat(3, minmax(0, 1fr)) 을 쓴다.
     Listing 폭을 항상 정확히 3등분해 Card 3장이 같은 폭을 갖고,
     세 번째 Card의 오른쪽 Edge가 Listing Right Edge와 정확히 맞는다.
     (auto-fill은 Column 수가 Viewport에 따라 달라져 3열 비교 자체가 흔들린다)

     minmax(0, 1fr) 이라 Viewport가 좁아져도 Overflow는 발생하지 않고
     Card 폭만 줄어든다. 좁은 Viewport용 Breakpoint는 임의로 만들지 않는다.
     Gap은 기존 --space-5(20px)를 그대로 유지한다.
================================================== */

.real-estate-results__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-5);
  margin-top: var(--space-5);
}

/* Border Color (v4)
   --border-light(#EEF1F5)는 White Page Background와 거의 같아 3열에서
   Card 사이 경계가 읽히지 않았다. 두께(1px)는 그대로 두고 Color만 한 단계
   진한 Neutral Gray로 올린다.

   기준 후보 #D8DEE8 과 기존 Token 거리 비교 (RGB 유클리드):
     --border-light   #EEF1F5   31.84
     --border-default #E2E7EE   14.73  <- 가장 가까움
     --border-strong  #CBD3DE   19.75
   가장 가까운 --border-default 를 재사용한다. 새 Token을 만들지 않는다.

   2px Border / 강한 Shadow / Navy Border 를 쓰지 않는다.
   Hover는 기존 --border-strong 을 유지해 기본보다 한 단계만 또렷해진다.
   (Brand Blue로 강조하지 않는다) */
.real-estate-card {
  position: relative;
  min-width: 0;
  border: 1px solid var(--border-default); /* #E2E7EE */
  border-radius: var(--radius-lg); /* 14px */
  background-color: var(--surface-default);
  overflow: hidden;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.real-estate-card:hover {
  border-color: var(--border-strong); /* #CBD3DE */
  box-shadow: var(--shadow-sm);
}

.real-estate-card__media {
  position: relative;
  aspect-ratio: 4 / 3;
  background-color: var(--bg-muted);
}

.real-estate-card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Media Overlay 정책 (v2)
   Domain Contract §8 / Web Guide §14 의 Card 정보 위계는
     사진 -> 거래유형/가격 -> 제목 -> 지역 -> Category별 핵심정보
   이고, 거래유형은 "가격과 같은 줄"에 놓이는 정보다.
   따라서 거래유형을 사진 위 Badge로 한 번 더 그리지 않는다.
   (같은 값을 Overlay + 가격줄에 이중 노출하면 시각 노이즈만 늘어난다)

   사진 위에 남기는 것은 공용 .photo-count(사진 장수)와 찜하기 둘뿐이다.
   .photo-count 는 components.css 공용 Component / media-photo.svg 를 그대로 쓴다. */

/* 찜하기. 공용 Favorite Component가 아직 없어 Card Scope로 둔다
   (.recommend-card__favorite / .event-card__favorite 와 같은 기존 패턴) */
.real-estate-card__favorite {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-pill);
  background-color: rgba(255, 255, 255, 0.9);
  color: var(--text-secondary);
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.real-estate-card__favorite:hover {
  background-color: var(--surface-default);
  color: var(--error);
}

.real-estate-card__favorite:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

.real-estate-card__favorite-icon {
  font-size: var(--font-size-lg);
  line-height: 1;
}

.real-estate-card__body {
  padding: var(--space-4);
}

/* ---------- Card Body ----------
   위계 : 거래유형/가격 -> 제목 -> 지역 -> Category 핵심정보
   Category가 바뀌어도 이 Shell은 그대로 두고 __specs 의 항목만 교체한다.
   (Web Guide §14 - Card Shell을 Category마다 새로 만들지 않는다) */

/* 1) 거래유형 + 가격 : Card에서 가장 강한 한 줄 */
.real-estate-card__price {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  color: var(--text-primary);
  font-size: var(--font-size-xl); /* 20px */
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-tight);
}

/* 거래유형은 Domain Contract 7종 중 하나다(§2).
   가격보다 앞서 읽히되 가격보다 강하지 않도록 작은 Chip으로 둔다. */
.real-estate-card__transaction {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
  background-color: var(--bg-brand-light);
  color: var(--brand-secondary);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  line-height: 1;
}

.real-estate-card__price-value {
  min-width: 0;
}

/* 2) 제목 */
.real-estate-card__title {
  margin-top: var(--space-2);
  overflow: hidden;
  color: var(--text-primary);
  font-size: var(--font-size-base); /* 16px */
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-snug);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Card 전체를 Click 영역으로 만드는 확장 Link (기존 Card 패턴과 동일) */
.real-estate-card__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.real-estate-card__link:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* 3) 지역 */
.real-estate-card__region {
  margin-top: var(--space-1);
  overflow: hidden;
  color: var(--text-secondary);
  font-size: var(--font-size-sm); /* 13px */
  line-height: var(--line-height-normal);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 4) Category별 핵심정보 (Spec Row)
   아파트 : 전용면적 / 방 수 / 층 / 관리비  (Domain §8, Web Guide §15)
   Category가 바뀌면 이 목록의 __spec 항목만 교체한다.
   Wrap을 허용해 항목 수가 달라져도 Card가 깨지지 않게 한다. */
.real-estate-card__specs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-light);
}

.real-estate-card__spec {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
  color: var(--text-secondary);
  font-size: var(--font-size-sm); /* 13px */
  line-height: var(--line-height-normal);
  white-space: nowrap;
}

.real-estate-card__spec-label {
  color: var(--text-tertiary);
  font-size: var(--font-size-xs);
}

.real-estate-card__spec-value {
  color: var(--text-primary);
  font-weight: var(--font-weight-medium);
}

/* 평 환산 병기 (Web Guide §12 : ㎡ (평)) */
.real-estate-card__spec-pyeong {
  color: var(--text-tertiary);
  font-size: var(--font-size-xs);
}

/* Spec 사이 구분점 */
.real-estate-card__spec + .real-estate-card__spec::before {
  content: "·";
  margin-right: var(--space-1);
  color: var(--border-strong);
}

.real-estate-results__pagination {
  margin-top: var(--space-10); /* 40px */
}


/* ==================================================
   10. Bottom Utility
   목록 → Footer 로 넘어가기 전 부동산 이용 안내 / 매물 등록 진입.
   메인의 .main-utility(공지 + 고객센터)를 복제하지 않는다.
   Section 성격이 다르고, 복제하면 메인 Section CSS와 결합되기 때문이다.
================================================== */

.real-estate-utility {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-6);
  margin-top: var(--space-10);
  padding: var(--space-6) var(--space-8);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  background-color: var(--bg-subtle);
}

.real-estate-utility__title {
  color: var(--text-primary);
  font-size: var(--font-size-lg); /* 18px */
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-snug);
}

.real-estate-utility__description {
  margin-top: var(--space-1);
  color: var(--text-secondary);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-normal);
}

.real-estate-utility__links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
  margin-top: var(--space-3);
}

.real-estate-utility__link {
  color: var(--text-link);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-normal);
}

.real-estate-utility__link:hover {
  color: var(--brand-interaction);
  text-decoration: underline;
}

.real-estate-utility__link:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.real-estate-utility__cta {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  height: 48px;
  padding: 0 var(--space-6);
  border-radius: var(--radius-md);
  background-color: var(--brand-secondary);
  color: var(--text-inverse);
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-normal);
  white-space: nowrap;
  transition: background-color var(--transition-fast);
}

.real-estate-utility__cta:hover {
  background-color: var(--brand-interaction);
  color: var(--text-inverse);
}

.real-estate-utility__cta:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 3px;
}
