:root {
    /* ---- Enjoysky 2026 리디자인: 딥네이비 + 브라스골드 (프리미엄 항공 라운지) ----
       기존 컴포넌트들은 전부 아래 시맨틱 토큰(accent, surface, border 등)만
       참조하므로, 이 블록만 바꿔도 헤더, 검색바, 표, 버튼 전체가 새 팔레트로
       재도색된다. navy, gold, teal, font 계열 신규 토큰은 이번 리디자인 때
       추가된 것들로, 보딩패스 카드 등 새 컴포넌트 전용. ---- */
    --navy-900: #0b1526;
    --navy-800: #14213d;
    --navy-700: #1e2f52;
    --navy-600: #2c4374;

    --gold: #c9a227;
    --gold-deep: #9c7a17;
    --gold-soft: #f2e6be;

    --teal: #0e6e5b;
    --teal-soft: #dfeee9;
    --teal-text: #0a5040;

    --ink: #1b1f2a;
    --muted: #5b6472;
    --faint: #8b93a1;

    --paper: #fafaf8;
    --surface: #ffffff;
    --surface-muted: #f3f1ea;
    --border: rgba(20, 33, 61, 0.11);
    --border-strong: rgba(20, 33, 61, 0.22);

    --bg: var(--paper);
    --text: var(--ink);
    --text-muted: var(--muted);
    --text-faint: var(--faint);

    --accent: var(--navy-800);
    --accent-dark: var(--navy-900);
    --accent-soft: rgba(20, 33, 61, 0.06);
    --accent-text: #fdfbf6;

    --badge-bg: var(--surface-muted);
    --badge-text: var(--navy-800);

    --warn-bg: #faf0d9;
    --warn-text: #7a5310;
    --warn-border: #e9d29e;
    --danger-bg: #f8e4e1;
    --danger-text: #9a2e23;
    --danger-border: #efc3bc;

    --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
    --shadow-md: 0 10px 26px rgba(15, 23, 42, 0.09);
    --shadow-lift: 0 20px 44px rgba(15, 23, 42, 0.14);

    --radius-sm: 6px;
    --radius-md: 12px;
    --radius-pill: 999px;

    --font-display: "Fraunces", "Noto Serif KR", Georgia, serif;
    /* 2026-08-30 (사용자 요청: 가이드 페이지에 적용해본 Pretendard가 "생각보다
       괜찮다"며 사이트 전체로 확대 -- app/templates/base.html에서 jsDelivr로
       로드) -- Gothic A1은 그대로 폴백 체인에 남겨둠(Pretendard CDN 장애 시
       성능 저하 안전망, 기존 Google Fonts 폴백 원칙과 동일). 브랜드
       워드마크/큰 헤드라인용 --font-display(Fraunces)는 이번 변경 대상이
       아님 -- 의도된 별도 디자인 요소라 그대로 둠. */
    --font-sans: "Pretendard", "Gothic A1", -apple-system, "Segoe UI", "Malgun Gothic", sans-serif;
    /* 한글이 섞여 들어와도(예: 표 헤더) 글자 단위로 자동 폴백되도록 Pretendard를
       체인 중간에 둠 -- IBM Plex Mono엔 한글 글리프가 없어 그 문자만 자동으로
       다음 폰트로 넘어감 (영문/숫자만 실제로 모노스페이스로 렌더링됨). */
    --font-mono: "IBM Plex Mono", "Pretendard", "Gothic A1", "SFMono-Regular", Consolas, monospace;

    /* 네이비 헤더 위에 얹히는 텍스트 공통 색 -- 브랜드 워드마크뿐 아니라
       다른 페이지들의 일반 페이지 제목(h1)에도 그대로 씀. */
    --on-navy: #f5f2e9;
    --on-navy-muted: rgba(245, 242, 233, 0.72);
}

* { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%;
}

/* 2026-08-29 (ui-ux-pro-max + frontend-design 스킬 점검): 카드 hover
   lift(translateY) 트랜지션이 여러 컴포넌트에 있는데 prefers-reduced-motion
   대응이 전혀 없었음 -- 모션에 민감한 사용자를 위해 전역으로 대폭 단축.
   !important라 선택자 명시도/작성 순서와 무관하게 항상 이김. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* 2026-08-29 (같은 점검): 버튼/링크류가 키보드 포커스 시 브라우저 기본
   파란 아웃라인을 그대로 썼음(브랜드 색과 안 맞음, 지워버린 것도 아니라
   버그는 아니지만 신경 안 쓴 티가 남) -- 이 사이트 톤에 맞는 골드 링으로
   통일. 입력 필드는 이미 자체 포커스 스타일(box-shadow 링)이 있어서 제외. */
a:focus-visible,
button:focus-visible,
.btn-book:focus-visible,
.btn-book-outline:focus-visible,
.suggest-item:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 2px;
}

body {
    margin: 0;
    background: var(--paper);
    color: var(--text);
    font-family: var(--font-sans);
    font-size: 14px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.page {
    max-width: 1180px;
    width: 100%;
    margin: 0 auto;
    padding: 22px 20px 0;
    flex: 1 0 auto;
    display: flex;
    flex-direction: column;
}

.page-content {
    flex: 1 0 auto;
}

/* ---------- Header (2026-08-25 리디자인: 프리미엄 항공 라운지 카운터 패널) ----------
   딥네이비 카드 + 하단 골드 심(seam) -- 아래 보딩패스 티켓 카드의 절취선과
   같은 조형 언어를 헤더에서 먼저 예고해두는 구조. */

.site-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    margin-bottom: 22px;
    padding: 18px 26px;
    background: linear-gradient(155deg, var(--navy-700) 0%, var(--navy-900) 100%);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    position: relative;
    overflow: hidden;
}

.site-header::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--gold) 15%, var(--gold) 85%, transparent);
    opacity: 0.9;
}

.site-header h1 {
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.01em;
    margin: 0;
    color: var(--on-navy);
    /* 2026-08-30 (user report): pages whose <h1> is just
       {% include site_logomark %} + plain text (booking_compare.html,
       fare_detail.html, fare_graph.html, search_form.html,
       search_result.html, admin_login.html -- every "새 창"/interstitial
       page) had the logo sitting visibly lower than the text next to it.
       Cause: .site-logomark below has `vertical-align: -9px` to nudge it
       against a PLAIN inline text baseline -- but index.html/guide.html/etc
       wrap the same logo+text in `.site-title`, which is already
       display:inline-flex + align-items:center (vertical-align is a no-op
       on a flex item), so that offset only ever actually applied on the
       bare-<h1> pages, where nothing was correcting for it. Making the <h1>
       itself a flex row centers the logo against a run of plain text OR an
       .site-title flex box identically, so the same rule stops depending on
       which of the two markup shapes a given page happens to use. */
    display: flex;
    align-items: center;
}

.site-logomark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    margin-right: 10px;
    border: 1.5px solid var(--gold);
    border-radius: 50%;
    color: var(--gold);
    flex-shrink: 0;
}

.site-title {
    font-family: var(--font-display);
    font-weight: 500;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    color: var(--on-navy);
    transition: opacity 0.15s ease;
}

.site-title .brand-accent {
    color: var(--gold);
}

.site-title:hover {
    opacity: 0.85;
}

/* 2026-08-20 (user request): GUIDE(왼쪽)/LOGIN·LOGOUT(항상 맨 끝) 내비게이션 --
   .site-header가 이미 justify-content:space-between이라 이 nav는 자연히
   오른쪽 끝에 붙고, 그 안에서 LOGIN/LOGOUT이 마지막 항목이라 늘 가장
   오른쪽에 위치함. 2026-08-25: 게이트 안내판 느낌의 모노스페이스 대문자로. */
.site-nav {
    display: flex;
    align-items: center;
    gap: 24px;
}

.site-nav a,
.site-nav button {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.09em;
    color: var(--on-navy-muted);
    text-decoration: none;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    transition: color 0.15s ease;
}

.site-nav a:hover,
.site-nav button:hover {
    color: var(--gold);
    text-decoration: none;
}

.site-nav-form {
    display: inline;
}

/* 관리자에게만 보이는 새로고침 상태 배지 줄 -- 헤더 바로 아래, 독립된 줄. */
.admin-status-row {
    margin-bottom: 20px;
}

.refresh-status {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* ---------- Badges & status pills ---------- */

.status-badge {
    background: var(--surface-muted);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    padding: 6px 12px;
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.4;
}

.refresh-badge {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.refresh-btn {
    background: var(--surface);
    border: 1px solid var(--border-strong);
    color: var(--text);
    border-radius: var(--radius-pill);
    padding: 7px 14px;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}

.refresh-btn:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-sm);
}

.refresh-btn:active {
    transform: translateY(1px);
}

.refresh-btn.htmx-request,
.refresh-btn:disabled {
    opacity: 0.55;
    cursor: progress;
}

.status-badge-warn {
    background: var(--warn-bg);
    color: var(--warn-text);
    border-color: var(--warn-border);
    cursor: help;
}

.status-badge-danger {
    background: var(--danger-bg);
    color: var(--danger-text);
    border-color: var(--danger-border);
    cursor: help;
    font-weight: 600;
}

/* ---------- "지금 가장 싼 항공권" strip (2026-08-25: 미니 보딩패스 스텁) ---------- */

.top-fares {
    margin-bottom: 22px;
}

.top-fares-title {
    /* 2026-08-29 (사용자 지적): 아래 홈 섹션(근거리/장거리/추천 휴양지)의
       .home-section-title와 폰트/크기가 달라 보였음 -- 둘 다 같은 위계의 홈
       화면 섹션 제목이라 값을 그대로 맞춤.
       2026-08-30 (사용자 요청): 한글 제목이라 --font-display(Fraunces, 라틴
       전용)는 어차피 Noto Serif KR로 폴백되고 있었는데, 그 세리프체가 나머지
       Pretendard 본문과 안 어울려 보여서 Pretendard로 직접 교체. */
    font-family: "Pretendard", var(--font-sans);
    font-size: 21px;
    font-weight: 600;
    letter-spacing: -0.005em;
    margin: 0 0 14px;
    color: var(--navy-800);
}

