현대 쏘나타
123가 4567

- 예약 날짜
- 코스
- 시그니처 코스
- 지점명
- 카앤쿡 창원점
웹앱(app/) 전용 공통 스타일입니다. 수정은 app/css/common.css (토큰 · 타이포그래피 · 컴포넌트) / app/css/layout.css (헤더 · 탭바 · 전체메뉴 · 우측 다운로드)에서 합니다. 이 페이지는 납품 전 제거합니다.
PC: inner 1220px 안에서 좌측 웹앱 화면(768px) + 우측 앱 다운로드 (space-between). 1280px 이하에서는 우측 영역을 숨기고 웹앱 화면만 가운데 정렬합니다.
<body class="app-body">
<div class="app-wrap"> ← inner 1220 / space-between
<div class="app-frame"> ← 웹앱 화면 768
<header class="app-header"> ← sticky (main | sub)
<main class="app-main"> ← 페이지 본문
<nav class="app-tabbar"> ← sticky 하단 탭바
</div>
<aside class="app-side"> ← 앱 다운로드 (sticky, 1280 이하 숨김)
</div>
<div class="app-layer app-menu"> ← 전체메뉴 (프레임 위치에 맞춰 열림)
| 변수 | 설명 |
|---|---|
| $root / $app | 사이트 루트 / 웹앱 루트 상대경로 (app/index.php → '../' / './') |
| $pageId | 탭바 활성 (home · reserve · car · benefit · my) · 전체메뉴 활성 |
| $headerType | 'main' 메뉴·로고·알림 / 'sub' 뒤로가기·타이틀(h1) / 'none' |
| $headerTitle · $backHref | sub 헤더 타이틀 · 뒤로가기 기본 경로 |
| $useTabbar | 하단 탭바 노출 (기본 true · 예약 단계 등 하단 고정 버튼 화면은 false) |
| $hasNewNoti | 알림 아이콘 새 소식 점 |
| $pageCss · $pageJs · $useSwiper | 페이지 전용 CSS/JS (app 기준 경로), 스와이퍼 사용 |
브랜드소개 · 프로그램 · 점포안내는 웹앱 페이지, 시공사례 · Q&A 는 'site' => true 로 공홈 연결 (↗ 아이콘).
app/index.php?state= 값으로 확인합니다.
크기 · 굵기 · 행간 · 자간은 아래 클래스로만 지정합니다. 컴포넌트 CSS 에 font-size 를 쓰지 않고, 마크업에 컴포넌트 클래스 + 타이포 클래스를 함께 붙입니다. 태그(h1~h6)는 문서 구조대로 쓰고 .h1 ~ .h4 는 크기 이름입니다. (자간 모두 0)
내 차를 아끼는 습관
내 차를 아끼는 습관
내 차를 아끼는 습관
홍예린 고객님, 예약하신 케어가 있어요.
2000P
사용가능한 혜택
카앤쿡 동탄점
스팀 손세차부터 실내 클리닝까지 세심하게 관리합니다.
최근 관리 이력이 없습니다.
묵은 오염을 집중 관리
예약 상세 보기
인증요청
차량 관리
MY CAR · M
내·외부 스팀 손세차
홈 · 예약 · 내 차
색 · 굵기 유틸 : .static1-txt .gray6-txt .gray7-txt .gray8-txt .white-txt .red-txt / .weight400 ~ .weight700
<h2 class="h3">사용가능한 혜택</h2>
<a class="square-btn full main-btn btn-l" href="#none">예약 상세 보기</a>
<p class="body-small gray6-txt">색 · 굵기 유틸 : .static1-txt .gray6-txt .gray7-txt .gray8-txt .white-txt .red-txt / .weight400 ~ .weight700</p>--color-gray5 (#A3A3A3) 이하 밝은 회색은 흰 배경 대비 부족 → 텍스트에 쓰지 않습니다. 텍스트 최소 회색은 --color-gray6.
브랜드 · 배경 · 라인
그레이
상태 (컬러칩 외)
inc/icons.php 인라인 SVG. <?= icon('이름', 크기, '클래스') ?> · 색은 부모 color(currentColor)를 따릅니다. 추가는 $icons 배열에 path 만 넣으면 됩니다.
모양(.square-btn .ico-btn .txt-btn) + 색(.main-btn .dark-btn .sub-btn .line-btn .gray-btn) 조합. 이동은 <a>, 동작은 <button type="button">.
<a class="square-btn full main-btn btn-l" href="#none">기본 52 (full)</a>
<div class="btn-list">
<button type="button" class="square-btn medium main-btn btn-m">medium 48</button>
<button type="button" class="square-btn medium dark-btn btn-m">dark</button>
<button type="button" class="square-btn medium sub-btn btn-m">sub</button>
<button type="button" class="square-btn medium line-btn btn-m">line</button>
<button type="button" class="square-btn medium gray-btn btn-m">gray</button>
</div>
<div class="btn-list">
<button type="button" class="square-btn small line-btn btn-s">small 40</button>
<button type="button" class="square-btn medium main-btn btn-m" disabled>비활성</button>
</div><div class="btn-list full">
<button type="button" class="square-btn line-btn btn-l">예약 취소</button>
<a class="square-btn main-btn btn-l" href="#none">예약 변경</a>
</div><a class="txt-btn btn-s" href="#none">차량 관리<span class="sr-only"> - 현대 쏘나타</span><?= icon('chevron', 16) ?></a>
<div class="btn-list">
<button type="button" class="ico-btn" aria-label="전체 메뉴 열기"><?= icon('menu') ?></button>
<a class="ico-btn" href="#none" aria-label="알림"><?= icon('bell') ?></a>
<button type="button" class="ico-btn" aria-label="닫기"><?= icon('close') ?></button>
</div>모든 입력 요소에 <label for> 와 name 필수. 글자 크기 16px 미만 금지(iOS 확대). 오류는 .error + aria-invalid + aria-describedby.
예약 안내 문자가 발송됩니다.
인증번호가 일치하지 않습니다.
<div class="input-item">
<label class="caption-m input-item-label req" for="cpCarNum">차량번호<span class="sr-only">(필수)</span></label>
<input class="custom-input body-large" type="text" id="cpCarNum" name="car_number" placeholder="예) 123가 4567" required>
</div>
<div class="input-item">
<label class="caption-m input-item-label" for="cpPhone">휴대폰 번호</label>
<div class="input-wrap">
<input class="custom-input body-large" type="tel" id="cpPhone" name="phone" inputmode="numeric" autocomplete="tel" aria-describedby="cpPhoneInfo">
<button type="button" class="square-btn dark-btn btn-m">인증요청</button>
</div>
<p class="info-msg caption-m" id="cpPhoneInfo">예약 안내 문자가 발송됩니다.</p>
</div>
<div class="input-item">
<label class="caption-m input-item-label" for="cpCode">인증번호</label>
<input class="custom-input error body-large" type="text" id="cpCode" name="auth_code" inputmode="numeric" value="1234" aria-invalid="true" aria-describedby="cpCodeError">
<p class="error-msg caption-m" id="cpCodeError">인증번호가 일치하지 않습니다.</p>
</div>
<div class="input-item">
<label class="caption-m input-item-label" for="cpDisabled">비활성</label>
<input class="custom-input body-large" type="text" id="cpDisabled" name="disabled_sample" value="수정할 수 없음" disabled>
</div><div class="input-item">
<label class="caption-m input-item-label" for="cpSize">차량 크기</label>
<select class="custom-select body-large" id="cpSize" name="car_size">
<option value="">선택해주세요</option>
<option value="S">소형 (S)</option>
<option value="M">중형 (M)</option>
<option value="L">대형 · SUV (L)</option>
</select>
</div>
<div class="input-item">
<label class="caption-m input-item-label" for="cpMemo">요청사항</label>
<textarea class="custom-textarea body-large" id="cpMemo" name="memo" maxlength="300"></textarea>
</div><div class="check-list">
<div class="check-item"><input class="custom-checkbox" type="checkbox" id="cpAgree1" name="agree_terms" checked><label class="body-medium" for="cpAgree1">이용약관 동의</label></div>
<div class="check-item"><input class="custom-checkbox" type="checkbox" id="cpAgree2" name="agree_marketing"><label class="body-medium" for="cpAgree2">마케팅 수신 동의</label></div>
<div class="check-item"><input class="custom-checkbox" type="checkbox" id="cpAgree3" name="agree_disabled" disabled><label class="body-medium" for="cpAgree3">비활성</label></div>
</div>
<fieldset>
<legend class="caption-m input-item-label">결제 수단</legend>
<div class="check-list">
<div class="check-item"><input class="custom-radio" type="radio" id="cpPay1" name="pay" value="card" checked><label class="body-medium" for="cpPay1">카드</label></div>
<div class="check-item"><input class="custom-radio" type="radio" id="cpPay2" name="pay" value="membership"><label class="body-medium" for="cpPay2">회원권</label></div>
<div class="check-item"><input class="custom-radio" type="radio" id="cpPay3" name="pay" value="onsite" disabled><label class="body-medium" for="cpPay3">현장결제</label></div>
</div>
</fieldset>
<div class="check-item"><input class="custom-switch" type="checkbox" role="switch" id="cpPush" name="push" checked><label class="body-medium" for="cpPush">알림 받기</label></div><fieldset>
<legend class="sr-only">코스 선택</legend>
<ul class="select-card-list">
<li class="select-card">
<input type="radio" id="cpCourse1" name="course" value="daily" checked>
<label for="cpCourse1"><span class="h4">데일리</span><span class="body-small gray6-txt">60,000원부터</span></label>
</li>
<!-- 복사 -->
<li class="select-card">
<input type="radio" id="cpCourse2" name="course" value="signature">
<label for="cpCourse2"><span class="h4">시그니처</span><span class="body-small gray6-txt">90,000원부터</span></label>
</li>
<li class="select-card">
<input type="radio" id="cpCourse3" name="course" value="soldout" disabled>
<label for="cpCourse3"><span class="h4">리뉴</span><span class="body-small">예약 마감</span></label>
</li>
</ul>
</fieldset>영업중 · 09:00 - 20:00
영업종료 · 09:00 - 20:00
<div class="btn-list">
<span class="badge main caption-s">시공중</span>
<span class="badge confirm caption-s">예약확정</span>
<span class="badge caption-s">이용완료</span>
<span class="badge line caption-s">BEST</span>
<span class="badge cancel caption-s">예약취소</span>
<span class="badge main square caption-s">M</span>
</div>
<p class="body-small"><span class="state-txt open">영업중</span> · 09:00 - 20:00</p>
<p class="body-small"><span class="state-txt close">영업종료</span> · 09:00 - 20:00</p>[data-tab] 안의 [role="tab"](.active) ↔ .tab-content(.active). 방향키 ← → · Home · End 이동.
예약중 패널
이용완료 패널
취소 패널
<div data-tab>
<div class="tab-list" role="tablist" aria-label="예약 내역">
<button type="button" class="tab active btn-m" role="tab" id="cpRvTab1" aria-selected="true" aria-controls="cpRvPanel1">예약중</button>
<button type="button" class="tab btn-m" role="tab" id="cpRvTab2" aria-selected="false" aria-controls="cpRvPanel2" tabindex="-1">이용완료</button>
<button type="button" class="tab btn-m" role="tab" id="cpRvTab3" aria-selected="false" aria-controls="cpRvPanel3" tabindex="-1">취소</button>
</div>
<div class="tab-content active" role="tabpanel" id="cpRvPanel1" aria-labelledby="cpRvTab1" tabindex="0"><p class="body-small">예약중 패널</p></div>
<div class="tab-content" role="tabpanel" id="cpRvPanel2" aria-labelledby="cpRvTab2" tabindex="0"><p class="body-small">이용완료 패널</p></div>
<div class="tab-content" role="tabpanel" id="cpRvPanel3" aria-labelledby="cpRvTab3" tabindex="0"><p class="body-small">취소 패널</p></div>
</div>포인트 패널
쿠폰 패널
회원권 패널
<div data-tab>
<div class="seg-tab-list" role="tablist" aria-label="혜택">
<button type="button" class="tab active btn-s" role="tab" id="cpBnTab1" aria-selected="true" aria-controls="cpBnPanel1">포인트</button>
<button type="button" class="tab btn-s" role="tab" id="cpBnTab2" aria-selected="false" aria-controls="cpBnPanel2" tabindex="-1">쿠폰</button>
<button type="button" class="tab btn-s" role="tab" id="cpBnTab3" aria-selected="false" aria-controls="cpBnPanel3" tabindex="-1">회원권</button>
</div>
<div class="tab-content active" role="tabpanel" id="cpBnPanel1" aria-labelledby="cpBnTab1" tabindex="0"><p class="body-small">포인트 패널</p></div>
<div class="tab-content" role="tabpanel" id="cpBnPanel2" aria-labelledby="cpBnTab2" tabindex="0"><p class="body-small">쿠폰 패널</p></div>
<div class="tab-content" role="tabpanel" id="cpBnPanel3" aria-labelledby="cpBnTab3" tabindex="0"><p class="body-small">회원권 패널</p></div>
</div><dl class="info-list body-small">
<div><dt>예약 날짜</dt><dd><time datetime="2026-09-27T14:00">09.27 SAT 14:00</time></dd></div>
<div><dt>코스</dt><dd>시그니처 코스</dd></div>
<div><dt>지점명</dt><dd>카앤쿡 창원점</dd></div>
</dl><dl class="info-list inline body-small">
<div><dt>최근 관리</dt><dd><time datetime="2026-09-12">2026.09.12</time> · 4일전</dd></div>
<div><dt>다음 관리</dt><dd>약 10일 후 추천</dd></div>
</dl><ul class="dot-ul caption-m">
<li>예약 변경은 방문 하루 전까지 가능합니다.</li>
<li>차량 상태에 따라 작업 시간이 달라질 수 있습니다.</li>
</ul>
<ul class="link-list body-large">
<li><a href="#none">예약 내역<?= icon('chevron', 20) ?></a></li>
<li><a href="#none">시공 이력<?= icon('chevron', 20) ?></a></li>
<li><a href="#none">알림 설정<?= icon('chevron', 20) ?></a></li>
</ul>inc/components.php → mycarCard($car, $mode, $data, $opt). $mode : reserved · working · empty · first · revisit. 차량 이미지는 배경 투명 WebP(620×280 비율)로 받습니다.
현대 쏘나타
123가 4567

현대 쏘나타
123가 4567

현재 작업 상태
시공 중 · 약 40분 경과
등록된 차량이 없습니다.
차량을 등록해주세요.
현대 쏘나타
123가 4567

최근 관리 이력이 없습니다.
현대 쏘나타
123가 4567

<a class="search-banner" href="#none">
<span class="banner-txt">
<span class="banner-tit h4"><?= icon('search', 20) ?>내 차 맞춤관리 찾기</span>
<span class="banner-desc caption-m">차량 사이즈별 가격을 바로 확인하세요.</span>
</span>
<?= icon('chevron', 20) ?>
</a><ul class="benefit-box shadow-box">
<li><a href="#none"><?= icon('point', 20) ?><strong class="benefit-num h2">2000P</strong><span class="benefit-label body-small">포인트</span></a></li>
<li><a href="#none"><?= icon('coupon', 20) ?><strong class="benefit-num h2">1장</strong><span class="benefit-label body-small">사용 가능 쿠폰</span></a></li>
<li><a href="#none"><?= icon('membership', 20) ?><strong class="benefit-num h2">10개</strong><span class="benefit-label body-small">남은 회원권</span></a></li>
</ul><ul class="h-scroll">
<li>
<a class="program-card" href="#none">
<h4 class="program-tit h4">데일리<?= icon('chevron', 18) ?></h4>
<p class="program-desc body-small">일상 오염을 가볍게</p>
<p class="program-sub caption-m">내·외부 스팀 손세차</p>
<p class="program-price body-medium">60,000원부터</p>
</a>
</li>
<!-- 복사 -->
<li>
<a class="program-card" href="#none">
<h4 class="program-tit h4">시그니처<?= icon('chevron', 18) ?></h4>
<p class="program-desc body-small">세차에 보호와 위생까지</p>
<p class="program-sub caption-m">왁스·가죽·타이어 보호</p>
<p class="program-price body-medium">90,000원부터</p>
</a>
</li>
</ul><a class="recommend-card shadow-box" href="#none">
<div class="recommend-img"><img src="img/home-renew.webp" alt="리뉴 프로그램으로 관리한 차량" width="724" height="362" loading="lazy" decoding="async"></div>
<div class="recommend-body">
<h4 class="recommend-tit h3">리뉴</h4>
<p class="recommend-desc body-small">묵은 오염을 집중 관리</p>
<p class="recommend-price h3">280,000원부터</p>
<?= icon('chevron', 20) ?>
</div>
</a><ul class="store-list">
<li>
<a class="store-card shadow-box" href="#none">
<span class="store-img"><img src="img/store-thumb-01.webp" alt="" aria-hidden="true" width="140" height="112" loading="lazy" decoding="async"></span>
<div class="store-info">
<h4 class="store-name h4">카앤쿡 동탄점</h4>
<p class="store-addr body-small">경기도 화성시 동탄구 지산1길 25-5 1층</p>
<p class="store-time body-small"><span class="state-txt open">영업중</span> · 09:00 - 20:00</p>
</div>
</a>
</li>
</ul>inc/components.php → workStateBox($work, $tag). $work['step'] = 현재 단계 index (0 입고 완료 · 1 작업 준비 · 2 시공 중 · 3 작업 완료). 지난 단계 li.done, 현재 단계 li.current + aria-current="step".
현재 작업 상태
시공 중 · 약 40분 경과
<ol class="progress-step" aria-label="작업 진행 단계">
<li class="current" aria-current="step"><span class="step-dot" aria-hidden="true"></span><span class="step-txt body-small">입고 완료<span class="sr-only">(진행 중)</span></span></li>
<li><span class="step-dot" aria-hidden="true"></span><span class="step-txt body-small">작업 준비</span></li>
<li><span class="step-dot" aria-hidden="true"></span><span class="step-txt body-small">시공 중</span></li>
<li><span class="step-dot" aria-hidden="true"></span><span class="step-txt body-small">작업 완료</span></li>
</ol>
<ol class="progress-step" aria-label="작업 진행 단계">
<li class="done"><span class="step-dot" aria-hidden="true"><?= icon('check', 16) ?></span><span class="step-txt body-small">입고 완료<span class="sr-only">(완료)</span></span></li>
<li class="done"><span class="step-dot" aria-hidden="true"><?= icon('check', 16) ?></span><span class="step-txt body-small">작업 준비<span class="sr-only">(완료)</span></span></li>
<li class="done"><span class="step-dot" aria-hidden="true"><?= icon('check', 16) ?></span><span class="step-txt body-small">시공 중<span class="sr-only">(완료)</span></span></li>
<li class="current" aria-current="step"><span class="step-dot" aria-hidden="true"></span><span class="step-txt body-small">작업 완료<span class="sr-only">(진행 중)</span></span></li>
</ol>열기 [data-layer-open="시트id"] · 닫기 [data-layer-close] · ESC · 딤 클릭. 포커스 트랩 · 스크롤 잠금 · 닫으면 열었던 버튼으로 포커스 복귀. 마크업은 </main> 뒤에 둡니다.
<div class="app-layer bottom-sheet" id="cpSheet" data-layer inert>
<div class="app-wrap">
<div class="app-layer-area">
<div class="app-layer-dim" data-layer-close></div>
<div class="sheet-panel" role="dialog" aria-modal="true" aria-labelledby="cpSheetTit2">
<div class="sheet-head">
<h2 class="h3" id="cpSheetTit2">차량 선택</h2>
<button type="button" class="ico-btn" data-layer-close aria-label="닫기"><?= icon('close') ?></button>
</div>
<div class="sheet-body"> … </div>
<div class="sheet-foot"><button type="button" class="square-btn full main-btn btn-l">선택 완료</button></div>
</div>
</div>
</div>
</div>
<div class="empty-box shadow-box">
<?= icon('place', 40) ?>
<p class="empty-tit h4">가까운 매장을 찾지 못했어요.</p>
<p class="empty-desc body-small">위치 권한을 허용하거나 전체 매장을 확인해주세요.</p>
<a class="square-btn small line-btn btn-s" href="#none">전체 매장 보기</a>
</div>