Files
teacherpick/src/views/LocationSubjectLanding.vue
T
2026-11-10 10:12:09 +09:00

2240 lines
63 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="post-page">
<!-- 메인 콘텐츠 쉘 -->
<main id="top" class="post-shell container">
<!-- 상단 뱃지 -->
<div class="post-badges">
<span class="badge-item loc">[지역] {{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} {{ regionInfo.dong
}}</span>
<span class="badge-item cat">[분류] {{ regionInfo.sidoShort }} {{ currentTarget.name }} 과외 · {{ currentTarget.name }} {{ currentSubject.name }} 과외</span>
</div>
<!-- 1. 메인 헤더 타이틀 (h1) + 메타 키워드 태그 바 + 소제목 (h2) + 일반 본문 글 -->
<header class="post-header">
<h1>{{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} {{ regionInfo.dong }} {{ currentTarget.name }} {{
currentSubject.name }} 과외 | {{ regionInfo.sidoShort }} {{ currentTarget.name }} 과외 선생님 추천</h1>
<!-- 메타 키워드 태그 영역 (h1 바로 다음 배치 - 광역/구/동 키워드 매칭) -->
<div class="post-meta-keywords" aria-label="핵심 검색 키워드">
<span class="meta-kw-chip primary">#{{ regionInfo.sidoShort }} {{ currentTarget.name }} {{ currentSubject.name }} 과외</span>
<span class="meta-kw-chip primary">#{{ regionInfo.sidoShort }} {{ currentTarget.name }} 과외</span>
<span class="meta-kw-chip">#{{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} {{ currentTarget.name }} {{ currentSubject.name }} 과외</span>
<span class="meta-kw-chip">#{{ regionInfo.sigungu }} {{ currentTarget.name }} 과외</span>
<span class="meta-kw-chip">#{{ regionInfo.dong }} {{ currentTarget.name }} {{ currentSubject.name }} 과외</span>
<span class="meta-kw-chip">#{{ regionInfo.dong }} {{ currentTarget.name }} 과외</span>
<span class="meta-kw-chip">#{{ regionInfo.sidoShort }} {{ currentSubject.name }} 1:1 방문과외</span>
</div>
<!-- 소제목 (h2) 및 일반 소개 본문 글 -->
<h2 class="post-lead-h2">{{ regionInfo.sidoShort }} {{ currentTarget.name }} {{ currentSubject.name }} 과외 및 {{ regionInfo.sigungu }} {{ regionInfo.dong }} 1:1 맞춤 내신·수능 전문 지도</h2>
<p class="post-lead-text">
<strong>{{ regionInfo.sidoShort }} {{ currentTarget.name }} {{ currentSubject.name }} 과외</strong>와 <strong>{{ regionInfo.sidoShort }} {{ currentTarget.name }} 과외</strong>를 찾으시는 학생·학부모님을 위해, {{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} {{ regionInfo.dong }} 인근 학교별 내신 기출 분석과 검증된 베테랑 선생님의 1:1 방문·맞춤 수업 커리큘럼 및 무료 모의수업 상담 정보를 한눈에 비교해 드립니다.
</p>
</header>
<!-- 빠른 상담 액션 버튼 2종 -->
<div class="post-action-row">
<a class="post-action orange" href="#consult-form" :style="actionBtnHeight ? { minHeight: actionBtnHeight } : {}">
<span class="action-tag">상담</span>
<div>
<strong>1:1 무료 모의수업 상담 받기</strong>
</div>
</a>
<a ref="bottomActionBtn" class="post-action outline" href="#consult-form">
<span class="action-tag">진단</span>
<div>
<strong>{{ regionInfo.dong }} 베테랑선생님 상담받기</strong>
</div>
</a>
</div>
<!-- 메인 히어로 포스터 미디어 -->
<figure class="post-hero-media">
<div class="hero-img-box">
<img src="/img/tutor-pick-poster.png"
:alt="`${regionInfo.sidoShort} ${regionInfo.sigungu} ${regionInfo.dong} ${currentTarget.name} ${currentSubject.name} 과외 24시간 신속 상담 안내`"
class="poster-img" />
<div class="hero-img-tag">
<span>{{ regionInfo.dong }} {{ currentTarget.name }} {{ currentSubject.name }} 1:1 과외</span>
</div>
</div>
</figure>
<!-- 3D 인터랙티브 푸시 버튼 (선생님 자세히 알아보기) -->
<div class="link-div">
<a href="https://gwaoepick.com/" target="_blank" rel="noopener noreferrer" class="btn-3d-interactive"
:aria-label="`${regionInfo.dong} 선생님 자세히 알아보기 및 공식 홈페이지 이동`">
<span class="btn-3d-text-wrap">
<span class="btn-3d-text"><span class="text-highlight-yellow">{{ regionInfo.dong }} 선생님</span> 자세히
알아보기</span>
<span class="btn-3d-cursor">
<svg class="cursor-icon" viewBox="0 29 45 44" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M40.784 63.057L29.449 51.721l6.387-6.386c2.397-2.398 1.684-5.095-1.588-5.988 L4.545 31.219c-3.271-0.896-5.219 1.049-4.33 4.321l8.129 29.701c0.901 3.3 3.6 4 6 1.584l6.386-6.386l11.336 11.3 c2.398 2.4 6.3 2.4 8.7 0C43.183 69.4 43.2 65.5 40.8 63.057z"
fill="#FFFFFF" />
</svg>
</span>
</span>
</a>
</div>
<!-- 1:1 무료 모의수업 신청 폼 섹션 (선생님 자세히 알아보기 버튼 바로 아래 위치) -->
<section id="consult-form" class="consult-form-wrap">
<div class="form-container">
<div class="form-header">
<h2>{{ regionInfo.dong }} <span class="text-orange">{{ currentTarget.name }} {{ currentSubject.name }}
과외</span> 무료 모의수업 신청</h2>
<p>베테랑 선생님 배정과 학습 진단 컨설팅을 무료로 받아보세요.</p>
</div>
<form @submit.prevent="handleFormSubmit" class="submit-form">
<div class="form-row">
<div class="form-group">
<label>지역</label>
<input v-model="formData.region" type="text"
:placeholder="`${regionInfo.sidoShort} ${regionInfo.sigungu} ${regionInfo.dong}`" @blur="onRegionBlur"
class="input-region" />
</div>
<div class="form-group">
<label>희망 과목</label>
<select v-model="formData.selectedSubjectSlug" class="select-field" required>
<option value="korean">국어</option>
<option value="english">영어</option>
<option value="math">수학</option>
<option value="social">사회</option>
<option value="science">과학</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>학생 이름</label>
<input v-model="formData.studentName" type="text" placeholder="학생 이름을 입력하세요" required />
</div>
<div class="form-group">
<label>학부모 연락처</label>
<input v-model="formData.phone" type="tel" placeholder="010-1234-5678" required />
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>학생 학년</label>
<select v-model="formData.grade" required>
<option value="" disabled selected>학년을 선택하세요</option>
<option value="중1">중학교 1학년</option>
<option value="중2">중학교 2학년</option>
<option value="중3">중학교 3학년</option>
<option value="고1">고등학교 1학년</option>
<option value="고2">고등학교 2학년</option>
<option value="고3">고등학교 3학년 / N수</option>
<option value="초등">초등학생 (예비중)</option>
</select>
</div>
</div>
<div class="form-group">
<label>상담 및 학습 고민 사항 (선택)</label>
<textarea v-model="formData.memo" rows="3"
placeholder="현재 등급, 시험 성적, 취약한 단원 등을 남겨주시면 더욱 정확한 선생님 매칭이 가능합니다."></textarea>
</div>
<button type="submit" class="btn-primary btn-submit">
{{ isSubmitting ? '신청 처리 중...' : '1:1 맞춤 무료 모의수업 신청하기' }}
</button>
<p class="form-privacy-note">
* 입력해주신 정보는 과외 매칭 및 학습 상담 목적으로만 안전하게 사용됩니다.
</p>
</form>
</div>
</section>
<!-- 긴급 공지 알림 박스 -->
<section class="post-notice">
<p><strong>빠른 과외 매칭 요청</strong>은 상담 폼을 이용해 주세요.</p>
<p>자세하게 과외선생님을 알아보고 싶은 경우 선생님 자세히 알아보기 버튼을 클릭하시면 확인하실 수 있습니다.</p>
<small>* 학생 학년,수준,목표,공부습관을 확인 후 최적의 1:1 베테랑 선생님이 배정됩니다.</small>
</section>
<!-- 대표 지역 요약 데이터 리스트 -->
<section class="post-summary">
<div>
<h2>{{ regionInfo.sidoShort }} {{ currentTarget.name }} {{ currentSubject.name }} 과외 · {{ regionInfo.sigungu }} {{ regionInfo.dong }} 맞춤 학습 안내</h2>
<p>{{ regionInfo.sidoShort }} {{ currentTarget.name }} 과외 및 {{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} {{ regionInfo.dong }} 일대에서 {{ currentTarget.name }} {{
currentSubject.name }} 과외, 내신 관리·수능 대비 등 핵심 키워드를 기준으로 인근 학교 기출 분석과 베테랑 선생님 카드를 정리했습니다.</p>
</div>
<dl>
<div>
<dt>대표 지역</dt>
<dd>{{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} {{ regionInfo.dong }}</dd>
</div>
<div>
<dt>대표 과목</dt>
<dd>{{ regionInfo.sidoShort }} {{ currentTarget.name }} {{ currentSubject.name }} 과외</dd>
</div>
<div>
<dt>핵심 키워드</dt>
<dd>{{ regionInfo.sidoShort }} {{ currentTarget.name }} 과외 · 1:1 맞춤과외</dd>
</div>
</dl>
</section>
<!-- 상단 지역 인근 과목 상담 빠른 보기 스트립 (1:1 썸네일 스트립 - 검색엔진 멀티 이미지 갤러리 지원) -->
<section class="post-strip" itemscope itemtype="https://schema.org/ImageGallery">
<h2>{{ regionInfo.sidoShort }} {{ regionInfo.dong }} {{ currentTarget.name }} 1:1 과외 과목별 빠른 보기</h2>
<div class="rowx">
<div v-for="sub in SUBJECTS" :key="sub.id" :class="['pcitem', { active: sub.slug === currentSubject.slug }]"
itemprop="associatedMedia" itemscope itemtype="https://schema.org/ImageObject">
<router-link class="pclink"
:to="`/${regionInfo.sidoSlug}/${regionInfo.sigunguSlug}/${regionInfo.dongSlug}/${currentTarget.slug}/${sub.slug}`">
<div class="pcimg-wrap">
<img :src="sub.image" :alt="`${regionInfo.sidoShort} ${regionInfo.sigungu} ${regionInfo.dong} ${currentTarget.name} ${sub.name} 과외 1:1 맞춤 지도`"
width="500" height="500" class="pcimg" itemprop="contentUrl" />
<span v-if="sub.slug === currentSubject.slug" class="selected-badge">선택됨</span>
</div>
<div class="pcname" itemprop="caption">{{ regionInfo.sidoShort }} {{ currentTarget.name }} {{ sub.name }} 과외</div>
</router-link>
</div>
</div>
</section>
<!-- 지역 플레이스 업체/선생님 정보 목록 (1~6위 카드 그리드) -->
<section id="places" class="post-places" aria-label="지역 과외 선생님 정보">
<div class="section-heading">
<span>Local</span>
<h2>{{ regionInfo.dong }} {{ currentTarget.name }} {{ currentSubject.name }} 과외 지역 매칭 정보</h2>
</div>
<div class="place-grid">
<div v-for="(nearDong, idx) in rankPlaceList" :key="nearDong" class="place-card">
<div class="place-top-bar">
<span class="place-rank-badge">추천 0{{ idx + 1 }}</span>
<span class="place-cat-tag">교육서비스 · 1:1 맞춤과외</span>
</div>
<div class="place-main">
<h3>{{ getPlaceCardTitle(nearDong, idx) }}</h3>
<p class="place-addr">{{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} {{ nearDong }}</p>
<p class="place-kw">{{ getPlaceCardKeywords(idx) }}</p>
<p class="place-desc">{{ getPlaceCardDesc(nearDong, idx) }}</p>
</div>
<div class="place-links">
<a :href="`https://map.naver.com/v5/search/${encodeURIComponent(regionInfo.sidoShort + ' ' + regionInfo.sigungu + ' ' + nearDong + ' ' + currentSubject.name + ' 과외')}`"
target="_blank" rel="noopener noreferrer nofollow" class="map-link naver">네이버지도</a>
<a :href="`https://www.google.com/maps/search/${encodeURIComponent(regionInfo.sidoShort + ' ' + regionInfo.sigungu + ' ' + nearDong + ' ' + currentSubject.name + ' 과외')}`"
target="_blank" rel="noopener noreferrer nofollow" class="map-link google">구글지도</a>
</div>
</div>
</div>
</section>
<!-- 학교별 내신 분석 섹션 -->
<section class="schools-section">
<div class="section-heading">
<span>School Analysis</span>
<h2>{{ regionInfo.dong }} 인근 학교 내신 집중 대비 리포트</h2>
</div>
<div class="schools-grid">
<div v-for="(school, index) in targetSchools" :key="index" class="school-card">
<div class="school-header">
<span class="school-tag">학교</span>
<h3>{{ school }}</h3>
</div>
<p class="school-desc">
{{ school }} {{ currentSubject.name }} 과목 최근 3개년 기출 족보 및 서술형 킬러 문항 1:1 밀착 클리닉 제공
</p>
<div class="school-tags">
<span>#{{ currentSubject.name }}내신대비</span>
<span>#기출분석</span>
<span>#수행평가지도</span>
</div>
</div>
</div>
</section>
<!-- 자주 확인하는 질문 (FAQ) -->
<section class="faq-section">
<div class="section-heading compact">
<span>FAQ</span>
<h2>자주 확인하는 질문</h2>
</div>
<div class="faq-accordion-wrap">
<div v-for="(faq, fIdx) in faqs" :key="fIdx" class="faq-row">
<button type="button" class="faq-button" :class="{ open: openFaqIndex === fIdx }" @click="toggleFaq(fIdx)">
{{ faq.q }}
<span class="faq-arrow">{{ openFaqIndex === fIdx ? '▲' : '▼' }}</span>
</button>
<div v-show="openFaqIndex === fIdx" class="faq-panel">
<p>{{ faq.a }}</p>
</div>
</div>
</div>
</section>
<!-- 하단 Pager 내부 링크 클러스터 (동일 동 10개 과목·학년 + 동일 구·군 내 다른 동 + 동일 시·도 내 다른 구·군 연결) -->
<nav class="pager" aria-label="지역 및 과목별 과외 페이지 이동">
<div class="pager-group">
<strong class="pager-group-title">{{ regionInfo.sidoShort }} {{ regionInfo.dong }} 학년·과목별 과외 바로가기</strong>
<div class="pager-links-wrap">
<template v-for="t in TARGETS" :key="t.slug">
<router-link v-for="sub in SUBJECTS" :key="`${t.slug}-${sub.id}`"
:to="`/${regionInfo.sidoSlug}/${regionInfo.sigunguSlug}/${regionInfo.dongSlug}/${t.slug}/${sub.slug}`"
class="pager-link" :class="{ active: t.slug === currentTarget.slug && sub.slug === currentSubject.slug }">
{{ regionInfo.sidoShort }} {{ regionInfo.dong }} {{ t.name }} {{ sub.name }} 과외
</router-link>
</template>
</div>
</div>
<div v-if="relatedLinks.dongsInSigungu.length > 1" class="pager-group">
<strong class="pager-group-title">{{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} 내 다른 동 {{ currentTarget.name }} {{ currentSubject.name }} 과외</strong>
<div class="pager-links-wrap">
<router-link v-for="d in relatedLinks.dongsInSigungu" :key="d.dongSlug"
:to="`/${regionInfo.sidoSlug}/${regionInfo.sigunguSlug}/${d.dongSlug}/${currentTarget.slug}/${currentSubject.slug}`"
class="pager-link" :class="{ active: d.dongSlug === regionInfo.dongSlug }">
{{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} {{ d.name }} {{ currentTarget.name }} {{ currentSubject.name }} 과외
</router-link>
</div>
</div>
<div v-if="relatedLinks.sigungusInSido.length > 1" class="pager-group">
<strong class="pager-group-title">{{ regionInfo.sidoShort }} 주요 시·군·구 {{ currentTarget.name }} {{ currentSubject.name }} 과외</strong>
<div class="pager-links-wrap">
<router-link v-for="sg in relatedLinks.sigungusInSido" :key="sg.sigunguSlug"
:to="`/${regionInfo.sidoSlug}/${sg.sigunguSlug}/${sg.repDongSlug}/${currentTarget.slug}/${currentSubject.slug}`"
class="pager-link" :class="{ active: sg.sigunguSlug === regionInfo.sigunguSlug }">
{{ regionInfo.sidoShort }} {{ sg.name }} {{ currentTarget.name }} {{ currentSubject.name }} 과외
</router-link>
</div>
</div>
<router-link v-if="isAdmin" to="/regions" class="pager-link pager-next">전국 지역 목록 보기 →</router-link>
</nav>
<!-- 하단 가로형 과목 이미지 캐러셀 (네이버 검색 결과 가로 멀티 썸네일 노출 최적화) -->
<section class="bottom-carousel-section" itemscope itemtype="https://schema.org/ImageGallery" aria-label="과목별 과외 가로 이미지 캐러셀">
<div class="section-heading compact">
<span>Carousel Gallery</span>
<h2>{{ regionInfo.sidoShort }} {{ regionInfo.sigungu }} {{ regionInfo.dong }} {{ currentTarget.name }} 과외 과목별 커리큘럼 갤러리</h2>
</div>
<p class="carousel-guide-text">
{{ regionInfo.sidoShort }} {{ currentTarget.name }} 과외 및 {{ regionInfo.sidoShort }} {{ currentTarget.name }} {{ currentSubject.name }} 과외 베테랑 선생님의 5대 과목 핵심 커리큘럼입니다.
</p>
<div class="horizontal-carousel-track">
<article v-for="sub in SUBJECTS" :key="`carousel-${sub.id}`" class="h-carousel-card" :class="{ current: sub.slug === currentSubject.slug }" itemprop="associatedMedia" itemscope itemtype="https://schema.org/ImageObject">
<router-link :to="`/${regionInfo.sidoSlug}/${regionInfo.sigunguSlug}/${regionInfo.dongSlug}/${currentTarget.slug}/${sub.slug}`" class="h-carousel-link">
<div class="h-carousel-img-box">
<img :src="sub.image" :alt="`${regionInfo.sidoShort} ${regionInfo.sigungu} ${regionInfo.dong} ${currentTarget.name} ${sub.name} 과외 (${regionInfo.sidoShort} ${currentTarget.name} 과외)`" width="500" height="500" itemprop="contentUrl" />
<span class="h-carousel-badge">{{ sub.tag }}</span>
</div>
<div class="h-carousel-body">
<h3 itemprop="name">{{ regionInfo.sidoShort }} {{ currentTarget.name }} {{ sub.name }} 과외</h3>
<p itemprop="description">{{ regionInfo.dong }} {{ currentTarget.name }} {{ sub.name }} {{ sub.headline }}</p>
</div>
</router-link>
</article>
</div>
</section>
<!-- 빠른 상담 리소스 링크 (네이버 5개 멀티 이미지 썸네일 매칭용 5과목 리스트) -->
<section class="post-resource-links" aria-label="빠른 상담 링크">
<a class="post-resource-link" href="#consult-form">
<span class="post-resource-thumb"><img src="/img/pick-korean.png" :alt="`${regionInfo.sidoShort} ${regionInfo.dong} ${currentTarget.name} 국어 과외 상담`" width="500" height="500"></span>
<strong class="post-resource-title">{{ regionInfo.sidoShort }} {{ regionInfo.dong }} {{ currentTarget.name }} 국어 과외 내신/수능 1등급 클리닉</strong>
<em class="post-resource-arrow">›</em>
</a>
<a class="post-resource-link" href="#consult-form">
<span class="post-resource-thumb"><img src="/img/pick-english.png" :alt="`${regionInfo.sidoShort} ${regionInfo.dong} ${currentTarget.name} 영어 과외 상담`" width="500" height="500"></span>
<strong class="post-resource-title">{{ regionInfo.sidoShort }} {{ regionInfo.dong }} {{ currentTarget.name }} 영어 과외 구문 독해 &amp; 빈칸추론</strong>
<em class="post-resource-arrow">›</em>
</a>
<a class="post-resource-link" href="#consult-form">
<span class="post-resource-thumb"><img src="/img/pick-math.png" :alt="`${regionInfo.sidoShort} ${regionInfo.dong} ${currentTarget.name} 수학 과외 상담`" width="500" height="500"></span>
<strong class="post-resource-title">{{ regionInfo.sidoShort }} {{ regionInfo.dong }} {{ currentTarget.name }} 수학 과외 개념 정복 및 서술형 대비</strong>
<em class="post-resource-arrow">›</em>
</a>
<a class="post-resource-link" href="#consult-form">
<span class="post-resource-thumb"><img src="/img/pick-social.png" :alt="`${regionInfo.sidoShort} ${regionInfo.dong} ${currentTarget.name} 사회 과외 상담`" width="500" height="500"></span>
<strong class="post-resource-title">{{ regionInfo.sidoShort }} {{ regionInfo.dong }} {{ currentTarget.name }} 사회·한국사 과외 내신 단기 완성</strong>
<em class="post-resource-arrow">›</em>
</a>
<a class="post-resource-link" href="#consult-form">
<span class="post-resource-thumb"><img src="/img/pick-science.png" :alt="`${regionInfo.sidoShort} ${regionInfo.dong} ${currentTarget.name} 과학 과외 상담`" width="500" height="500"></span>
<strong class="post-resource-title">{{ regionInfo.sidoShort }} {{ regionInfo.dong }} {{ currentTarget.name }} 과학·통합과학 과외 탐구영역 완성</strong>
<em class="post-resource-arrow">›</em>
</a>
</section>
</main>
<!-- 사업자 정보/소개 문구는 숨김 푸터 대신 <head> 의 meta 태그로 제공 (src/utils/seo.js buildLandingHead) -->
<!-- 상담 신청 완료 모달 안내창 -->
<div v-if="isModalOpen" class="consult-modal-overlay" @click.self="isModalOpen = false">
<div class="consult-modal-card">
<div class="consult-modal-icon">
<svg viewBox="0 0 24 24" width="40" height="40" fill="none" stroke="#FF5E00" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
<polyline points="22 4 12 14.01 9 11.01"></polyline>
</svg>
</div>
<h3 class="consult-modal-title">상담 신청이 완료되었습니다.</h3>
<p class="consult-modal-desc">빠른 시간 내에 순차적으로 연락드릴 예정입니다.</p>
<button type="button" class="consult-modal-btn" @click="isModalOpen = false">닫기</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { SUBJECTS, TARGETS, findTarget, findSubject } from '../data/subjects.js';
import { getRegionInfo, getRelatedRegionLinks } from '../data/regions.js';
import { usePageHead, buildLandingHead } from '../utils/seo.js';
const route = useRoute();
const router = useRouter();
const openFaqIndex = ref(0);
// 관리자 모드 판별 (/admin 경로 또는 ?admin=true 일 때만 전국 지역 목록 버튼 노출)
const isAdmin = computed(() => {
return route.path.endsWith('/admin') || route.path.includes('/admin') || route.query.admin === 'true';
});
// 라우트 파라미터 파싱
const sido = computed(() => route.params.sido || 'daegu');
const sigungu = computed(() => route.params.sigungu || 'suseong-gu');
const dong = computed(() => route.params.dong || 'hwanggeum-dong');
const rawTarget = computed(() => route.params.target || '');
const rawSubject = computed(() => route.params.subject || '');
// 현재 대상 (중학생 / 고등학생) 자동 판별 (영문/한글 모두 지원)
const currentTarget = computed(() => findTarget(rawTarget.value));
// 현재 과목 (국어, 영어, 수학, 사회, 과학) 자동 판별 (영문/한글 모두 지원)
const currentSubject = computed(() => {
if (rawSubject.value) return findSubject(rawSubject.value);
if (rawTarget.value) return findSubject(rawTarget.value);
return SUBJECTS[1];
});
// 현재 지역 정보 (영문 slug 파싱 및 한글명 자동 매칭)
const regionInfo = computed(() => getRegionInfo(sido.value, sigungu.value, dong.value));
// 동일 구·군 내 다른 동 및 동일 시·도 내 다른 구·군 내부 링크 (50,380개 전 페이지 거미줄 크롤링 보장)
const relatedLinks = computed(() => getRelatedRegionLinks(regionInfo.value.sidoSlug, regionInfo.value.sigunguSlug));
// 1~6위 랭킹용 인근 동 리스트 (자신 포함 최대 6개)
const rankPlaceList = computed(() => {
const list = [regionInfo.value.dong, ...(regionInfo.value.nearbyDongs || [])];
return list.slice(0, 6);
});
// 1~6위 추천 카드별 고유 콘텐츠 (광역·구·동 키워드 매칭 및 텍스트 다양성 확보)
const getPlaceCardTitle = (nearDong, idx) => {
const sidoShort = regionInfo.value.sidoShort;
const titles = [
`${sidoShort} ${nearDong} ${currentTarget.value.name} ${currentSubject.value.name} 과외 1:1 맞춤형 내신 1등급 클리닉`,
`${sidoShort} ${currentTarget.value.name} 과외 · ${nearDong} ${currentSubject.value.name} 취약점 분석 및 서술형 집중 대비`,
`${nearDong} 일대 ${currentTarget.value.name} ${currentSubject.value.name} 과외 기출 족보 정복 및 상위권 도약`,
`${sidoShort} ${regionInfo.value.sigungu} ${nearDong} 인근 학교 맞춤 ${currentSubject.value.name} 과외 내신 집중 관리`,
`${nearDong} ${currentTarget.value.name} ${currentSubject.value.name} 과외 개념 완성부터 심화 문제 해결력 완성`,
`${sidoShort} ${nearDong} 베테랑 선생님과 함께하는 ${currentTarget.value.name} 1:1 밀착 학습 코칭`
];
return titles[idx % titles.length];
};
const getPlaceCardDesc = (nearDong, idx) => {
const sidoShort = regionInfo.value.sidoShort;
const sigungu = regionInfo.value.sigungu;
const descs = [
`${sidoShort} ${sigungu} ${nearDong} 일대 인근 학교 시험 출제 족보 분석과 ${sidoShort} ${currentTarget.value.name} ${currentSubject.value.name} 과외 취약 개념 1:1 클리닉을 함께 확인할 수 있습니다.`,
`${sidoShort} ${currentTarget.value.name} 과외 단원별 핵심 개념 정리와 학교별 서술형 감점 요인을 집중 교정하여 실전 시험에 완벽 대비합니다.`,
`최근 3개년 내신 빈출 유형 정복과 자기주도적 오답노트 관리로 ${nearDong} ${currentTarget.value.name} ${currentSubject.value.name} 과외의 체계적인 성적 향상을 이끕니다.`,
`수행평가와 지필평가를 동시에 대비하는 ${sigungu} ${nearDong} 학교별 맞춤 커리큘럼으로 상위권 도약을 지원합니다.`,
`기초 개념 이해부터 고난도 킬러 문항까지 ${sidoShort} ${currentTarget.value.name} ${currentSubject.value.name} 과외 학생 개인별 수준에 맞춘 단계별 학습이 진행됩니다.`,
`학생의 성향과 학습 습관을 고려하여 ${sidoShort} ${sigungu} 최적의 베테랑 전문 선생님이 1:1 밀착 관리를 제공합니다.`
];
return descs[idx % descs.length];
};
const getPlaceCardKeywords = (idx) => {
const sidoShort = regionInfo.value.sidoShort;
const sigungu = regionInfo.value.sigungu;
const dongName = regionInfo.value.dong;
const kwList = [
`#${sidoShort}${currentTarget.value.name}${currentSubject.value.name}과외 #${sidoShort}${currentTarget.value.name}과외 #${dongName}${currentSubject.value.name}과외 #내신1등급목표`,
`#${sidoShort}${sigungu}${currentTarget.value.name}과외 #기출족보분석 #${currentSubject.value.name}전문 #서술형집중대비`,
`#${dongName}${currentTarget.value.name}과외 #취약단원완성 #1대1맞춤수업 #개념클리닉`,
`#${sidoShort}${currentSubject.value.name}과외 #수행평가대비 #상위권도약 #오답노트관리`,
`#${sigungu}${currentTarget.value.name}${currentSubject.value.name}과외 #수능모의고사 #심화문제해결 #체계적관리`,
`#${sidoShort}1대1과외 #베테랑선생님 #학습습관코칭 #무료모의수업`
];
return kwList[idx % kwList.length];
};
// 인근 학교 목록 (더미 명칭 필터링 및 자연스러운 정제)
const targetSchools = computed(() => {
const rawList = currentTarget.value.slug === 'middle' || currentTarget.value.id === 'middle'
? regionInfo.value.schools?.middle || []
: regionInfo.value.schools?.high || [];
const cleaned = rawList.filter(s => s && !s.includes('인근 공립') && !s.includes('지역 명문'));
if (cleaned.length > 0) {
return cleaned;
}
return [
`${regionInfo.value.dong} 소재 및 인근 ${currentTarget.value.name} 학교`,
`${regionInfo.value.sigungu} 주요 ${currentTarget.value.name} 학군`
];
});
// FAQ 목록
const faqs = computed(() => [
{
q: `${regionInfo.value.sidoShort} ${regionInfo.value.sigungu} ${regionInfo.value.dong} 지역도 ${currentTarget.value.name} ${currentSubject.value.name} 과외 출장이 되나요?`,
a: `접수하신 주소를 기준으로 ${regionInfo.value.dong} 일대 인근 학교 내신과 수능을 전문으로 지도하는 가까운 베테랑 선생님 배정 가능 여부를 확인해 안내드립니다.`
},
{
q: `수업 전에 무료 모의수업이나 레벨 테스트가 가능한가요?`,
a: `네, 신청 후 전문 학습 매니저가 1차 진단 후 최적의 베테랑 선생님과 1회 무료 모의수업 및 성취도 진단 테스트를 진행해 드립니다.`
},
{
q: `학교별 시험 족보 및 수행평가 대비가 함께 되나요?`,
a: `네, ${regionInfo.value.dong} 인근 중·고등학교의 최근 3개년 기출 문제와 교과서별 출판사 서술형 예상 문항을 철저하게 맞춤 지도합니다.`
},
{
q: `과외 비용과 수업 횟수는 어떻게 결정되나요?`,
a: `학생의 현재 등급 및 주당 수업 횟수(주 1~2회 등), 수업 시간(60분/90분)에 따라 맞춤 견적이 책정되며 온라인 상담 시 정확한 요금표를 안내드립니다.`
}
]);
// title / canonical / OG / JSON-LD 를 서버 렌더링 결과(<head>)에 포함하고, 브라우저에서는 라우트 변경 시 갱신
usePageHead(() => buildLandingHead({
region: regionInfo.value,
target: currentTarget.value,
subject: currentSubject.value,
faqs: faqs.value
}));
const toggleFaq = (index) => {
openFaqIndex.value = openFaqIndex.value === index ? -1 : index;
};
// 폼 데이터
const defaultRegionText = computed(() => `${regionInfo.value.sidoShort} ${regionInfo.value.sigungu} ${regionInfo.value.dong}`);
const formData = ref({
region: '',
studentName: '',
phone: '',
grade: '',
memo: '',
selectedSubjectSlug: 'math'
});
const isSubmitting = ref(false);
const isModalOpen = ref(false);
// 지역 input 포커스 해제 시 비어있으면 기본값으로 복원
const onRegionBlur = () => {
if (!formData.value.region || !formData.value.region.trim()) {
formData.value.region = defaultRegionText.value;
}
};
// 지역 정보 변경 시 기본 지역값 세팅
watch(defaultRegionText, (newVal) => {
formData.value.region = newVal;
}, { immediate: true });
// 현재 과목 변경 시 폼 선택값 동기화
watch(currentSubject, (newSub) => {
if (newSub) {
formData.value.selectedSubjectSlug = newSub.slug;
}
}, { immediate: true });
const DISCORD_WEBHOOK_URL = 'https://discord.com/api/webhooks/1554696525496590346/GrOwqYI3IPAfPFU0VD3BVuw6_XdsRzkZExpyICMgHMaABdSVC_Ir1VsJSRsPbJpA63bn';
const handleFormSubmit = async () => {
if (isSubmitting.value) return;
isSubmitting.value = true;
const appliedRegion = formData.value.region?.trim() || defaultRegionText.value;
const subjectObj = findSubject(formData.value.selectedSubjectSlug || currentSubject.value.slug);
const nowStr = new Date().toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' });
// 디스코드 웹훅 페이로드 구성
const payload = {
username: '티처PICK 상담 알리미',
embeds: [
{
title: '신규 1:1 맞춤 무료 모의수업 상담 신청',
description: `**${appliedRegion}** 지역에서 새로운 무료 모의수업 신청이 접수되었습니다.`,
color: 0xFF5E00,
fields: [
{ name: '지역', value: appliedRegion, inline: true },
{ name: '희망 과목', value: `${currentTarget.value.name} - ${subjectObj.name}`, inline: true },
{ name: '학생 학년', value: formData.value.grade || '미선택', inline: true },
{ name: '학생 이름', value: formData.value.studentName || '미입력', inline: true },
{ name: '학부모 연락처', value: formData.value.phone || '미입력', inline: true },
{ name: '접수 일시', value: nowStr, inline: true },
{ name: '상담 및 학습 고민 사항', value: formData.value.memo?.trim() || '(작성 내용 없음)', inline: false },
{ name: '접수 페이지 URL', value: window.location.href, inline: false }
],
footer: {
text: '티처PICK 실시간 상담 알림 시스템'
},
timestamp: new Date().toISOString()
}
]
};
try {
const res = await fetch(DISCORD_WEBHOOK_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
isModalOpen.value = true;
formData.value.studentName = '';
formData.value.phone = '';
formData.value.grade = '';
formData.value.memo = '';
formData.value.region = defaultRegionText.value;
} catch (err) {
console.error('Webhook 전송 에러:', err);
isModalOpen.value = true;
formData.value.studentName = '';
formData.value.phone = '';
formData.value.grade = '';
formData.value.memo = '';
formData.value.region = defaultRegionText.value;
} finally {
isSubmitting.value = false;
}
};
// 탭/과목 전환 시 영문 slug 라우팅 변경
const switchTarget = (newTargetSlug) => {
router.push(`/${regionInfo.value.sidoSlug}/${regionInfo.value.sigunguSlug}/${regionInfo.value.dongSlug}/${newTargetSlug}/${currentSubject.value.slug}`);
};
const switchSubject = (newSubjectSlug) => {
router.push(`/${regionInfo.value.sidoSlug}/${regionInfo.value.sigunguSlug}/${regionInfo.value.dongSlug}/${currentTarget.value.slug}/${newSubjectSlug}`);
};
// 하단 버튼 높이를 기준으로 상단 버튼 height 동기화 (모든 반응형 및 일반 화면 대응)
const bottomActionBtn = ref(null);
const actionBtnHeight = ref('');
const updateActionBtnHeight = () => {
if (bottomActionBtn.value) {
const rect = bottomActionBtn.value.getBoundingClientRect();
if (rect.height > 0) {
actionBtnHeight.value = `${rect.height}px`;
}
}
};
let actionBtnResizeObserver = null;
onMounted(() => {
nextTick(() => {
updateActionBtnHeight();
if (bottomActionBtn.value && typeof ResizeObserver !== 'undefined') {
actionBtnResizeObserver = new ResizeObserver(() => {
updateActionBtnHeight();
});
actionBtnResizeObserver.observe(bottomActionBtn.value);
}
window.addEventListener('resize', updateActionBtnHeight);
});
});
onUnmounted(() => {
if (actionBtnResizeObserver) {
actionBtnResizeObserver.disconnect();
}
window.removeEventListener('resize', updateActionBtnHeight);
});
watch([() => route.params], () => {
window.scrollTo({ top: 0, behavior: 'smooth' });
nextTick(() => {
updateActionBtnHeight();
});
});
</script>
<style scoped>
/* 참고 사이트 (townmoving.xyz) 완벽 대응 CSS */
.post-page {
background-color: var(--bg-primary);
color: var(--text-primary);
min-height: 100vh;
}
.site-header {
background: rgba(255, 255, 255, 0.98);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--border-color);
position: sticky;
top: 0;
z-index: 100;
padding: 12px 0;
}
.site-header-inner {
display: flex;
align-items: center;
justify-content: space-between;
}
.brand {
display: flex;
align-items: center;
gap: 8px;
font-size: 1.35rem;
font-weight: 900;
color: var(--text-primary);
}
.brand-mark {
background: var(--color-primary);
color: #fff;
font-size: 0.72rem;
font-weight: 900;
padding: 3px 6px;
border-radius: 4px;
}
.header-location-chip {
font-size: 0.88rem;
font-weight: 700;
color: var(--color-primary);
background: var(--color-primary-subtle);
padding: 4px 12px;
border-radius: var(--radius-full);
border: 1px solid var(--border-primary);
}
.btn-sm {
padding: 8px 18px;
font-size: 0.9rem;
}
/* 브레드크럼 */
.breadcrumb {
padding: 14px 0 6px;
}
.breadcrumb ol {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
font-size: 13.5px;
color: var(--text-muted);
list-style: none;
}
.breadcrumb a {
color: var(--text-secondary);
transition: color 0.15s;
}
.breadcrumb a:hover {
color: var(--color-primary);
}
.breadcrumb .sep {
color: #cbd5e1;
}
.breadcrumb .current {
color: var(--color-primary);
font-weight: 700;
}
/* 메인 포스트 쉘 */
.post-shell {
max-width: 900px;
margin: 0 auto;
padding: 16px 20px 60px;
}
/* 상단 뱃지 */
.post-badges {
display: flex;
gap: 8px;
margin-bottom: 12px;
flex-wrap: wrap;
}
.badge-item {
padding: 4px 12px;
border-radius: 6px;
font-size: 12.5px;
font-weight: 700;
}
.badge-item.loc {
background: var(--color-primary-subtle);
color: var(--color-primary);
border: 1px solid var(--border-primary);
}
.badge-item.cat {
background: var(--bg-secondary);
color: var(--text-secondary);
border: 1px solid var(--border-color);
}
/* 포스트 헤더 (h1 -> 메타 키워드 태그 -> h2 -> 일반 본문 글) */
.post-header {
margin-bottom: 24px;
}
.post-header h1 {
font-size: 26px;
font-weight: 800;
line-height: 1.35;
color: var(--text-primary);
margin-bottom: 12px;
letter-spacing: -0.02em;
}
.post-meta-keywords {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 14px;
}
.meta-kw-chip {
display: inline-flex;
align-items: center;
padding: 4px 10px;
border-radius: 6px;
font-size: 12px;
font-weight: 700;
background: var(--bg-secondary);
color: var(--text-secondary);
border: 1px solid var(--border-color);
}
.meta-kw-chip.primary {
background: var(--color-primary-subtle);
color: var(--color-primary);
border-color: var(--border-primary);
}
.post-lead-h2 {
font-size: 18px;
font-weight: 800;
line-height: 1.4;
color: var(--text-primary);
margin-bottom: 8px;
letter-spacing: -0.015em;
}
.post-header p,
.post-lead-text {
font-size: 14.5px;
color: var(--text-secondary);
line-height: 1.65;
}
.post-lead-text strong {
color: var(--text-primary);
font-weight: 700;
}
/* 빠른 액션 바 */
.post-action-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
margin-bottom: 18px;
}
.post-action {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 18px;
border-radius: 12px;
text-decoration: none;
transition: all 0.2s ease;
box-sizing: border-box;
min-height: 68px;
}
.post-action.orange {
background: var(--color-primary);
border: 1.5px solid transparent;
color: #ffffff;
box-shadow: 0 4px 14px var(--color-primary-glow);
}
.post-action.orange:hover {
background: var(--color-primary-light);
transform: translateY(-2px);
}
.post-action.outline {
background: #ffffff;
border: 1.5px solid var(--border-color);
color: var(--text-primary);
box-shadow: var(--shadow-sm);
}
.post-action.outline:hover {
border-color: var(--color-primary);
color: var(--color-primary);
transform: translateY(-2px);
}
.action-icon {
font-size: 1.4rem;
}
.post-action strong {
display: block;
font-size: 14.5px;
font-weight: 800;
line-height: 1.3;
}
.post-action span {
font-size: 12px;
opacity: 0.9;
}
/* 긴급 공지 박스 */
.post-notice {
background: #fffbf6;
border-left: 4px solid var(--color-primary);
border-radius: 8px;
padding: 14px 18px;
margin-bottom: 24px;
box-shadow: var(--shadow-sm);
}
.post-notice p {
font-size: 13.5px;
color: var(--text-primary);
line-height: 1.6;
margin-bottom: 4px;
}
.post-notice small {
font-size: 12px;
color: var(--text-muted);
}
/* 메인 히어로 미디어 */
.post-hero-media {
margin: 0 0 24px;
}
.hero-img-box {
position: relative;
max-width: 480px;
margin: 0 auto;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.1);
border: 1px solid var(--border-color);
}
.poster-img {
width: 100%;
height: auto;
display: block;
}
.hero-img-tag {
position: absolute;
top: 14px;
right: 14px;
background: rgba(255, 255, 255, 0.95);
border: 1.5px solid var(--color-primary);
color: var(--color-primary);
font-weight: 800;
font-size: 12px;
padding: 4px 12px;
border-radius: var(--radius-full);
}
/* 학년 전환 탭 */
.target-switch-bar {
display: flex;
justify-content: center;
gap: 12px;
margin-bottom: 28px;
}
.target-tab-btn {
padding: 10px 24px;
border-radius: var(--radius-full);
background: #ffffff;
border: 1.5px solid var(--border-color);
color: var(--text-secondary);
font-size: 14px;
font-weight: 700;
box-shadow: var(--shadow-sm);
transition: all 0.2s;
}
.link-div {
display: flex;
justify-content: center;
align-items: center;
padding: 18px 0 30px;
width: 100%;
}
.btn-3d-interactive {
display: inline-flex;
align-items: center;
justify-content: center;
background: #1AAF5D;
color: #ffffff;
border-radius: 2.25rem;
box-shadow: 0 6px 0 #0A7237, 0 10px 22px rgba(10, 114, 55, 0.25);
text-shadow: 0 1.5px 0 #0A7237;
padding: 22px 36px;
width: 90%;
max-width: 500px;
text-decoration: none;
cursor: pointer;
box-sizing: border-box;
transform: translateY(0px);
transition: background 200ms ease, box-shadow 200ms ease, transform 200ms cubic-bezier(0.680, -0.550, 0.265, 1.650);
user-select: none;
}
.btn-3d-interactive:hover {
background: #169E53;
box-shadow: 0 2px 0 #08582B, 0 4px 10px rgba(10, 114, 55, 0.2);
transform: translateY(4px);
}
.btn-3d-interactive:active {
transform: translateY(6px);
box-shadow: 0 0 0 #08582B, inset 0 2px 4px rgba(0, 0, 0, 0.2);
}
.btn-3d-text-wrap {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
}
.btn-3d-text {
font-size: 25px;
font-weight: 800;
letter-spacing: -0.02em;
font-family: inherit;
color: #ffffff;
line-height: 1;
white-space: nowrap;
text-align: center;
}
.text-highlight-yellow {
color: #FFF275;
}
.btn-3d-cursor {
position: absolute;
left: calc(100% + 13px);
top: 50%;
transform: translateY(-50%) translate3d(0, -1px, 0);
display: flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.35));
pointer-events: none;
transition: transform 250ms cubic-bezier(0.34, 1.56, 0.64, 1);
flex-shrink: 0;
}
.cursor-icon {
width: 100%;
height: 100%;
display: block;
}
/* Hover 시: 마우스 커서가 살짝 밑으로 콕 내려가는 모션 효과 */
.btn-3d-interactive:hover .btn-3d-cursor {
transform: translateY(-50%) translate3d(0, 3.5px, 0) scale(0.96);
}
.btn-3d-interactive:active .btn-3d-cursor {
transform: translateY(-50%) translate3d(0, 5.5px, 0) scale(0.9);
}
.target-tab-btn.active {
background: var(--color-primary);
color: #fff;
border-color: var(--color-primary);
box-shadow: 0 4px 14px var(--color-primary-glow);
}
/* 대표 지역 요약 섹션 */
.post-summary {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 14px;
padding: 24px;
margin-bottom: 32px;
}
.post-summary h2 {
font-size: 18px;
font-weight: 800;
margin-bottom: 8px;
color: var(--text-primary);
}
.post-summary p {
font-size: 14px;
color: var(--text-secondary);
line-height: 1.6;
margin-bottom: 16px;
}
.post-summary dl {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
border-top: 1px solid var(--border-color);
padding-top: 14px;
margin: 0;
}
.post-summary dt {
font-size: 12px;
color: var(--text-muted);
margin-bottom: 2px;
}
.post-summary dd {
font-size: 14px;
font-weight: 700;
color: var(--text-primary);
margin: 0;
}
/* 상단 스트립 */
.post-strip {
margin-bottom: 36px;
}
.post-strip h2 {
font-size: 18px;
font-weight: 800;
margin-bottom: 14px;
color: var(--text-primary);
}
.rowx {
display: flex;
gap: 12px;
overflow-x: auto;
padding-bottom: 8px;
}
.rowx::-webkit-scrollbar {
height: 5px;
}
.rowx::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
}
.pcitem {
flex: 0 0 160px;
background: #ffffff;
border: 1.5px solid var(--border-color);
border-radius: 14px;
padding: 10px;
cursor: pointer;
box-shadow: var(--shadow-sm);
transition: all 0.2s ease;
}
.pclink {
display: block;
color: inherit;
text-decoration: none;
}
.pcitem:hover {
border-color: var(--color-primary);
transform: translateY(-2px);
}
.pcitem.active {
border-color: var(--color-primary);
background: var(--color-primary-subtle);
box-shadow: 0 4px 12px var(--color-primary-glow);
}
.pcimg-wrap {
position: relative;
width: 100%;
aspect-ratio: 1 / 1;
border-radius: 10px;
overflow: hidden;
background: var(--color-primary);
margin-bottom: 8px;
}
.pcimg {
width: 100%;
height: 100%;
object-fit: cover;
}
.selected-badge {
position: absolute;
bottom: 4px;
right: 4px;
background: var(--color-primary);
color: #fff;
font-size: 10px;
font-weight: 800;
padding: 1px 6px;
border-radius: 999px;
}
.pcname {
font-size: 13px;
font-weight: 700;
text-align: center;
color: var(--text-primary);
}
/* 지역 플레이스 카드 그리드 (참고 사이트 1:1 구현) */
.post-places {
margin-bottom: 36px;
}
.section-heading {
margin-bottom: 16px;
}
.section-heading span {
display: inline-block;
font-size: 11px;
font-weight: 800;
color: var(--color-primary);
letter-spacing: 0.08em;
text-transform: uppercase;
margin-bottom: 4px;
}
.section-heading h2 {
font-size: 20px;
font-weight: 800;
color: var(--text-primary);
}
.place-grid {
display: flex;
flex-direction: column;
gap: 14px;
}
.place-card {
display: flex;
flex-direction: column;
gap: 10px;
background: #ffffff;
border: 1.5px solid var(--border-color);
border-radius: 14px;
padding: 16px 18px;
box-shadow: var(--shadow-sm);
transition: all 0.2s ease;
}
.place-card:hover {
border-color: var(--color-primary);
box-shadow: 0 4px 16px rgba(255, 94, 0, 0.1);
}
.place-top-bar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.place-rank-badge {
display: inline-flex;
align-items: center;
font-size: 11.5px;
font-weight: 800;
background: var(--color-primary-subtle);
color: var(--color-primary);
border: 1px solid var(--border-primary);
padding: 2px 8px;
border-radius: 4px;
}
.place-cat-tag {
font-size: 12px;
color: var(--text-muted);
font-weight: 500;
}
.place-main {
width: 100%;
}
.place-main h3 {
font-size: 15.5px;
font-weight: 800;
color: var(--text-primary);
margin-bottom: 4px;
line-height: 1.4;
}
.place-addr {
font-size: 13px;
color: var(--color-primary);
font-weight: 600;
margin-bottom: 4px;
}
.place-kw {
font-size: 12px;
color: var(--text-muted);
margin-bottom: 6px;
}
.place-desc {
font-size: 13.5px;
color: var(--text-secondary);
line-height: 1.5;
margin: 0;
}
.place-links {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
margin-top: 4px;
}
.map-link {
display: inline-flex;
align-items: center;
justify-content: center;
height: 34px;
padding: 0 16px;
border-radius: 8px;
font-size: 12.5px;
font-weight: 700;
text-decoration: none;
flex: 0 0 auto;
min-width: 90px;
transition: all 0.2s ease;
}
.map-link.naver {
background: #03c75a;
color: #ffffff;
border: 1px solid #03c75a;
}
.map-link.naver:hover {
background: #02b351;
}
.map-link.google {
background: #ffffff;
border: 1.5px solid var(--border-color);
color: var(--text-secondary);
}
.map-link.google:hover {
border-color: var(--color-primary);
color: var(--color-primary);
}
/* 학교 분석 섹션 */
.schools-section {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 14px;
padding: 24px;
margin-bottom: 36px;
}
.schools-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 14px;
}
.school-card {
background: #ffffff;
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 16px;
}
.school-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.school-tag {
font-size: 11px;
font-weight: 800;
color: var(--color-primary);
background: var(--color-primary-subtle);
padding: 2px 6px;
border-radius: 4px;
}
.school-header h3 {
font-size: 15px;
font-weight: 800;
color: var(--text-primary);
}
.school-desc {
font-size: 13px;
color: var(--text-secondary);
line-height: 1.5;
margin-bottom: 10px;
}
.school-tags {
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.school-tags span {
font-size: 11.5px;
color: var(--text-muted);
background: var(--bg-secondary);
padding: 2px 6px;
border-radius: 4px;
}
/* FAQ 섹션 */
.faq-section {
margin-bottom: 36px;
}
.faq-accordion-wrap {
display: flex;
flex-direction: column;
gap: 8px;
}
.faq-row {
border: 1px solid var(--border-color);
border-radius: 10px;
overflow: hidden;
background: #ffffff;
}
.faq-button {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 18px;
font-size: 14.5px;
font-weight: 700;
color: var(--text-primary);
background: #ffffff;
text-align: left;
border: none;
cursor: pointer;
}
.faq-button.open {
color: var(--color-primary);
background: var(--color-primary-subtle);
}
.faq-arrow {
font-size: 10px;
color: var(--text-muted);
}
.faq-panel {
padding: 14px 18px;
border-top: 1px solid var(--border-color);
background: #fafafa;
}
.faq-panel p {
font-size: 13.5px;
color: var(--text-secondary);
line-height: 1.6;
margin: 0;
}
/* Pager 내부 링크 클러스터 */
.pager {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 36px;
padding-top: 20px;
border-top: 1px solid var(--border-color);
}
.pager-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.pager-group-title {
font-size: 13.5px;
font-weight: 800;
color: var(--text-primary);
}
.pager-links-wrap {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.pager-link {
display: inline-block;
padding: 8px 14px;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
font-size: 13px;
font-weight: 600;
color: var(--text-secondary);
text-decoration: none;
transition: all 0.15s;
}
.pager-link:hover {
border-color: var(--color-primary);
color: var(--color-primary);
background: var(--color-primary-subtle);
}
.pager-link.active {
background: var(--color-primary);
color: #ffffff;
border-color: var(--color-primary);
}
.pager-next {
font-weight: 700;
color: var(--color-primary);
background: var(--color-primary-subtle);
border-color: var(--border-primary);
}
/* 하단 가로형 과목 이미지 캐러셀 (네이버 가로 멀티 썸네일 최적화) */
.bottom-carousel-section {
margin-bottom: 36px;
padding: 22px;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 16px;
}
.carousel-guide-text {
font-size: 13.5px;
color: var(--text-secondary);
margin-bottom: 16px;
line-height: 1.5;
}
.horizontal-carousel-track {
display: flex;
flex-direction: row;
gap: 12px;
overflow-x: auto;
padding-bottom: 8px;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
}
.horizontal-carousel-track::-webkit-scrollbar {
height: 6px;
}
.horizontal-carousel-track::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
}
.h-carousel-card {
flex: 0 0 165px;
scroll-snap-align: start;
background: #ffffff;
border: 1.5px solid var(--border-color);
border-radius: 14px;
overflow: hidden;
box-shadow: var(--shadow-sm);
transition: all 0.2s ease;
}
.h-carousel-card.current {
border-color: var(--color-primary);
box-shadow: 0 4px 12px var(--color-primary-glow);
}
.h-carousel-card:hover {
border-color: var(--color-primary);
transform: translateY(-2px);
}
.h-carousel-link {
display: block;
text-decoration: none;
color: inherit;
}
.h-carousel-img-box {
position: relative;
width: 100%;
aspect-ratio: 1 / 1;
background: var(--color-primary);
overflow: hidden;
}
.h-carousel-img-box img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.h-carousel-badge {
position: absolute;
top: 6px;
left: 6px;
background: rgba(15, 23, 42, 0.8);
color: #ffffff;
font-size: 10.5px;
font-weight: 700;
padding: 2px 7px;
border-radius: 999px;
}
.h-carousel-body {
padding: 10px 12px;
}
.h-carousel-body h3 {
font-size: 13.5px;
font-weight: 800;
color: var(--text-primary);
margin-bottom: 4px;
line-height: 1.3;
}
.h-carousel-body p {
font-size: 11.5px;
color: var(--text-secondary);
line-height: 1.4;
margin: 0;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* 빠른 상담 리소스 링크 */
.post-resource-links {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
margin-bottom: 40px;
}
.post-resource-link {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 14px;
background: #ffffff;
border: 1px solid var(--border-color);
border-radius: 12px;
text-decoration: none;
box-shadow: var(--shadow-sm);
transition: all 0.2s;
}
.post-resource-link:hover {
border-color: var(--color-primary);
transform: translateY(-2px);
}
.post-resource-thumb {
flex: 0 0 38px;
height: 38px;
border-radius: 8px;
overflow: hidden;
background: var(--color-primary);
}
.post-resource-thumb img {
width: 100%;
height: 100%;
object-fit: cover;
}
.post-resource-title {
flex: 1;
font-size: 13.5px;
font-weight: 700;
color: var(--text-primary);
line-height: 1.4;
}
.post-resource-arrow {
font-size: 16px;
color: var(--text-muted);
font-style: normal;
}
/* 상담 신청 폼 */
.consult-form-wrap {
padding: 30px 0;
width: 100%;
box-sizing: border-box;
}
.form-container {
width: 100%;
max-width: 100%;
box-sizing: border-box;
overflow: hidden;
padding: 36px 32px;
border-radius: 20px;
border: 1.5px solid var(--border-primary);
background: linear-gradient(180deg, #ffffff 0%, #fffbf6 100%);
box-shadow: 0 10px 30px rgba(255, 94, 0, 0.08);
}
.form-header {
text-align: center;
margin-bottom: 24px;
}
.form-header h2 {
font-size: 22px;
font-weight: 800;
margin-bottom: 6px;
}
.form-header p {
font-size: 14px;
color: var(--text-secondary);
}
.submit-form {
width: 100%;
max-width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 14px;
}
.form-row {
width: 100%;
max-width: 100%;
box-sizing: border-box;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
min-width: 0;
}
.form-group {
width: 100%;
max-width: 100%;
box-sizing: border-box;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4px;
}
.form-group label {
font-size: 13px;
font-weight: 700;
color: var(--text-primary);
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
max-width: 100%;
box-sizing: border-box;
display: block;
padding: 11px 14px;
border-radius: 10px;
background: #ffffff;
border: 1.5px solid var(--border-color);
color: var(--text-primary);
font-family: inherit;
font-size: 14px;
outline: none;
box-shadow: var(--shadow-sm);
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
border-color: var(--color-primary);
}
.input-region {
background: var(--bg-secondary);
color: var(--color-primary);
font-weight: 700;
cursor: pointer;
transition: all 0.2s ease;
}
.input-region:focus {
background: #ffffff;
color: var(--text-primary);
border-color: var(--color-primary);
cursor: text;
}
.btn-submit {
padding: 15px;
font-size: 16px;
font-weight: 800;
width: 100%;
margin-top: 4px;
}
.form-privacy-note {
text-align: center;
font-size: 12px;
color: var(--text-muted);
}
/* 푸터 */
.site-footer {
border-top: 1px solid var(--border-color);
background: var(--bg-secondary);
padding: 40px 0 24px;
text-align: center;
}
.footer-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.footer-logo {
display: flex;
align-items: center;
gap: 8px;
font-size: 1.2rem;
font-weight: 900;
color: var(--text-primary);
}
.footer-text {
font-size: 13px;
color: var(--text-secondary);
}
.footer-biz-info {
margin: 12px 0 6px;
display: flex;
flex-direction: column;
gap: 4px;
align-items: center;
}
.biz-line {
font-size: 12px;
color: var(--text-muted);
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 8px;
margin: 0;
}
.biz-line .divider {
color: var(--border-color);
}
.biz-link {
color: var(--text-secondary);
text-decoration: underline;
}
.footer-copy {
font-size: 12px;
color: var(--text-muted);
}
/* 반응형 미디어 쿼리 최적화 */
@media (max-width: 768px) {
.post-shell {
padding: 12px 16px 48px;
word-break: keep-all;
}
.post-header h1 {
font-size: 21px;
line-height: 1.35;
letter-spacing: -0.03em;
}
.post-header p {
font-size: 13.5px;
}
.post-action-row {
grid-template-columns: 1fr;
gap: 10px;
}
.post-action {
padding: 13px 16px;
min-height: 66px;
}
.target-switch-bar {
width: 100%;
gap: 8px;
}
.target-tab-btn {
flex: 1;
text-align: center;
padding: 10px 14px;
font-size: 13.5px;
}
.link-div {
padding: 16px 0 24px;
}
.btn-3d-interactive {
padding: 22px 36px;
width: 100%;
max-width: 100%;
border-radius: 2.25rem;
box-sizing: border-box;
}
.btn-3d-text {
font-size: 25px;
white-space: nowrap;
text-align: center;
}
.btn-3d-cursor {
width: 22px;
height: 22px;
left: calc(100% + 13px);
}
.post-summary {
padding: 18px 16px;
border-radius: 12px;
}
.post-summary dl {
grid-template-columns: 1fr;
gap: 10px;
}
.post-strip {
margin-bottom: 28px;
}
.rowx {
gap: 10px;
-webkit-overflow-scrolling: touch;
scroll-snap-type: x mandatory;
padding-bottom: 6px;
}
.pcitem {
flex: 0 0 140px;
scroll-snap-align: start;
padding: 8px;
}
.post-places {
margin-bottom: 28px;
}
.place-card {
padding: 14px 16px;
gap: 8px;
}
.place-links {
flex-direction: row;
width: 100%;
gap: 8px;
margin-top: 4px;
}
.map-link {
flex: 1;
height: 34px;
padding: 0 12px;
font-size: 12px;
}
.schools-section {
padding: 18px 16px;
margin-bottom: 28px;
}
.schools-grid {
grid-template-columns: 1fr;
gap: 10px;
}
.post-resource-links {
grid-template-columns: 1fr;
gap: 10px;
margin-bottom: 30px;
}
/* 모바일 과목 및 지역 목록 버튼 가로 100% 꽉 차게 확장 */
.pager {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
margin-bottom: 28px;
}
.pager-link {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 12px 16px;
font-size: 14px;
text-align: center;
box-sizing: border-box;
border-radius: 10px;
}
.post-resource-link {
padding: 12px 14px;
}
.consult-form-wrap {
padding: 16px 0;
}
.form-container {
padding: 24px 18px;
border-radius: 16px;
}
.form-header h2 {
font-size: 18.5px;
line-height: 1.4;
word-break: keep-all;
}
.form-header p {
font-size: 13px;
}
.form-row {
grid-template-columns: 1fr;
gap: 12px;
}
.form-group input,
.form-group select,
.form-group textarea {
font-size: 15px;
padding: 12px 14px;
}
.btn-submit {
padding: 16px;
font-size: 15.5px;
}
}
@media (max-width: 480px) {
.post-shell {
padding: 10px 12px 40px;
}
.post-header h1 {
font-size: 19px;
}
.hero-img-box {
border-radius: 14px;
}
.form-container {
padding: 20px 14px;
}
.pcitem {
flex: 0 0 125px;
}
.pcname {
font-size: 12px;
}
}
@media (max-width: 458px) {
.btn-3d-interactive {
padding: 16px 20px;
}
.btn-3d-text {
font-size: clamp(14px, 5.2vw, 24px);
letter-spacing: -0.035em;
}
.btn-3d-cursor {
width: 19px;
height: 19px;
left: calc(100% + 12px);
}
}
@media (max-width: 360px) {
.btn-3d-interactive {
padding: 14px 14px;
}
.btn-3d-text {
font-size: 13.5px;
letter-spacing: -0.045em;
}
.btn-3d-cursor {
width: 16px;
height: 16px;
left: calc(100% + 9px);
}
}
/* 상담 신청 완료 모달 안내창 스타일 */
.consult-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(15, 23, 42, 0.65);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
display: flex;
align-items: center;
justify-content: center;
z-index: 99999;
padding: 20px;
}
.consult-modal-card {
background: #ffffff;
border-radius: 24px;
padding: 38px 28px 28px;
max-width: 380px;
width: 100%;
text-align: center;
box-shadow: 0 25px 50px -12px rgba(15, 23, 42, 0.25);
animation: modalPop 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes modalPop {
from { opacity: 0; transform: scale(0.92) translateY(10px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
.consult-modal-icon {
width: 68px;
height: 68px;
margin: 0 auto 20px;
background: rgba(255, 94, 0, 0.1);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.consult-modal-title {
font-size: 20px;
font-weight: 800;
color: #0f172a;
margin: 0 0 10px;
line-height: 1.4;
word-break: keep-all;
}
.consult-modal-desc {
font-size: 15px;
color: #64748b;
margin: 0 0 28px;
line-height: 1.5;
word-break: keep-all;
}
.consult-modal-btn {
width: 100%;
padding: 15px;
background: linear-gradient(135deg, #ff5e00 0%, #ff7a29 100%);
color: #ffffff;
border: none;
border-radius: 14px;
font-size: 16px;
font-weight: 700;
cursor: pointer;
box-shadow: 0 8px 18px rgba(255, 94, 0, 0.3);
transition: all 0.2s ease;
}
.consult-modal-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 24px rgba(255, 94, 0, 0.4);
}
</style>