/* 2026-08-29 (사용자 요청): 좌우로 스크롤하는 카드 스트립 대신, 이벤트
   배너처럼 한 번에 하나씩 자동으로 슬라이드되는 캐러셀로 교체
   (base.html의 스크립트가 자동재생/도트/화살표를 담당). */
/* 2026-08-29 (사용자 요청, 재작업): 테두리/그림자/"최저가" 리본을 슬라이드가
   아니라 이 바깥 프레임에 둠 -- 처음엔 슬라이드 자체에 금테두리+비행기 아이콘
   노치를 얹었었는데, overflow-x:hidden인 안쪽 뷰포트 때문에 아이콘이 잘리는
   버그가 있었음(CSS 스펙상 overflow-x/overflow-y 중 하나만 visible로 두면
   브라우저가 그 값을 auto로 강제 변환해버려서, "세로는 안 잘리게" 의도가
   실제로는 안 먹힘 -- 라이브에서 아이콘이 점처럼 잘려 보인다는 사용자 리포트로
   확인). 프레임(이 요소)은 애초에 가로 클리핑이 없으니 리본이 왼쪽으로 살짝
   삐져나와도 안전. */
.fare-carousel {
    position: relative;
    border: 2px solid var(--gold);
    border-radius: var(--radius-md);
    background: var(--surface);
    box-shadow: var(--shadow-md), 0 0 22px rgba(201, 162, 39, 0.22);
}

.fare-carousel-viewport {
    overflow: hidden;
    border-radius: calc(var(--radius-md) - 2px);
    /* 2026-08-30 (스와이프 네비게이션 추가): touch-action:pan-y로 세로
       페이지 스크롤은 브라우저가 그대로 처리하게 두고, 가로 방향만 base.html의
       포인터 이벤트 핸들러가 가로채서 슬라이드를 넘김 -- 이게 없으면 모바일에서
       가로로 스와이프할 때 브라우저가 먼저 페이지를 확대/스크롤하려 들어서
       손맛이 뻑뻑해짐. */
    touch-action: pan-y;
    cursor: grab;
}

.fare-carousel-viewport:active {
    cursor: grabbing;
}

/* "최저가" 리본 -- 눈에 확 띄게 해달라는 요청. 처음엔 카드 왼쪽 위 모서리
   안쪽(출발지 텍스트와 같은 줄)에 얹었더니 출발지 글자를 가려버려서(사용자
   리포트), 콘텐츠 영역이 아니라 금테두리 선 위에 걸치도록 위로 옮김 --
   .filters::before(검색창 비행기 아이콘)와 같은 "테두리 위에 얹힌 태그"
   자리를 공유, 텍스트와는 절대 안 겹침. */
.fare-carousel::before {
    content: '최저가';
    position: absolute;
    top: -11px;
    left: 22px;
    background: var(--gold);
    color: var(--navy-900);
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    padding: 4px 12px;
    border-radius: var(--radius-sm);
    box-shadow: 0 3px 8px rgba(20, 33, 61, 0.25);
    z-index: 1;
}

.fare-carousel-track {
    display: flex;
    transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
    will-change: transform;
}

.fare-carousel-slide {
    flex: 0 0 100%;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    background: transparent;
    padding: 20px 26px 18px;
    text-decoration: none;
    color: var(--text);
}

.fare-slide-main {
    min-width: 0;
}

.fare-slide-route {
    font-family: var(--font-mono);
    font-size: 15px;
    font-weight: 600;
    color: var(--navy-800);
    margin-bottom: 8px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    letter-spacing: 0.01em;
}

.fare-slide-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    font-size: 12px;
    color: var(--text-muted);
}

.fare-slide-airline {
    margin-left: 2px;
}

.fare-slide-price {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: 26px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    letter-spacing: -0.01em;
    text-align: right;
    white-space: nowrap;
}

.fare-slide-price .subtext {
    display: block;
    font-size: 11px;
    font-weight: 500;
    color: var(--text-muted);
    margin-top: 4px;
}

.fare-carousel-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--navy-800);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    box-shadow: var(--shadow-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease, box-shadow 0.15s ease;
}

.fare-carousel-arrow:hover {
    background: var(--surface-muted);
    box-shadow: var(--shadow-md);
}

.fare-carousel-prev { left: -14px; }
.fare-carousel-next { right: -14px; }

/* 2026-08-29 (사용자 지적: "배경이 꽉차게 안 들어가있다"): 원래 점(dots)이
   뷰포트 아래 별도 줄에 있어서, 그 줄 높이만큼 프레임 안에 사진이 안 덮인
   흰 여백이 남았음 -- 사진이 프레임 전체를 채우도록 점을 사진 위에 얹는
   오버레이로 바꿈.
   2026-08-30 (사용자 지적: "반투명 회색 알약이 거슬린다, 그냥 투명하게"):
   컨테이너 배경/blur를 완전히 제거 -- 점 자체는 밑에서 각 점에 건
   drop-shadow로 밝은 사진 위에서도 계속 잘 보임(알약 없이도 대비 유지). */
.fare-carousel-dots {
    position: absolute;
    left: 50%;
    bottom: 10px;
    transform: translateX(-50%);
    display: flex;
    justify-content: center;
    gap: 2px;
}

/* 24x24 실제 탭 영역(WCAG 웹 터치타겟 최소 24px) 안에 8px짜리 작은 점만
   시각적으로 보여주는 패턴 -- 2026-08-29 요일칩 터치타겟 점검과 같은 원칙. */
.fare-carousel-dot {
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
}

.fare-carousel-dot::after {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.85);
    /* 뒤에 알약 배경이 없어졌으니, 밝은 하늘/건물 사진 위에서도 점이
       묻히지 않도록 각 점에 직접 어두운 그림자를 줌. */
    filter: drop-shadow(0 0 2px rgba(11, 21, 38, 0.9));
    transition: background 0.15s ease, transform 0.15s ease;
}

.fare-carousel-dot.is-active::after {
    background: var(--gold);
    transform: scale(1.3);
}

@media (max-width: 640px) {
    .fare-carousel-arrow {
        display: none;
    }

    .fare-carousel-slide {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
    }

    .fare-slide-price {
        text-align: left;
    }
}

/* ---------- Filter form ---------- */

.filters {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-top: 3px solid var(--gold);
    border-radius: var(--radius-md);
    padding: 22px 22px 18px;
    margin-bottom: 22px;
    box-shadow: var(--shadow-md);
}

.filters::before {
    content: '✈';
    position: absolute;
    top: -11px;
    left: 26px;
    background: var(--paper);
    color: var(--gold-deep);
    padding: 0 8px;
    font-size: 13px;
    line-height: 1;
}

.trip-type-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
}

.trip-type-tabs {
    display: flex;
    gap: 22px;
}

.trip-type-tab {
    position: relative;
    padding-bottom: 8px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-faint);
    cursor: pointer;
}

.trip-type-tab input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.trip-type-tab input:checked + span {
    color: var(--text);
}

.trip-type-tab input:checked ~ * {
    color: var(--text);
}

.trip-type-tab:has(input:checked)::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: var(--text);
}

.connecting-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
    /* 2026-08-30 (user report: 체크칸+"경유 포함" 텍스트가 왕복/편도 탭보다
       살짝 아래로 보임) -- .trip-type-tab은 활성 탭 밑줄(::after, bottom:0)
       공간을 reserve하려고 padding-bottom:8px를 갖고 있어서, 같은 줄에서
       align-items:center로 정렬될 때 그 여백만큼 tab 텍스트가 상대적으로
       위로 쏠려 보였음(.connecting-toggle엔 그 여백이 없었으므로). 같은
       padding-bottom을 줘서 두 요소의 "내용+여백" 모양을 맞춤 -- 실측으로
       두 텍스트의 세로 중심이 정확히 같아지는 것까지 확인. */
    padding-bottom: 8px;
}

.trip-type-tab span {
    line-height: 1;
}

/* 2026-08-30 (사용자가 여러 번 재확인해도 여전히 안 맞는다고 보고): 위
   padding-bottom 정렬은 Chromium 실측(centerY 0.5px 이내)으로는 이미
   맞아떨어지지만, 네이티브 <input type="checkbox">는 브라우저/OS마다
   자체 위젯을 그려서 실제 체크 표시가 요소의 박스 안 어디에 그려지는지가
   렌더러마다 조금씩 다를 수 있음(이 프로젝트 검증 환경인 Chromium
   기준으로는 안 보이는 차이). 그 불확실성 자체를 없애기 위해 네이티브
   체크박스 외형을 완전히 꺼버리고 크기·위치를 우리가 직접 그리는 방식으로
   교체 -- 어느 브라우저에서 봐도 항상 동일한 16x16 박스로 렌더링됨. */
.connecting-toggle input {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    flex: none;
    width: 16px;
    height: 16px;
    border: 1.5px solid var(--text-faint);
    border-radius: 4px;
    position: relative;
    cursor: pointer;
    background: var(--surface);
}

.connecting-toggle input:checked {
    background: var(--accent);
    border-color: var(--accent);
}

.connecting-toggle input:checked::after {
    content: "";
    position: absolute;
    left: 4.5px;
    top: 1.5px;
    width: 4px;
    height: 8px;
    border: solid var(--accent-text);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

.connecting-toggle input:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 2px;
}

.filters-primary {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 10px;
}

/* 2026-08-20 (user request: "한 줄로 만들 수 있을까"): every primary field
   shrunk down as far as still legible so route/date/duration/weekday/submit
   all fit on ONE line at ordinary desktop widths instead of the previous
   2-line layout (weekday+submit used to wrap to their own line because row 1
   alone was already ~890px in a ~1040px-wide card). flex-wrap on
   .filters-primary is untouched, so this still degrades gracefully to
   multiple lines on narrow/mobile viewports -- it's not a hard one-line
   requirement, just tight enough to make one line the common case. */
.filters-primary .field label,
.filters-primary .field-weekday label {
    font-size: 11px;
}

