/* 모든 페이지가 공유하는 커스텀 스타일.
   Tailwind 유틸리티로 표현되지 않는 것만 여기 둔다 (브라우저 프레임, 플레이스홀더, 마퀴 등).
   body 배경 같은 토큰성 값은 CSS 가 아니라 Tailwind 클래스(bg-ivory)로 붙인다 —
   Play CDN 이 주입하는 <style> 과의 순서 다툼을 피하기 위해서다. */

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}
::selection { background: rgba(62,207,142,.3); color: #26231b; }
:focus-visible { outline: 2px solid #18b476; outline-offset: 3px; border-radius: 4px; }

/* 브라우저 프레임 — 목업에서 가져온 유일한 구조. 실제 스크린샷이 들어갈 자리를
   프레임이 잡아주므로 이미지 비율이 조금씩 달라도 레이아웃이 흔들리지 않는다. */
.frame { background: #fff; border: 1px solid #e7e0cd; border-radius: 18px; overflow: hidden; }
.frame-bar { display: flex; align-items: center; gap: 6px; padding: 11px 14px; border-bottom: 1px solid #efeade; background: #faf8f2; }
.frame-bar i { width: 9px; height: 9px; border-radius: 50%; background: #e0dac9; display: block; }
.frame-bar .addr { margin-left: 8px; height: 20px; flex: 1; border-radius: 999px; background: #f2eee3; }

/* 실제 스크린샷 확보 전까지 쓰는 플레이스홀더 UI (CSS만으로 그린다) */
.screen { position: relative; padding: 14px; background: linear-gradient(170deg, #f7f4ec, #f1ede2); }
.sk { background: #fff; border: 1px solid #eee8da; border-radius: 10px; }
/* 실제 스크린샷이 들어갈 때 — 프레임 안을 여백 없이 채운다.
   .screen 의 14px 패딩은 CSS 플레이스홀더용이라 이미지에는 맞지 않는다. */
.screen-img { padding: 0; }
.screen-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ln { height: 6px; border-radius: 999px; background: #e9e3d4; display: block; }
.ln.w80 { width: 80%; } .ln.w60 { width: 60%; } .ln.w40 { width: 40%; }
.accent { background: #18b476; }

/* MINOR 스트립 — 목업의 `.mini-strip`을 무한 루프 마퀴로 바꾼 것 */
.mini-thumb {
  height: 96px; border-radius: 12px; border: 1px solid #e7e0cd;
  overflow: hidden; background: #f7f4ec;
}
.mini-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 빈 슬롯 타일 */
.mini-thumb.is-empty {
  border-style: dashed; border-color: #ded7c4; background: #fdfcf8;
  display: flex; align-items: center; justify-content: center;
}

/* 마퀴 항목이 링크일 때 — 움직이는 동안에는 클릭 대상이 되지 않는다.
   조준이 불가능한 것을 클릭 가능하게 두면 오클릭만 낳는다.
   마우스를 올리면 트랙이 멈추므로(아래), 멈춘 뒤에만 눌리게 한다. */
.mini-item { pointer-events: none; }
.mini-marquee:hover .mini-item,
.mini-marquee:focus-within .mini-item { pointer-events: auto; }
.mini-marquee:hover a.mini-item:hover .mini-thumb { border-color: #3ecf8e; }
a.mini-item { display: block; color: inherit; text-decoration: none; }
a.mini-item:hover .mini-name { color: #0b7550; }
/* 키보드 사용자는 hover 가 없다 — focus 로도 멈추고(focus-within) 눌린다. */
@media (prefers-reduced-motion: reduce) {
  .mini-item { pointer-events: auto; }
}
.mini-marquee {
  display: flex; gap: 12px; overflow: hidden;
  /* 양 끝을 흐리게 해서 잘린 항목이 갑자기 사라지지 않게 한다 */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.mini-track {
  display: flex; gap: 12px; flex: 0 0 auto; margin: 0; padding: 0; list-style: none;
  animation: mini-scroll 48s linear infinite;
}
/* 트랙 하나가 자기 너비 + 트랙 사이 gap 만큼 밀리면 두 번째 트랙이 정확히 그 자리에 온다 */
@keyframes mini-scroll { to { transform: translateX(calc(-100% - 12px)); } }
.mini-marquee:hover .mini-track,
.mini-marquee:focus-within .mini-track { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .mini-marquee { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
  .mini-track { animation: none; }
  .mini-track[aria-hidden="true"] { display: none; }
}

/* ── 포트폴리오 빈 슬롯 ──────────────────────────────────────────
   아직 채우지 않은 자리. 가짜 사례를 두느니 비어 있음을 그대로 보여준다
   (docs/PRD.md §4.1 — 허구 금지). 점선으로 채워진 카드와 즉시 구분되게 하고,
   클릭 대상이 아니므로 커서도 바꾸지 않는다.
   aria-hidden 을 쓰지 않는다 — 빈 칸은 장식이 아니라 **상태 정보**다. */
.frame-empty { border-style: dashed; border-color: #ded7c4; background: #fdfcf8; box-shadow: none; }
.frame-empty .frame-bar { background: #f7f4ec; border-bottom-style: dashed; border-bottom-color: #e7e0cd; }
.frame-empty .frame-bar i { background: #ebe5d6; }
.frame-empty .frame-bar .addr { background: #efeade; }
.screen-empty {
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(170deg, #faf8f2, #f5f2e8);
}
.slot-label {
  display: inline-flex; align-items: center; gap: 8px;
  color: #a8a08b; font-size: 13px; letter-spacing: .01em;
}
.slot-num { font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 12px; letter-spacing: .08em; color: #bdb5a0; }

/* 빈 슬롯의 텍스트부 — 채워진 항목의 제목/설명 자리를 그대로 잡아준다. */
.slot-title { color: #b3ab96; }
.slot-desc  { color: #c2bba8; }

/* ── 「개발 구독」 개편 (D34, 2026-10-13) ─────────────────────────
   색 · 그림자 · 움직임은 tailwind-config.js 의 토큰이다(sun · paper · shadow-pop · animate-*).
   여기에는 유틸리티로 쓰기 어려운 것만 둔다. 지금 페이지들은 아직 쓰지 않는다. */

/* 형광펜 — 글자 아래쪽 1/3 에만 노란 띠. 줄이 바뀌어도 줄마다 그어진다. */
.mark {
  background: linear-gradient(transparent 58%, #ffd84d 58%, #ffd84d 92%, transparent 92%);
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
  padding-inline: 2px;
}


/* ══════════ 랜딩 — 「개발 구독」 (D34) ═══════════════════════════════
   랜딩 한 장만 쓰는 컴포넌트다(위의 마퀴가 그랬듯). 유틸리티로 길어지는 것 —
   상태가 바뀌는 것(요청 보드 · 가상 데이터 · FAQ), 의사 요소가 필요한 것(초대장 홈) — 만 여기 둔다.
   색은 tailwind-config.js 의 토큰과 같은 값이다: 글자·테두리 #26231b(warm-900) · 흐림 #6f6a5a(warm-700)
   · 선 #e7e0cd(warm-200) · 모래 #f5f1e6(warm-50) · 그린 #0e9261/#0c7550/#3ecf8e · 민트 #d5f9e4/#eefdf5
   · 노랑 #ffd84d/#fff4c2. 「가상 데이터」의 주황(#c2410c)은 이 시연에서만 쓴다. */

/* 보류 — 아직 정하지 않은 약속(가격 · 선착순 · 약정 · 통화 예약)은 마크업만 두고 숨긴다.
   주소에 ?preview 를 붙이면 사유와 함께 보인다(검토용). 배포 전에 속성을 지우는 것으로 공개한다.
   check-device.sh 가 남은 개수를 알린다. */
html:not(.preview) [data-pending] { display: none !important; }
html.preview [data-pending] { outline: 2px dashed #c2410c; outline-offset: 4px; border-radius: 8px; }
html.preview [data-pending]::before {
  content: "보류 · " attr(data-pending); display: block; width: fit-content; margin-bottom: 6px;
  font: 700 12px/1.4 "Nanum Gothic", sans-serif; letter-spacing: 0;
  color: #c2410c; background: #fff1e6; border: 1px solid #c2410c; border-radius: 6px; padding: 2px 8px;
}

/* 요청 보드 — HTML 에 네 줄이 먼저 있고, JS 는 순서를 돌리기만 한다(D15). */
.req { display: grid; grid-template-columns: 74px 1fr; gap: 2px 12px; align-items: center; padding: 12px 14px;
  border-radius: 14px; background: #f5f1e6; border: 1.5px solid transparent;
  transition: background .45s, border-color .45s, transform .45s cubic-bezier(.2,.9,.3,1.3); }
.req .st { grid-row: span 2; font-size: 12px; font-weight: 800; padding: 4px 0; text-align: center; border-radius: 999px;
  background: #fff; color: #6f6a5a; border: 1.5px solid #e7e0cd; }
.req .t { font-weight: 800; font-size: 15px; line-height: 1.35; min-width: 0; }
.req .m { font-size: 12.5px; color: #6f6a5a; }
.req.now { background: #d5f9e4; border-color: #0e9261; transform: scale(1.02); }
.req.now .st { background: #0e9261; color: #fff; border-color: #0e9261; }
.req.done { background: #fff; border-color: #e7e0cd; }
.req.done .st { background: #fff4c2; color: #26231b; border-color: #ffd84d; }
.req.done .t { color: #6f6a5a; }

/* 띠 — 같은 목록을 두 벌 이어 붙여 -50% 로 돈다. 움직임을 줄이면 한 벌만 감싸서 보인다. */
.ticker-track > span { white-space: nowrap; display: inline-flex; align-items: center; gap: 28px; }
.ticker-track > span::after { content: "✦"; color: #ffd84d; font-size: 16px; }
@media (prefers-reduced-motion: reduce) {
  .ticker-track { animation: none !important; flex-wrap: wrap; width: auto !important; justify-content: center; row-gap: 8px; }
  .ticker-track > [aria-hidden="true"] { display: none; }
}

/* 톡 — 메신저 말풍선 */
.msg { max-width: 78%; padding: 12px 16px; border-radius: 18px; font-size: 15.5px; line-height: 1.5; }
.msg.ai { background: #fff; border-top-left-radius: 6px; }
.msg.me { background: #ffd84d; border-top-right-radius: 6px; font-weight: 600; }
.msg.out { background: #d5f9e4; border: 1.5px solid #0e9261; border-top-left-radius: 6px; }
.msg.out b { display: block; font-size: 12.5px; color: #0c7550; margin-bottom: 4px; }
.typing i { width: 6px; height: 6px; border-radius: 50%; background: #6f6a5a; display: block; animation: blink 1.2s infinite; }
.typing i:nth-child(2) { animation-delay: .2s; } .typing i:nth-child(3) { animation-delay: .4s; }
@keyframes blink { 50% { opacity: .25; transform: translateY(-2px); } }

/* 진행 모니터링 — 줄무늬 진척 막대 */
.bar-fill { display: block; height: 100%; background: repeating-linear-gradient(45deg, #0e9261 0 10px, #3ecf8e 10px 20px);
  background-size: 28px 28px; animation: stripes 1.2s linear infinite; }
@keyframes stripes { to { background-position: 28px 0; } }

/* 가상 데이터 시연 — .real 이 붙으면 배지가 사라지고 테두리가 그린으로 */
.blk { border-radius: 14px; padding: 14px; border: 2px dashed #c2410c; background: #fff1e6; position: relative; min-width: 0;
  transition: all .45s cubic-bezier(.2,.9,.3,1.2); }
.blk .bdg { position: absolute; top: 10px; right: 10px; font-size: 11px; font-weight: 800; color: #c2410c; background: #fff;
  border: 1.5px dashed #c2410c; border-radius: 6px; padding: 1px 6px; transition: opacity .3s, transform .3s; }
.blk.real { border: 2px solid #0e9261; background: #eefdf5; }
.blk.real .bdg { opacity: 0; transform: scale(.6); }
.blk .rows span { display: block; height: 10px; border-radius: 999px; background: currentColor; opacity: .14; }
.meter-num { color: #c2410c; transition: color .3s; }
.meter-num.zero { color: #0e9261; }

/* 초대장 — 오른쪽 그루터기의 반원 홈 */
.ticket-stub { position: relative; }
@media (min-width: 768px) {
  .ticket-stub::before, .ticket-stub::after { content: ""; position: absolute; left: -16px; width: 28px; height: 28px;
    border-radius: 50%; background: #fffdf7; border: 2px solid #26231b; }
  .ticket-stub::before { top: -16px; } .ticket-stub::after { bottom: -16px; }
}

/* 열 자리 벽 */
.seat { border: 2px dashed #e7e0cd; border-radius: 22px; background: #fff; display: grid; place-items: center; align-content: center;
  gap: 4px; padding: 12px; text-align: center; position: relative; min-width: 0;
  transition: transform .2s cubic-bezier(.2,.9,.3,1.4), border-color .2s, background .2s; }
.seat .q { font-size: clamp(34px, 5vw, 52px); font-weight: 900; color: #e7e0cd; line-height: 1; transition: color .2s; }
.seat:hover { border-color: #26231b; background: #fff4c2; transform: translateY(-4px) rotate(-1.5deg); }
.seat:hover .q { color: #26231b; }
.seat.next { border-color: #0e9261; background: #eefdf5; }
.seat.next .q { color: #0e9261; }
.seat.filled { border: 2px solid #26231b; box-shadow: 5px 5px 0 #0e9261; }
.seat.filled:hover { transform: none; background: #fff; }

/* FAQ — <details> 의 기본 삼각형 대신 + 표시 */
.faq summary { list-style: none; cursor: pointer; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; flex: none; width: 30px; height: 30px; border-radius: 50%; background: #f5f1e6;
  display: grid; place-items: center; font-weight: 900; transition: transform .25s, background .2s; }
.faq details[open] summary::after { transform: rotate(45deg); background: #ffd84d; }
.faq details[open], .faq details:hover { border-color: #26231b; }