/* 2026-08-20 (user request: 필드마다 네모 박스로 나뉘어있던 걸 참고 디자인처럼
   구분선만 있는 깔끔한 한 줄 형태로) -- .field-group의 기본 박스(테두리+배경,
   위 "Connected field groups" 규칙)를 primary 검색바 안에서만 지우고, 대신
   필드 사이에 얇은 세로 구분선만 둠. 상세검색(advanced-grid)의 가격범위
   .field-group 등 다른 곳은 기존 박스 스타일 그대로 유지(이 선택자들은
   .filters-primary 안에서만 적용됨). */
.filters-primary .field-group {
    border: none;
    background: none;
    box-shadow: none;
    border-radius: 0;
    padding-right: 18px;
    margin-right: 4px;
    border-right: 1px solid var(--border);
    /* 2026-08-20 bugfix (user report: 출발지/도착지가 너무 붙어있음) -- 화살표
       아이콘을 없앤 뒤로 그 자리가 주던 간격도 같이 사라져서 둘이 거의
       붙어보였음. */
    gap: 20px;
}

.filters-primary .field-group:hover,
.filters-primary .field-group:focus-within {
    border: none;
    border-right: 1px solid var(--border);
    box-shadow: none;
}

.filters-primary .field-group .field {
    padding: 0;
}

.filters-primary .field-group .field input,
.filters-primary .field-group .field select {
    font-size: 13.5px;
    min-width: 90px;
}

.filters-primary .route-group .field select {
    min-width: 58px;
}

.filters-primary .route-group .suggest-field input {
    min-width: 110px;
}

/* 2026-08-20 (user request): 참고 디자인처럼 필드마다 네모 박스로 나누는 대신
   얇은 세로 구분선만 두는 깔끔한 한 줄 형태로 교체 -- 이전엔 여기(날짜/여행
   기간/포함요일)와 위 route-group이 전부 개별 테두리 박스였음. */
.filters-primary > .field:not(.field-submit) {
    border: none;
    background: none;
    border-radius: 0;
    padding: 0 18px 0 0;
    margin-right: 4px;
    border-right: 1px solid var(--border);
}

/* 2026-08-20 bugfix (user report: "일" 위에 마우스를 올리면 오른쪽에 선이
   생겼다가 한참 있다 없어짐) -- 이 hover 규칙이 :not(.field-weekday) 없이
   ":hover" 하나만 더 붙은 채였는데, 가상클래스도 명시도에 들어가서
   (0,4,0)이 되어 바로 아래 field-weekday 전용 "구분선 없음" 규칙(0,3,0)을
   가볍게 이겨버렸음 -- 포함요일(지금 "선호 요일") 칸 위에 마우스가 있는
   동안(칩들 사이를 오가는 것도 전부 포함) 내내 구분선이 도로 나타났다가,
   마우스가 필드 전체를 완전히 벗어나야 사라졌던 것. 아예 이 선택자에서
   field-weekday를 제외해서 그런 상태 자체가 생기지 않게 함. */
.filters-primary > .field:not(.field-submit):not(.field-weekday):hover,
.filters-primary > .field:not(.field-submit):not(.field-weekday):focus-within {
    border-right: 1px solid var(--border);
    box-shadow: none;
}

/* 선호 요일은 검색바의 마지막 필드라 뒤에 구분선 없이 버튼과의 여백만 둠
   (버튼은 margin-left:auto로 오른쪽 끝에 붙어서 이미 시각적으로 분리됨). */
.filters-primary > .field-weekday:not(.field-submit) {
    border-right: none;
    padding-right: 0;
    margin-right: 0;
}

.filters-primary > .field:not(.field-submit) input {
    border: none;
    padding: 0;
    background: transparent;
    font-size: 13.5px;
    min-width: 80px;
}

/* 2026-08-20: used to flex-grow to soak up row 1's leftover space (back when
   weekday+submit were expected to wrap to row 2) -- now everything targets
   one line, so it just sizes to its own content like every other field
   instead of stretching and pushing later fields into a second line. */
.filters-primary .field-duration {
    flex: 0 0 auto;
}

.filters-primary .field-duration input {
    width: 64px;
}

/* margin-left:auto anchors the button to the right edge of whichever line
   it ends up on -- the common case is now line 1 (everything fits), but this
   still looks right if a narrow viewport wraps it down alone. */
.filters-primary .field-submit {
    margin-left: auto;
}

/* 2026-08-20 bugfix (user report: 선호 요일 라벨 높이가 출발일/여행기간과 안
   맞음) -- 요일 칩(24px)이 옆 입력창(18px)보다 커서, 아래쪽이 맞춰지는
   align-items:flex-end 때문에 위쪽 라벨이 그만큼 더 위로 밀려 보였음. 입력창과
   같은 18px로 맞춤. */
.filters-primary .chip-toggle span {
    font-size: 12px;
    height: 18px;
}

.filters-primary .field-submit button {
    padding: 9px 18px;
    font-size: 13.5px;
}

/* ---------- Advanced search (collapsed by default) ---------- */

.advanced-search {
    border-top: 1px dashed var(--border);
    padding-top: 14px;
}

.advanced-search summary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    list-style: none;
    cursor: pointer;
    color: var(--text-muted);
    font-size: 13px;
    font-weight: 700;
    user-select: none;
    transition: color 0.15s ease;
}

.advanced-search summary::-webkit-details-marker {
    display: none;
}

.advanced-search summary:hover {
    color: var(--accent-dark);
}

.advanced-search summary .chevron {
    transition: transform 0.15s ease;
}

.advanced-search[open] summary .chevron {
    transform: rotate(180deg);
}

/* 2026-08-18: CSS Grid instead of flex-wrap -- with 5 fields (구분/항공사/
   여행사/가격범위/정렬) at a shared fixed width, they fill this card's
   ~1040px content width edge-to-edge every time instead of wrapping
   wherever content happens to run out, and the price-range field (a single
   grid item holding two inputs) gets a wider track.
   2026-08-20 bugfix (user report: "정렬은 너무 길고 최소가/최대가는 너무
   짧다"): this used to list 6 track widths ("1fr 1fr 1fr 1fr 1.6fr 1fr")
   for only 5 actual grid items -- auto-placement filled tracks 1-5 in
   order, so the wide 1.6fr track landed on 정렬 (5th item) instead of the
   가격범위 field-group (4th item) it was meant for, leaving an unused 6th
   track's worth of width to redistribute and price-range starved to a
   plain 1fr for two inputs. Now exactly 5 tracks, wide one on the 4th. */
.advanced-grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1.6fr 1fr;
    align-items: end;
    gap: 14px;
    margin-top: 14px;
}

.advanced-grid .field:not(.field-group) input,
.advanced-grid .field:not(.field-group) select {
    width: 100%;
    min-width: 0;
}

.advanced-grid .field-group .field {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    /* 2026-08-20 bugfix (user report: 최소가/최대가가 구분·항공사·여행사·정렬과
       높이가 안 맞음) -- 최소가/최대가는 여전히 옛 박스형 .field-group .field의
       8px 위아래 패딩(그 스타일을 지금은 다 없앤 다른 필드들엔 없음)을 물려받고
       있어서, 그룹 전체 높이가 달라져 세로 정렬이 어긋났었음. */
    padding: 0;
}

/* 위아래 패딩만 지우면 "~" 연결자가 값에 바짝 붙어버려서, 좌우 여백은
   양쪽 끝(첫/마지막 필드)에만 남겨서 "최소가" 라벨은 다른 필드들과 왼쪽이
   맞으면서도 "~" 앞뒤로는 여백이 생기게 함. */
.advanced-grid .field-group .field:first-child {
    padding-right: 8px;
}

.advanced-grid .field-group .field:last-child {
    padding-left: 8px;
}

/* 2026-08-20 (user request: 상세검색도 검색바처럼 박스 대신 구분선 느낌으로) --
   가격범위(최소가~최대가)의 박스 테두리를 지우고, 나머지 필드처럼 그리드
   칸 사이 구분선만 남김. "~" 텍스트가 이미 최소/최대 사이 구분자 역할을 하고
   있어서 그 안에 별도 구분선은 안 넣음. */
.advanced-grid .field-group {
    border: none;
    background: none;
    box-shadow: none;
    border-radius: 0;
}

.advanced-grid .field-group:hover,
.advanced-grid .field-group:focus-within {
    border: none;
    box-shadow: none;
}

/* 2026-08-20 bugfix (user report: "구분선이 구분 쪽에 바짝 붙어있어") -- the
   border sits right at the grid item's own edge, so with no padding of its
   own it landed flush against e.g. 구분 with the entire 14px gap on the
   OTHER side before 항공사 -- padding-right matching the grid's own gap
   puts the line at the midpoint between the two fields' text instead. */
.advanced-grid > *:not(:last-child) {
    padding-right: 14px;
    border-right: 1px solid var(--border);
}

@media (max-width: 900px) {
    .advanced-grid {
        grid-template-columns: 1fr 1fr 1fr;
    }

    .advanced-grid .field-group {
        grid-column: span 3;
    }

    /* 3열로 줄바꿈되면 "구분 위 아래 divider" 개념 자체가 깨짐(다음 줄로
       넘어간 필드까지 세로선이 뻗어 보이는 버그) -- 이 폭에서는 구분선을
       전부 없애고 줄바꿈 간격만으로 구분함. */
    .advanced-grid > *:not(:last-child) {
        border-right: none;
    }
}

.advanced-grid .field input,
.advanced-grid .field select {
    height: 34px;
}

.field {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.field label {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.field input, .field select, .field textarea {
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 8px 10px;
    font-family: inherit;
    font-size: 13px;
    min-width: 110px;
    background: var(--surface);
    color: var(--text);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.field input:hover, .field select:hover, .field textarea:hover {
    border-color: var(--text-faint);
}

.field input:focus, .field select:focus, .field textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ---------- Connected field groups (route / range pairs) ---------- */
/* Reads as one control (like a real booking site's "from -> to" or
   min~max range widget) instead of two unrelated boxes sitting side by
   side -- the group owns the border, the inputs inside go borderless. */

.field-group {
    display: flex;
    align-items: stretch;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--surface);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.field-group:hover {
    border-color: var(--text-faint);
}

.field-group:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.field-group .field {
    gap: 5px;
    padding: 8px 10px;
    position: relative;
}

.field-group .field input,
.field-group .field select {
    border: none;
    padding: 0;
    min-width: 92px;
    background: transparent;
}

.field-group .field input:focus,
.field-group .field select:focus {
    box-shadow: none;
}

.field-group.route-group .field select {
    min-width: 72px;
}

.field-group.route-group .suggest-field input {
    min-width: 120px;
}

.group-connector {
    display: flex;
    align-items: center;
    align-self: flex-end;
    padding-bottom: 8px;
    color: var(--text-faint);
    font-size: 13px;
    font-weight: 500;
}

.suggest-field {
    position: relative;
}

/* 2026-08-19 (user request): absolutely positioned (not in normal flow) so
   showing/hiding this never shifts any other search field's position.
   Floats ABOVE the input, not below -- .suggest-list (the autocomplete
   dropdown) already occupies top:100% of this same .suggest-field parent,
   and stacking a second absolutely-positioned element in that same spot
   made the warning cover the suggestion list whenever both could show
   (live user report: "연관검색어가 안보여"). Above the field has no such
   collision. .suggest-field (its parent) already has position:relative. */
.field-warning {
    display: none;
    position: absolute;
    bottom: 100%;
    left: 0;
    z-index: 20;
    margin-bottom: 4px;
    padding: 6px 10px;
    max-width: 260px;
    background: var(--danger-bg);
    border: 1px solid var(--danger-border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-sm);
    color: var(--danger-text);
    font-size: 12px;
    line-height: 1.4;
}

.field-warning:not(:empty) {
    display: block;
}

.field-checkbox {
    justify-content: flex-end;
}

.checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 8px 12px;
    font-size: 13px;
    color: var(--text);
    background: var(--surface);
    white-space: nowrap;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.checkbox-label:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.checkbox-label input[type="checkbox"] {
    width: 15px;
    height: 15px;
    margin: 0;
    accent-color: var(--accent);
    cursor: pointer;
}

/* 2026-08-20 (user request: 요일 선택도 지금 검색바에서 쓰는 "박스 대신 깔끔한"
   스타일로) -- 채워진 사각 배지 대신 밑줄로 선택 상태를 표시하는 방식으로
   교체(왕복/편도 탭의 밑줄 표시와 같은 언어). .chip-toggle/.chip-group은
   요일 선택 하나에만 쓰이므로(다른 용도 없음, grep으로 확인) 범위 제한 없이
   그대로 바꿔도 안전함. */
.chip-group {
    display: flex;
    gap: 10px;
    flex-wrap: nowrap;
}

.chip-toggle {
    position: relative;
    display: inline-flex;
    cursor: pointer;
}

.chip-toggle input[type="checkbox"] {
    position: absolute;
    /* 2026-08-29 (ui-ux-pro-max 점검): 원래 inset:0이라 실제 탭 영역이 보이는
       글자 상자(.filters-primary에서는 18px 높이, ~16-20px 너비)와 똑같이
       작았음 -- 이 글자 크기 자체는 "선호 요일" 필드가 옆 입력창들과 높이를
       맞추기 위해(위 2026-08-20 정렬 버그 수정 참고) 일부러 작게 유지해야
       해서, 시각적 크기는 그대로 두고 탭 영역만 음수 inset으로 부모 박스
       바깥까지 넓힘(24x24 안팎, 웹 WCAG 최소 터치타겟) -- .chip-group의
       10px gap과 겹치지 않게 여유를 남김. absolute라 레이아웃 높이에는
       영향 없음(부모 .chip-toggle의 flex 정렬은 그대로 유지됨). */
    inset: -3px -4px;
    /* Overrides the generic `.field input { min-width: 110px }` rule --
       without this the invisible checkbox's real hit-area stayed 110px wide
       regardless of inset, silently overlapping/blocking whatever sat next
       to a narrow chip (only became visible as a real click-blocking bug once
       chips wrapped close to the search button on narrower viewports). */
    width: auto;
    min-width: 0;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.chip-toggle span {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 24px;
    padding: 0 1px;
    border: none;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--text-muted);
    font-size: 13px;
    font-weight: 600;
    line-height: 1;
    user-select: none;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.chip-toggle.is-saturday span {
    color: var(--accent-dark);
}

.chip-toggle.is-sunday span {
    color: var(--danger-text);
}

.chip-toggle:hover span {
    border-bottom-color: var(--border-strong);
}

/* 배경을 채우는 대신 글자를 굵게+밑줄로 -- 밑줄 색은 currentColor라 평일/토/일
   각자의 색(기본/파란색/빨간색)을 선택 상태에서도 그대로 유지함. */
.chip-toggle input:checked + span {
    font-weight: 800;
    border-bottom-color: currentColor;
}

.chip-toggle input:focus-visible + span {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.suggest-list {
    list-style: none;
    margin: 4px 0 0;
    padding: 6px;
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 20;
    min-width: 200px;
    max-width: 280px;
    max-height: 240px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lift);
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.suggest-list:empty {
    border: none;
    box-shadow: none;
    margin-top: 0;
    padding: 0;
}

/* 2026-08-19 (user request): single calendar popup replacing the two
   separate 출발일(부터)/출발일(까지) <input type="date"> fields -- see
   partials/filters.html for the picking logic. .daterange-field needs
   position:relative the same way .suggest-field does, for the popup below. */
.daterange-field {
    position: relative;
}

.daterange-display {
    cursor: pointer;
    /* 2026-08-20 bugfix (user report: 날짜 범위 선택 시 뒤가 짤림) -- "YYYY-MM-DD
       ~ YYYY-MM-DD" 형태(23자)가 148px에는 다 안 들어갔음. */
    width: 190px;
}

.daterange-popup {
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 4px;
    z-index: 25;
    width: 280px;
    padding: 12px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lift);
}

.daterange-popup-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}

.daterange-month-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
}

/* 2026-08-19 bugfix (live user report: "달력이 깨져있어"): `.filters button`
   (a class+type selector, specificity (0,1,1)) was winning over these plain
   class selectors (0,1,0) and painting every nav/day/footer button with its
   solid-accent submit-button styling (padding, inline-flex+gap, etc.) --
   the exact same specificity bug this project already hit once with
   .suggest-item (see that rule's comment below). Scoping every one of these
   under `.filters` too (0,2,0) is what actually wins this time. */
.filters .daterange-nav {
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    width: 26px;
    height: 26px;
    padding: 0;
    line-height: 1;
    font-size: 15px;
    color: var(--text);
    cursor: pointer;
    box-shadow: none;
}

.filters .daterange-nav:hover {
    border-color: var(--accent);
    color: var(--accent);
    background: none;
    box-shadow: none;
}

.daterange-weekdays,
.daterange-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}

.daterange-weekdays {
    margin-bottom: 4px;
}

.daterange-weekdays span {
    text-align: center;
    font-size: 11px;
    color: var(--text-muted);
    padding-bottom: 4px;
}

.daterange-weekdays .is-saturday {
    color: var(--accent-dark);
}

.daterange-weekdays .is-sunday {
    color: var(--danger-text);
}

.filters .daterange-day {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    border: none;
    background: none;
    border-radius: var(--radius-sm);
    padding: 0;
    font-size: 13px;
    font-weight: 400;
    color: var(--text);
    cursor: pointer;
    box-shadow: none;
}

.filters .daterange-day:hover:not(:disabled) {
    background: var(--accent-soft);
}

.filters .daterange-day:disabled {
    color: var(--text-faint);
    cursor: not-allowed;
}

.filters .daterange-day.is-today {
    font-weight: 700;
    color: var(--accent-dark);
}

.filters .daterange-day.is-in-range {
    background: var(--accent-soft);
    border-radius: 0;
}

.filters .daterange-day.is-start,
.filters .daterange-day.is-end {
    background: var(--accent);
    color: var(--accent-text);
    font-weight: 600;
}

.daterange-hint {
    margin: 8px 0 0;
    font-size: 11px;
    color: var(--text-muted);
    line-height: 1.4;
}

.daterange-popup-footer {
    display: flex;
    justify-content: space-between;
    margin-top: 10px;
}

.filters .daterange-popup-footer button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0;
    font-size: 12px;
    font-weight: 600;
    padding: 6px 12px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    box-shadow: none;
}

.filters .daterange-clear {
    background: none;
    border: 1px solid var(--border);
    color: var(--text-muted);
}

.filters .daterange-clear:hover {
    background: var(--surface-muted);
    border-color: var(--text-faint);
}

.filters .daterange-done {
    background: var(--accent);
    border: none;
    color: var(--accent-text);
}

.filters .daterange-done:hover {
    background: var(--accent-dark);
}

/* Overrides .filters button's solid accent fill (higher specificity than a
   bare .suggest-item would have) -- these are list items, not the form's
   submit button, even though they're both <button> elements inside .filters. */
.filters .suggest-item {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    padding: 9px 12px;
    font: inherit;
    font-size: 13px;
    color: var(--text);
    cursor: pointer;
    white-space: nowrap;
    box-shadow: none;
    transition: background 0.1s ease, color 0.1s ease;
}

.filters .suggest-item:hover {
    background: var(--accent-soft);
    color: var(--accent-dark);
}

/* 2026-08-30 (구글 플라이트 도착지 선택 방식, 사용자 후속 요청: "화살표를
   눌러야지 밑에 상세로 나오게 해주고 화살표 안누르고 그냥 클릭하면 걔도
   클릭할수있게"): a multi-airport city (e.g. "타이베이" -> 타오위안/쑹산)
   collapses into one .suggest-group row -- the city NAME and the expand
   toggle are now two separate clickable elements side by side (previously
   one single button that only ever expanded, with no way to pick the bare
   city itself). */
.suggest-group-row {
    display: flex;
    align-items: center;
    gap: 4px;
}

.filters .suggest-group-label {
    flex: 1;
    width: auto;
    min-width: 0;
}

/* The plain (non-clickable) variant -- shown instead of a button when the
   bare group name can't resolve to one specific code (e.g. "도쿄", genuinely
   ambiguous between Narita/Haneda with no single right answer -- see
   _rows_from_codes()'s comment on `group_value`). Same box model as the
   button variant so the row doesn't visually jump between the two cases. */
.filters .suggest-group-label-plain {
    display: block;
    padding: 9px 12px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
    cursor: default;
}

.filters .suggest-group-toggle {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    padding: 9px;
    cursor: pointer;
    box-shadow: none;
    color: var(--text-muted);
    transition: background 0.1s ease, color 0.1s ease;
}

.filters .suggest-group-toggle:hover {
    background: var(--accent-soft);
    color: var(--accent-dark);
}

.suggest-group-toggle .chevron {
    flex: none;
    transition: transform 0.15s ease;
}

.suggest-group-toggle[aria-expanded="true"] .chevron {
    transform: rotate(180deg);
}

.suggest-sublist {
    list-style: none;
    margin: 0 0 0 12px;
    padding: 0 0 0 8px;
    border-left: 1px solid var(--border);
}

.field-submit {
    flex-direction: row;
    gap: 8px;
    justify-content: flex-end;
}

.filters button {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--accent);
    color: var(--accent-text);
    border: none;
    border-radius: var(--radius-sm);
    padding: 10px 20px;
    font-size: 13.5px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
    box-shadow: var(--shadow-sm);
}

.filters button svg {
    flex-shrink: 0;
}

.filters button:hover {
    background: var(--accent-dark);
    box-shadow: var(--shadow-md);
}

.filters button:active {
    transform: translateY(1px);
}

.filters button.btn-secondary {
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border-strong);
    box-shadow: none;
}

.filters button.btn-secondary:hover {
    background: var(--surface-muted);
    border-color: var(--accent);
}

.search-error-banner {
    background: var(--warn-bg);
    color: var(--warn-text);
    border: 1px solid var(--warn-border);
    border-radius: var(--radius-sm);
    padding: 10px 14px;
    margin-bottom: 12px;
    font-size: 13px;
    font-weight: 600;
}

/* 2026-08-30: admin-only "이 수집기가 자동으로 일시중지됨" banner
   (naver_flight blocked-detection, see app/services/collector_pause.py) --
   danger-toned (not the plain warn banner above) since this means an entire
   compare source has stopped collecting until an admin acts, not just a
   filter value getting silently clamped. */
.collector-pause-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    background: var(--danger-bg);
    color: var(--danger-text);
    border: 1px solid var(--danger-border);
    border-radius: var(--radius-sm);
    padding: 10px 14px;
    margin-bottom: 12px;
    font-size: 13px;
}

.collector-pause-banner-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.collector-pause-banner-text strong {
    font-weight: 700;
}

.collector-pause-banner-meta {
    font-size: 12px;
    opacity: 0.8;
}

.collector-pause-banner form {
    flex-shrink: 0;
}

.collector-pause-banner button {
    background: var(--surface);
    color: var(--danger-text);
    border: 1px solid var(--danger-border);
    border-radius: var(--radius-pill);
    padding: 6px 14px;
    font-size: 13px;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
}

.collector-pause-banner button:hover {
    background: var(--danger-bg);
}

/* 2026-08-30 (user request): "직접 검색"을 결과 목록 맨 끝으로 옮기면서
   (partials/direct_search_prompt.html) 카드형 안내 박스를 새로 도입 --
   같은 자리에서 진행 중일 땐 partials/search_progress_badge.html이 이
   클래스를 그대로 재사용해 "버튼 -> 진행 중 -> 완료" 흐름이 하나의 상자
   모양으로 이어지는 것처럼 보이게 함. */
.direct-search-prompt {
    margin-top: 20px;
    padding: 18px 22px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    text-align: center;
}

.direct-search-prompt-title {
    margin: 0 0 6px;
    font-size: 15px;
    font-weight: 700;
    color: var(--ink);
}

.direct-search-prompt-body {
    margin: 0 0 4px;
    font-size: 13px;
    color: var(--text);
}

.direct-search-prompt-caveat {
    margin: 0 0 14px;
    font-size: 12px;
    color: var(--text-muted);
}

.direct-search-progress-bar {
    width: 100%;
    max-width: 320px;
    height: 6px;
    margin: 0 auto 8px;
    border-radius: 3px;
    background: var(--surface-muted);
    overflow: hidden;
}

.direct-search-progress-bar-fill {
    height: 100%;
    background: var(--gold);
    transition: width 0.4s ease;
}

.direct-search-form {
    display: flex;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
}

.direct-search-form button {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 10px 18px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.direct-search-form button:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}

/* ---------- Results table ---------- */

.result-count {
    color: var(--text-muted);
    margin: 0 0 10px;
    font-size: 13px;
}

.table-scroll {
    overflow-x: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
}

/* 2026-08-30: route_summary_table.html renders BOTH this table and a
   .ticket-list card version of the same rows -- only one is ever visible,
   swapped by the max-width:640px query below. Default (desktop/tablet) shows
   the table; .route-summary-mobile-list stays hidden until that breakpoint.
   Selector is .ticket-list.route-summary-mobile-list (not just the latter)
   so its specificity (0,2,0) reliably beats .ticket-list's own
   `display: flex` (0,1,0) regardless of which rule happens to come later in
   the file -- a plain single-class override would silently lose that fight. */
.ticket-list.route-summary-mobile-list {
    display: none;
}

/* "직접 검색" 결과(search_status.html)의 날짜별 가는편/오는편 표 -- 위
   route_summary_table.html과 같은 이유(모바일 좌우 스크롤)로 같은 dual-render
   패턴을 쓰지만, 데이터 모양이 "노선+예약버튼"이 아니라 "날짜조합+편명"이라
   .ticket-card 대신 이 표 전용의 작은 카드를 새로 만듦.
   2026-08-30 추가: fare_detail.html("상세보기")의 5열 표도 실제 데이터로는
   375px에서 넘쳐서(실측) 같은 클래스(.day-result-table-wrap/.day-result-list/
   .day-result-card)를 그대로 재사용 -- hide/show 토글 규칙이 이름 그대로
   범용이라 새 CSS 없이 그대로 적용됨(내용 구성만 fare_detail.html에서 다르게,
   .day-result-action 참고). */
.day-result-list {
    display: none;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 16px;
}

.day-result-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 12px 14px;
}

.day-result-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.day-result-dates {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
}

.day-result-price {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 17px;
    font-weight: 700;
    color: var(--ink);
}

.day-result-meta {
    margin-top: 4px;
    font-size: 12px;
    color: var(--text-muted);
}

.day-result-legs {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--border);
    display: flex;
    flex-direction: column;
    gap: 3px;
    font-size: 12.5px;
    color: var(--text);
}

/* fare_detail.html("상세보기")의 .day-result-card 전용 -- 가는편/오는편
   목록(.day-result-legs) 대신 예약 버튼 하나만 오는 자리라 이름을 구분,
   시각적 구분선 스타일은 동일하게 재사용. */
.day-result-action {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--border);
    display: flex;
    justify-content: flex-end;
}

.fare-table {
    width: 100%;
    border-collapse: collapse;
    white-space: nowrap;
}

.fare-table th, .fare-table td {
    text-align: left;
    padding: 12px 14px;
    border-bottom: 1px solid var(--border);
}

.fare-table thead th {
    font-family: var(--font-mono);
    color: var(--text-muted);
    font-weight: 600;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: var(--surface-muted);
    position: sticky;
    top: 0;
}

.fare-table thead th:first-child { border-top-left-radius: var(--radius-md); }
.fare-table thead th:last-child { border-top-right-radius: var(--radius-md); }

.fare-table tbody tr {
    transition: background 0.1s ease;
}

.fare-table tbody tr:hover {
    background: var(--surface-muted);
}

.fare-table tbody tr:last-child td {
    border-bottom: none;
}

.fare-table td.price {
    font-family: var(--font-mono);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

.subtext {
    font-weight: 400;
    color: var(--text-faint);
    font-size: 11px;
}

.badge {
    background: var(--badge-bg);
    color: var(--badge-text);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    padding: 2px 10px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.info-marker {
    display: inline-block;
    margin-left: 3px;
    color: var(--text-faint);
    cursor: help;
    font-size: 12px;
}

/* ---------- Booking action buttons (ttang.com's own "예약하기" button was
   the reference -- a solid pill, not a plain text link). 2026-08-25: 골드는
   이 CTA와 헤더/카드 seam에만 쓰기로 한 자리 -- 예약 버튼을 카운터에서 건네는
   실제 항공권처럼 네이비+골드로 처리해서 검색바의 중립적 네이비 버튼과
   위계를 구분함. ---------- */

.btn-book {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--navy-800);
    color: var(--gold);
    padding: 7px 16px;
    border: 1px solid var(--navy-800);
    border-radius: var(--radius-pill);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.01em;
    text-decoration: none;
    white-space: nowrap;
    box-shadow: var(--shadow-sm);
    transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}

.btn-book:hover {
    background: var(--navy-900);
    box-shadow: var(--shadow-md);
}

.btn-book:active {
    transform: translateY(1px);
}

.btn-book-outline {
    background: var(--surface);
    color: var(--navy-800);
    border: 1px solid var(--border-strong);
    box-shadow: none;
}

.btn-book-outline:hover {
    background: var(--accent-soft);
    border-color: var(--navy-800);
    box-shadow: none;
}

/* ---------- 보딩패스 티켓 카드 (2026-08-25 리디자인 시그니처 컴포넌트) ----------
   fare_table.html의 표 대신 쓰는 카드 리스트. 본문(ticket-main)과 스텁
   (ticket-stub) 사이를 실제 항공권 절취선처럼 점선+반원 펀치홀로 표현 --
   펀치홀은 페이지 배경색(--paper)으로 칠해 카드 위에 "구멍"처럼 보이게 하고,
   카드의 overflow:hidden이 위아래 절반을 잘라내 카드 모서리에 반원 노치를
   만든다. */

.ticket-list {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.ticket-card {
    display: flex;
    align-items: stretch;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    position: relative;
    transition: box-shadow 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.ticket-card:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-lift);
    transform: translateY(-2px);
}

.ticket-main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 9px;
    padding: 16px 22px;
}

.ticket-top-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.ticket-tag {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.03em;
    padding: 2px 9px;
    border-radius: var(--radius-pill);
    background: var(--teal-soft);
    color: var(--teal-text);
    white-space: nowrap;
}

.ticket-tag.is-muted {
    background: var(--surface-muted);
    color: var(--text-muted);
}

.ticket-tag.is-oneway {
    background: var(--gold-soft);
    color: var(--gold-deep);
}

.ticket-route {
    display: flex;
    align-items: center;
    gap: 14px;
    font-family: var(--font-mono);
    font-size: 21px;
    font-weight: 600;
    color: var(--ink);
    letter-spacing: 0.005em;
}

.ticket-route-line {
    position: relative;
    flex: 1 1 auto;
    max-width: 110px;
    height: 1px;
    background: var(--border-strong);
}

.ticket-route-line::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 13px;
    height: 13px;
    transform: translate(-50%, -50%) rotate(90deg);
    mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22 16.5v-1.8l-8.5-5.2V4.3c0-.9-.7-1.6-1.5-1.6s-1.5.7-1.5 1.6v5.2L2 14.7v1.8l8.5-2.6v5.4l-2.3 1.7v1.4l3.8-1 3.8 1v-1.4l-2.3-1.7v-5.4z"/></svg>') center / contain no-repeat;
    -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M22 16.5v-1.8l-8.5-5.2V4.3c0-.9-.7-1.6-1.5-1.6s-1.5.7-1.5 1.6v5.2L2 14.7v1.8l8.5-2.6v5.4l-2.3 1.7v1.4l3.8-1 3.8 1v-1.4l-2.3-1.7v-5.4z"/></svg>') center / contain no-repeat;
    background-color: var(--gold-deep);
}

.ticket-sub {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 5px 16px;
    font-size: 12.5px;
    color: var(--text-muted);
}

.ticket-airline {
    font-weight: 700;
    color: var(--ink);
}

.ticket-dates {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.ticket-note {
    font-size: 11px;
    color: var(--text-faint);
}

.ticket-stub {
    position: relative;
    flex: 0 0 208px;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: center;
    gap: 10px;
    padding: 16px 22px;
    background: var(--surface-muted);
    border-left: 1.5px dashed var(--border-strong);
}

.ticket-stub::before,
.ticket-stub::after {
    content: "";
    position: absolute;
    left: -9px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--paper);
    border: 1px solid var(--border);
}

.ticket-stub::before { top: -9px; }
.ticket-stub::after { bottom: -9px; }

.ticket-price {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 20px;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    text-align: right;
    line-height: 1.3;
}

.ticket-price-sub {
    display: block;
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 400;
    color: var(--text-faint);
}

.ticket-actions {
    display: flex;
    flex-direction: column;
    /* 2026-08-30 (user report, desktop: "가격 그래프가 예약하기랑 다른 줄에
       오른쪽 정렬이라 이상해보임") -- flex-end였을 때는 "가격 그래프"(짧은
       텍스트)가 "예약하기"/"상세보기 (N건)" 버튼(더 넓음)의 오른쪽 끝에만
       맞춰져서 버튼 밑 가운데가 아니라 오른쪽으로 치우쳐 보였음. center로
       바꿔서 버튼과 같은 세로 중심선에 오게 함 -- .ticket-stub 쪽의
       align-items:flex-end(이 블록 전체를 stub 오른쪽 끝에 붙이는 역할)는
       안 건드려서, 가격 옆 전체 정렬은 그대로 오른쪽 유지. 모바일
       (<=640px)은 이 프로퍼티 자체가 이미 무의미함 -- 그 폭에서
       .ticket-actions는 display:contents로 바뀌어 별도의
       .ticket-stub .graph-link{flex-basis:100%; text-align:left}로
       처리됨(가격 바로 아래, 왼쪽 정렬 -- 위 미디어쿼리 참고). */
    align-items: center;
    gap: 5px;
}

.ticket-empty {
    text-align: center;
    color: var(--text-muted);
    padding: 48px 0;
    font-size: 13px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

/* ---------- Booking-click 마이리얼트립 vs 원본소스 비교 (2026-08-22) ---------- */

.booking-compare-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(220px, 1fr));
    gap: 16px;
    margin-top: 24px;
}

.booking-compare-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-top: 3px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 26px 24px;
    text-align: center;
}

.booking-compare-card--mrt {
    border-top-color: var(--gold);
    box-shadow: var(--shadow-md);
}

.booking-compare-card h2 {
    margin: 0 0 10px;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--text-muted);
}

.booking-compare-price {
    margin: 0 0 4px;
    font-family: var(--font-mono);
    font-size: 24px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
}

.booking-compare-card .subtext {
    margin: 0 0 16px;
}

@media (max-width: 640px) {
    .booking-compare-grid {
        grid-template-columns: 1fr;
    }
}

.empty {
    text-align: center;
    color: var(--text-muted);
    padding: 40px 0;
    font-size: 13px;
}

.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    margin: 20px 0 24px;
}

.pagination button {
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 7px 16px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.pagination button:not(:disabled):hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-sm);
}

.pagination button:disabled {
    opacity: 0.4;
    cursor: default;
}

.page-indicator {
    color: var(--text-muted);
    font-size: 13px;
    font-weight: 500;
}

/* ---------- Home browse sections (근거리/장거리/휴양지 카드, 이벤트 배너,
   고객센터 -- 2026-08-20, 참고: tour.yanolja.com/air) ---------- */

.home-section {
    margin-bottom: 32px;
}

.home-section-title {
    /* 2026-08-30 (사용자 요청): 위 .top-fares-title과 같은 이유로 Pretendard로 교체. */
    font-family: "Pretendard", var(--font-sans);
    font-size: 21px;
    font-weight: 600;
    letter-spacing: -0.005em;
    margin: 0 0 14px;
    color: var(--navy-800);
}

.dest-card-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 14px;
}

.dest-card {
    display: block;
    text-decoration: none;
    color: var(--text);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.dest-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-lift);
}

.dest-card-visual {
    position: relative;
    height: 120px;
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
}

.dest-card-visual::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(190deg, rgba(11, 21, 38, 0.05) 0%, rgba(11, 21, 38, 0.55) 100%);
}

.dest-card-badge {
    position: relative;
    z-index: 1;
    margin: 10px;
    padding: 3px 9px;
    background: rgba(11, 21, 38, 0.55);
    border: 1px solid rgba(201, 162, 39, 0.5);
    color: #f5f2e9;
    font-size: 11px;
    font-weight: 600;
    border-radius: var(--radius-pill);
    backdrop-filter: blur(2px);
}

.dest-card-body {
    padding: 12px 14px 14px;
}

.dest-card-route {
    font-size: 13px;
    font-weight: 700;
    margin-bottom: 4px;
}

.dest-card-date {
    font-size: 12px;
    color: var(--text-muted);
    margin-bottom: 6px;
}

.dest-card-price {
    font-size: 16px;
    font-weight: 800;
    color: var(--accent-dark);
    letter-spacing: -0.01em;
}

/* Event banner */

.event-banner-strip {
    display: flex;
    gap: 12px;
}

.event-banner-card {
    display: flex;
    align-items: center;
    gap: 14px;
    flex: 1 1 auto;
    background: linear-gradient(135deg, var(--accent-soft), var(--surface));
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 18px 20px;
    text-decoration: none;
    color: var(--text);
    box-shadow: var(--shadow-sm);
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.event-banner-card:hover {
    box-shadow: var(--shadow-lift);
    transform: translateY(-2px);
}

.event-banner-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--surface);
    color: var(--accent);
    box-shadow: var(--shadow-sm);
}

.event-banner-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1 1 auto;
}

.event-banner-text strong {
    font-size: 15px;
    font-weight: 800;
}

.event-banner-text span {
    font-size: 13px;
    color: var(--text-muted);
}

.event-banner-arrow {
    color: var(--text-faint);
    flex: 0 0 auto;
}

/* Customer service */

.customer-service-box {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 18px 20px;
    box-shadow: var(--shadow-sm);
}

.customer-service-row {
    display: flex;
    align-items: center;
    gap: 14px;
}

.customer-service-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent-dark);
}

.customer-service-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.customer-service-info strong {
    font-size: 14px;
}

.customer-service-info a {
    color: var(--accent-dark);
    font-weight: 600;
    text-decoration: none;
}

.customer-service-info a:hover {
    text-decoration: underline;
}

.customer-service-note {
    margin: 12px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

/* 익명 건의 (2026-08-20) -- the whole block (icon+title row plus the
   description below it) is a link, unlike the email row above (which links
   only the address text), so it needs its own hover/focus affordance.
   2026-08-31 (user-reported layout bug): the description used to live
   inside .customer-service-info next to the icon, so it started indented
   past the icon column while the email row's .customer-service-note started
   flush left -- moved the description out to its own .customer-service-note
   (same class/left edge as the email row's) and made this <a> a block
   container so it stacks the icon+title row above it, matching the email
   row's flush-left description. */
.customer-service-link {
    display: block;
    margin-top: 12px;
    padding: 8px;
    margin-left: -8px;
    margin-right: -8px;
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: inherit;
    transition: background 0.15s ease;
}

.customer-service-link:hover {
    background: var(--accent-soft);
}

.customer-service-link .customer-service-note {
    margin-top: 6px;
}

/* ---------- Guide page (/guide, 이벤트 배너에서 새 창으로 열림) ---------- */

.guide-page {
    max-width: 720px;
    margin: 0 auto 40px;
}

.guide-title {
    font-family: var(--font-display);
    font-size: 27px;
    font-weight: 600;
    color: var(--navy-800);
    margin: 0 0 8px;
}

.guide-intro {
    color: var(--text-muted);
    margin: 0 0 28px;
    line-height: 1.6;
}

.guide-block {
    margin-bottom: 22px;
    padding-bottom: 22px;
    border-bottom: 1px solid var(--border);
}

.guide-block:last-child {
    border-bottom: none;
}

.guide-block h3 {
    font-size: 16px;
    font-weight: 700;
    color: var(--navy-800);
    margin: 0 0 8px;
}

.guide-block p, .guide-block li {
    line-height: 1.7;
    color: var(--text);
}

.guide-block ul {
    margin: 0;
    padding-left: 18px;
}

.guide-block a {
    color: var(--navy-800);
    font-weight: 600;
    transition: color 0.15s ease;
}

.guide-block a:hover {
    color: var(--gold-deep);
}

/* 2026-08-30 (사용자 요청: "최대한 자세하게... 필드 모양을 그대로 가져오면서
   하나씩 체크하며") -- 가이드 페이지 전면 개편에 새로 추가된 컴포넌트들.
   기존 .guide-page 폭(720px)은 실제 검색창(최대 ~1040px)을 축소 없이
   보여주기엔 좁아서 페이지 자체를 넓힘. */
/* 2026-08-30 (사용자 요청: "가이드 문서 폰트를 pretendard로 바꿔줄래? 눈이
   아픈거 같아") -- 사이트 전체(--font-sans, Gothic A1)는 그대로 두고 이
   가이드 페이지 안의 설명 글(제목·본문·필드 설명·콜아웃·FAQ)만 Pretendard로
   교체. 실제 검색창/카드를 그대로 복제한 .guide-mockup 안쪽은 그 컴포넌트
   자신의 폰트 규칙(예: .ticket-price의 --font-mono)이 이미 따로 있어서
   상속으로 값이 없는 요소에만 적용되는 이 규칙의 영향을 받지 않음 -- 즉
   미리보기는 실제 사이트와 완전히 같은 모습을 계속 유지함. */
/* 2026-08-30 (사용자 지적: "데스크탑에서 보기에 가로 길이가 다 제각각") --
   원래 .guide-copy/.guide-section-desc만 680px로 좁게 잡아뒀는데, 그 옆의
   .guide-mockup/.guide-fieldnotes/.guide-callout/.guide-faq는 전부 max-width가
   없어 .guide-page 전체 폭(880px)까지 늘어나 있었음 -- 문단만 좁고 나머지는
   넓어서 왼쪽/오른쪽 끝이 안 맞았던 것(모바일은 어차피 둘 다 화면 폭에 눌려서
   차이가 안 보였을 뿐). .guide-copy의 680px 제한을 없애고 전부 .guide-page의
   폭에 맞춰 통일. */
.guide-page {
    max-width: 880px;
    font-family: "Pretendard", var(--font-sans);
}

.guide-title, .guide-section-title {
    font-family: "Pretendard", var(--font-sans);
}

.guide-toc {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    list-style: none;
    margin: 0 0 32px;
    padding: 16px;
    background: var(--surface-muted);
    border-radius: var(--radius-md);
}

.guide-toc a {
    display: inline-block;
    padding: 6px 12px;
    border-radius: var(--radius-pill);
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.guide-toc a:hover {
    background: var(--navy-800);
    border-color: var(--navy-800);
    color: var(--on-navy);
}

.guide-section {
    margin-bottom: 44px;
    scroll-margin-top: 20px;
}

.guide-section-title {
    font-size: 21px;
    font-weight: 600;
    color: var(--navy-800);
    margin: 0 0 6px;
}

.guide-section-desc {
    color: var(--text-muted);
    margin: 0 0 18px;
    line-height: 1.7;
}

/* 실제 검색창/카드 컴포넌트를 그대로 재사용한 "미리보기" -- 실제 폼이 아니라
   순수 예시라 클릭/입력이 전혀 안 먹도록 이 안의 모든 상호작용 요소를 죽임
   (개별 태그마다 disabled를 신경 쓰는 대신 컨테이너 레벨에서 한 번에 차단). */
.guide-mockup {
    padding: 20px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    margin-bottom: 14px;
}

.guide-mockup * {
    pointer-events: none !important;
}

.guide-mockup .suggest-list { display: none !important; }

/* 가이드 페이지의 미리보기 카드는 실제 검색창보다 폭이 좁아서(880px 대
   ~1040px), .daterange-display의 고정 width:190px가 부모 .field의 좁아진
   flex 배분폭에 밀려 실제로는 158px까지 줄어들며 날짜 범위 텍스트 뒷부분이
   잘렸음(실측 확인) -- 실제 검색창은 이 폭 문제가 없어 그대로 두고, 미리보기
   안에서만 최소폭을 보장. */
.guide-mockup .daterange-display {
    min-width: 190px;
}

.guide-fieldnotes {
    margin: 0 0 32px;
    padding: 0;
    list-style: none;
}

.guide-fieldnotes > li {
    display: flex;
    gap: 12px;
    padding: 10px 0;
    border-top: 1px dashed var(--border);
    line-height: 1.7;
}

.guide-fieldnotes > li:first-child {
    border-top: none;
}

.guide-fieldnotes .field-label {
    flex: none;
    width: 96px;
    font-weight: 700;
    color: var(--navy-800);
}

.guide-fieldnotes .field-desc {
    flex: 1;
    min-width: 0;
    color: var(--text);
}

.guide-fieldnotes .field-desc code {
    background: var(--surface-muted);
    padding: 1px 6px;
    border-radius: 4px;
    font-family: var(--font-mono);
    font-size: 12px;
}

.guide-callout {
    display: flex;
    gap: 10px;
    padding: 14px 16px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    margin: 0 0 18px;
    line-height: 1.7;
}

.guide-callout-icon {
    flex: none;
    font-size: 15px;
    line-height: 1.7;
}

.guide-callout p {
    margin: 0;
}

.guide-callout p + p {
    margin-top: 6px;
}

.guide-callout-key {
    background: var(--gold-soft);
    border-color: var(--gold);
    color: var(--navy-900);
}

.guide-callout-tip {
    background: var(--teal-soft);
    border-color: var(--teal);
    color: var(--teal-text);
}

.guide-callout-warn {
    background: var(--warn-bg);
    border-color: var(--warn-border);
    color: var(--warn-text);
}

.guide-callout strong {
    font-weight: 700;
}

.guide-faq {
    margin: 0;
    padding: 0;
}

.guide-faq-item {
    border-top: 1px solid var(--border);
    padding: 14px 0;
}

.guide-faq-item:last-child {
    padding-bottom: 0;
}

.guide-faq-q {
    font-weight: 700;
    color: var(--navy-800);
    margin: 0 0 6px;
}

.guide-faq-a {
    margin: 0;
    color: var(--text);
    line-height: 1.7;
}

.guide-example-caption {
    font-size: 12px;
    color: var(--text-faint);
    margin: 0 0 14px;
}

@media (max-width: 700px) {
    .guide-fieldnotes > li {
        flex-direction: column;
        gap: 2px;
    }
    .guide-fieldnotes .field-label {
        width: auto;
    }
}

.credit-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.credit-table th, .credit-table td {
    text-align: left;
    padding: 9px 12px;
    border-bottom: 1px solid var(--border);
}

.credit-table th {
    font-family: var(--font-mono);
    color: var(--text-muted);
    font-weight: 600;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.credit-table a {
    color: var(--navy-800);
    transition: color 0.15s ease;
}

.credit-table a:hover {
    color: var(--gold-deep);
}

/* Small, deliberately unobtrusive link at the bottom of the home browse
   sections -- see partials/home_sections.html's photo-credit-link. */
.photo-credit-link {
    display: block;
    text-align: right;
    font-size: 11px;
    color: var(--text-faint);
    text-decoration: none;
    margin: -6px 0 26px;
}

.photo-credit-link:hover {
    color: var(--text-muted);
}

/* 익명 건의 (2026-08-20) -- write form textarea + admin 건의함 list. */
.field textarea {
    width: 100%;
    min-height: 160px;
    resize: vertical;
    line-height: 1.5;
}

.feedback-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.feedback-item {
    border: 1px solid var(--border);
    border-left: 3px solid var(--gold);
    border-radius: var(--radius-sm);
    padding: 14px 16px;
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}

.feedback-message {
    margin: 0 0 8px;
    white-space: pre-wrap;
    line-height: 1.6;
}

.feedback-date {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-faint);
}

/* ---------- Footer ---------- */

.site-footer {
    margin-top: 44px;
    padding: 22px 0 30px;
    border-top: 1px solid var(--border-strong);
    text-align: center;
    color: var(--text-faint);
    font-size: 12px;
    line-height: 1.6;
}

.affiliate-disclosure {
    max-width: 720px;
    margin: 0 auto;
}

.site-footer a {
    color: var(--text-muted);
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.site-footer a:hover {
    color: var(--gold-deep);
    border-color: var(--gold-deep);
}

/* ---------- Small screens ---------- */

@media (max-width: 640px) {
    .page {
        padding: 20px 14px 0;
    }

    .site-header {
        align-items: flex-start;
    }

    .filters {
        padding: 14px;
    }

    .ticket-card {
        flex-direction: column;
    }

    .ticket-route {
        font-size: 17px;
        flex-wrap: wrap;
        row-gap: 6px;
    }

    .ticket-route-line {
        max-width: 60px;
    }

    .ticket-stub {
        flex-basis: auto;
        width: 100%;
        align-items: stretch;
        border-left: none;
        border-top: 1.5px dashed var(--border-strong);
        flex-direction: row;
        justify-content: space-between;
        align-items: center;
        /* 2026-08-30 (user report: 예약하기가 가격이랑 안 맞고, 가격그래프가
           오른쪽으로 치우쳐 보임) -- .ticket-actions를 display:contents로
           "펼쳐서" 예약하기/가격그래프가 이 flex row의 직접 자식이 되게 함.
           그래야 예약하기 하나만 있을 때의 높이로 .ticket-price와 나란히
           center 정렬되고(전엔 button+link 뭉치 전체가 가운데 정렬되면서
           button 혼자 위로 쏠려 보였음), 가격그래프는 flex-basis:100%로
           둘째 줄에 내려가 그 줄 안에서 다시 가운데 정렬됨(전엔
           align-items:flex-end라 예약하기 오른쪽 끝에 맞춰져 있었음). */
        flex-wrap: wrap;
        row-gap: 4px;
    }

    .ticket-stub::before,
    .ticket-stub::after {
        left: auto;
        top: -9px;
    }

    .ticket-stub::before { left: -9px; }
    .ticket-stub::after { right: -9px; bottom: auto; }

    .ticket-price {
        text-align: left;
    }

    .ticket-actions {
        display: contents;
    }

    .ticket-stub .graph-link {
        /* 2026-08-30 (user request, 재수정): 가운데 정렬 대신 가격 바로
           아래, 가격과 같은 왼쪽 정렬로 -- .ticket-price가 이 줄과 같은
           left padding을 공유해서 별도 위치 지정 없이 text-align:left만으로
           가격 바로 밑에 붙어 보임. */
        flex: 0 0 100%;
        text-align: left;
        margin-top: 0;
    }

    .field input, .field select {
        min-width: 0;
        width: 100%;
    }

    .field-group {
        width: 100%;
    }

    .field-group .field {
        flex: 1 1 0;
        min-width: 0;
    }

    .field-group .field input,
    .field-group .field select {
        width: 100%;
        min-width: 0;
    }

    .advanced-grid {
        grid-template-columns: 1fr 1fr;
    }

    .advanced-grid .field-group {
        grid-column: span 2;
    }

    /* 이 폭에서는 검색바 필드들이 세로로 쌓이는데(각 필드가 100% 너비),
       가로 구분선이 그대로 남아있으면 각 필드 블록 오른쪽에 세로줄이
       삐죽 튀어나오는 것처럼 보임 -- 줄바꿈 간격만으로 구분되도록 지움. */
    .filters-primary .field-group,
    .filters-primary > .field:not(.field-submit) {
        border-right: none;
    }

    .filters-primary .field-duration {
        flex-basis: 100%;
        max-width: none;
    }

    /* 2026-08-30 (user report: 출발일 선택 후 날짜 뒤쪽이 잘려 보임) --
       .daterange-field는 .field-duration과 마찬가지로 그냥 .field라 이 폭에서
       자동으로 100% 너비가 되는 게 아니라 내용물 크기만큼만 좁게 잡혀있었음
       (실측: 필드 176px, 입력창 158px인데 "2026-09-16 ~ 2026-09-22" 같은 범위
       텍스트는 167px 필요 -- 그 차이만큼 뒤가 잘림). .field-duration과 동일하게
       한 줄 전체 너비로 넓혀서 desktop 전용이던 .daterange-display의 고정
       width:190px보다 항상 넉넉하게 함. */
    .daterange-field {
        flex-basis: 100%;
        max-width: none;
    }

    .daterange-display {
        width: 100%;
    }

    .filters-primary .field-submit {
        margin-left: 0;
        width: 100%;
    }

    .filters-primary .field-submit button {
        width: 100%;
        justify-content: center;
    }

    /* 2026-08-30 (user report: 5개가 2+2+1로 어중간하게 줄바꿈되면서
       스크롤이 괜히 길어 보임): grid -> 가로 스와이프 한 줄로 전환. 카드
       폭을 뷰포트의 72%로 잡아 다음 카드가 오른쪽에 살짝 걸쳐 보이게
       해서(peek) "옆으로 더 있다"는 걸 스크롤바 없이도 알 수 있게 함 --
       top-fares 캐러셀(fare-carousel)과 달리 자동재생/점 인디케이터 없는
       순수 CSS 스크롤 스냅만 사용(5개 정도는 자연스러운 스와이프로 충분,
       별도 JS/컨트롤 불필요). scroll-snap-align:start라 한 번 스와이프하면
       카드 경계에 딱 맞춰 멈춤. */
    .dest-card-grid {
        display: flex;
        flex-wrap: nowrap;
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        padding-bottom: 2px;
        margin: 0 -14px;
        padding-left: 14px;
        padding-right: 14px;
    }

    .dest-card-grid::-webkit-scrollbar {
        display: none;
    }

    .dest-card-grid .dest-card {
        flex: 0 0 72%;
        scroll-snap-align: start;
    }

    .route-summary-table-wrap {
        display: none;
    }

    /* Must match the (0,2,0) specificity of the desktop-default
       .ticket-list.route-summary-mobile-list{display:none} rule above --
       .route-summary-mobile-list alone is only (0,1,0) and would silently
       lose that fight regardless of media-query/source order. */
    .ticket-list.route-summary-mobile-list {
        display: flex;
    }

    .day-result-table-wrap {
        display: none;
    }

    .day-result-list {
        display: flex;
    }

    .event-banner-strip {
        flex-direction: column;
    }

    .customer-service-row {
        align-items: flex-start;
    }
}

@media (max-width: 900px) and (min-width: 641px) {
    .dest-card-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

.graph-link {
    display: inline-block;
    margin-top: 6px;
    font-size: 12px;
    color: var(--text-muted);
    text-decoration: underline;
}

.graph-link:hover {
    color: var(--accent);
}

/* 2026-08-21: "일자별 가격 그래프" (/fares/graph) -- see fare_graph.html.
   Single-series line chart: no legend box (dataviz skill's "a single series
   needs no legend" -- the page title already names it), text stays in
   text tokens (never the line's own color), gridlines hairline+recessive. */
.graph-duration-form {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 20px;
}

.graph-duration-form label {
    font-size: 14px;
    color: var(--text-muted);
}

.graph-duration-form select {
    font-family: inherit;
    font-size: 14px;
    padding: 6px 10px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
}

.graph-stats {
    display: flex;
    gap: 12px;
    margin-bottom: 20px;
}

.graph-stat {
    flex: 1;
    background: var(--surface);
    border: 1px solid var(--border);
    border-top: 3px solid var(--border-strong);
    border-radius: var(--radius-md);
    padding: 12px 16px;
    box-shadow: var(--shadow-sm);
}

/* 세 통계 카드는 항상 최저가/평균가/최고가 순으로 렌더링됨(fare_graph.html) --
   이 앱의 핵심 가치인 "최저가"만 골드로 강조. */
.graph-stat:first-child {
    border-top-color: var(--gold);
}

.graph-stat-label {
    display: block;
    font-family: var(--font-mono);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    margin-bottom: 5px;
}

.graph-stat-value {
    display: block;
    font-family: var(--font-mono);
    font-size: 21px;
    font-weight: 700;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}

.graph-stat:first-child .graph-stat-value {
    color: var(--gold-deep);
}

.graph-wrap {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 16px;
}

.graph-gridline {
    stroke: var(--border);
    stroke-width: 1;
}

.graph-axis-label {
    fill: var(--text-faint);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

.graph-line {
    stroke: var(--accent);
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.graph-min-marker {
    fill: var(--gold-deep);
    stroke: var(--surface);
    stroke-width: 2;
}

.graph-min-label {
    fill: var(--gold-deep);
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.graph-crosshair {
    stroke: var(--text-faint);
    stroke-width: 1;
    pointer-events: none;
}

.graph-hover-dot {
    fill: var(--accent-dark);
    stroke: var(--surface);
    stroke-width: 2;
    pointer-events: none;
}

#graph-hit-area {
    cursor: crosshair;
    /* 2026-08-30 (user report: 모바일에서 드래그해도 날짜별 값이 안 보이고
       그래프 전체만 보임) -- 이게 없으면 이 위에서 손가락으로 드래그하는
       제스처를 브라우저가 기본적으로 "페이지를 옆/위아래로 스크롤하려는
       시도"로 먼저 채가서, JS의 pointermove가 안정적으로 연속 발생하지
       않았음(터치 인터랙션의 fare-carousel 스와이프 때와 반대 상황 --
       거긴 세로 스크롤은 살리고 가로만 가로채야 했지만, 여기는 그래프 위
       제스처 전부를 툴팁 갱신에 써야 해서 touch-action 자체를 꺼야 함). */
    touch-action: none;
}

.graph-tooltip {
    position: absolute;
    top: 8px;
    transform: translateX(-50%);
    background: var(--text);
    color: #fff;
    border-radius: var(--radius-sm);
    padding: 6px 10px;
    font-size: 12px;
    line-height: 1.4;
    pointer-events: none;
    white-space: nowrap;
    box-shadow: var(--shadow-md);
    z-index: 5;
}

.graph-tooltip-date {
    color: rgba(255, 255, 255, 0.75);
}

.graph-tooltip-price {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* ---------- Confirmation modal (2026-08-30, "직접 검색" 확인창) ----------
   이 프로젝트 첫 모달 -- 기존 daterange-popup/suggest-list 같은 다른 팝오버는
   전부 특정 필드에 앵커된 절대배치였지만, 이건 페이지 전체를 덮는 진짜
   모달이 필요해서 새 패턴으로 추가. */
/* [hidden] must win over the plain class rule below -- a bare
   .modal-overlay{display:flex} has the SAME specificity as the browser's
   own default `[hidden]{display:none}` UA rule, and since this stylesheet
   loads after the UA one, it would silently win the tie and keep the modal
   visible (and worse, still intercepting clicks) even while `hidden` is
   set. Found live: the confirm-overlay swallowed every click on the page
   underneath it despite `hidden` being present. */
.modal-overlay[hidden] {
    display: none;
}

.modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(11, 21, 38, 0.55);
}

.modal-card {
    width: 100%;
    max-width: 380px;
    background: var(--surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lift);
    padding: 22px 24px;
}

.modal-card h3 {
    margin: 0 0 14px;
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 600;
    color: var(--ink);
}

.modal-summary-list {
    list-style: none;
    margin: 0 0 14px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 13px;
    color: var(--text);
}

.modal-summary-list li {
    padding-bottom: 6px;
    border-bottom: 1px dashed var(--border);
}

.modal-summary-list li:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.modal-note {
    margin: 0 0 18px;
    font-size: 12px;
    color: var(--text-muted);
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

.modal-btn {
    padding: 9px 18px;
    border-radius: var(--radius-sm);
    font-size: 13px;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    border: 1px solid transparent;
    transition: opacity 0.15s ease, background 0.15s ease;
}

.modal-btn-secondary {
    background: var(--surface);
    color: var(--text);
    border-color: var(--border-strong);
}

.modal-btn-secondary:hover {
    background: var(--surface-muted);
}

.modal-btn-primary {
    background: var(--navy-800);
    color: var(--gold-soft);
}

.modal-btn-primary:hover {
    opacity: 0.9;
}

@media (max-width: 640px) {
    .modal-card {
        padding: 18px 20px;
    }
}
