/* ============================================================================
   GiftTalk — 움직임

   여기서 정하는 것은 "장식"이 아니라 **읽는 순서**다.
   손님의 눈이 가야 할 곳으로 먼저 가게 만들고, 방금 바뀐 것을 알아채게 한다.

   지키는 선
     · 움직임에는 뜻이 있어야 한다. 뜻 없이 흔들리는 것은 넣지 않는다.
       (네온·카지노·코인사이트 느낌은 이 사이트가 피하는 방향이다)
     · 한 화면에서 저절로 움직이는 것은 **한 번에 하나**만 둔다.
     · 0.2초 안팎으로 짧게. 길면 느린 사이트로 느껴진다.
     · 움직임을 줄여 달라고 설정한 사람에게는 전부 멈춘다(맨 아래).
     · 인라인 스타일 금지(CSP) — 값이 바뀌는 것은 JS 가 el.style 로 준다.
   ========================================================================== */

:root {
  --t-fast:  .14s;
  --t-base:  .22s;
  --t-slow:  .42s;
  --ease-out: cubic-bezier(.22, .61, .36, 1);
  --ease-spring: cubic-bezier(.34, 1.32, .64, 1);
}

/* ── 나타나기 ────────────────────────────────────────────────────────
   화면을 내리면 그 자리에서 조금 떠오른다. 한 번만 일어난다.
   .reveal 을 붙여 두면 core.js 의 관찰자가 보일 때 .in 을 달아 준다. */
.reveal {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out);
  will-change: opacity, transform;
}
.reveal.in { opacity: 1; transform: none; }
/* 여러 개가 한꺼번에 뜰 때 아주 조금씩 어긋나게 — 우르르 튀어나오지 않게 */
.reveal.d1 { transition-delay: .04s }
.reveal.d2 { transition-delay: .08s }
.reveal.d3 { transition-delay: .12s }
.reveal.d4 { transition-delay: .16s }

/* ── 손을 올렸을 때 ──────────────────────────────────────────────── */
.gcard, .scard, .card, .rvcard, .pitem {
  transition: transform var(--t-base) var(--ease-out),
              border-color var(--t-base) var(--ease-out),
              box-shadow var(--t-base) var(--ease-out),
              background-color var(--t-base) var(--ease-out);
}
@media (hover: hover) {
  .gcard:hover, .scard:hover, .card:hover, .rvcard:hover {
    transform: translateY(-3px);
    border-color: var(--line-3);
    box-shadow: var(--sh-2);
  }
  /* 그림은 살짝만 커진다. 크게 움직이면 목록이 출렁인다. */
  .gcard .gimg img, .card .gimg img { transition: transform var(--t-slow) var(--ease-out); }
  .gcard:hover .gimg img, .card:hover .gimg img { transform: scale(1.045); }
}
.gcard:active, .scard:active, .card:active { transform: translateY(-1px) scale(.995); }

/* 누를 수 있는 것은 눌리는 느낌을 준다 */
.btn { transition: transform var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out),
                   border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out); }
.btn:active { transform: scale(.97); }

/* ── 방금 들어온 것 ──────────────────────────────────────────────────
   내가 보고 있는 동안 새로 올라온 매물에만 잠깐 붙는다.
   "새로고침해야 새 글이 보이는 사이트" 라는 느낌을 없애는 장치다. */
@keyframes freshIn {
  from { opacity: 0; transform: translateY(-6px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
.is-fresh { animation: freshIn var(--t-slow) var(--ease-spring); }
.is-fresh::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  border: 1px solid var(--accent-line);
  animation: freshRing 2.4s var(--ease-out) 1 forwards;
  pointer-events: none;
}
@keyframes freshRing {
  0%   { opacity: 1; box-shadow: 0 0 0 0 var(--accent-soft); }
  70%  { opacity: 1; box-shadow: 0 0 0 7px transparent; }
  100% { opacity: 0; box-shadow: none; }
}

/* ── 살아 있다는 표시 ────────────────────────────────────────────────
   깜빡이는 점 하나. 지금 이 숫자가 실제로 움직인다는 뜻으로만 쓴다. */
.livedot {
  width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
  background: var(--ok); position: relative;
}
.livedot::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: var(--ok); animation: livePulse 2.2s var(--ease-out) infinite;
}
@keyframes livePulse {
  0%   { transform: scale(1);   opacity: .55; }
  70%  { transform: scale(2.6); opacity: 0; }
  100% { transform: scale(2.6); opacity: 0; }
}

/* ── 값이 바뀌었을 때 ────────────────────────────────────────────────
   숫자가 조용히 바뀌면 아무도 못 본다. 잠깐 색만 준다. */
@keyframes bumpUp {
  0%   { transform: none;             color: inherit; }
  30%  { transform: translateY(-3px); color: var(--accent); }
  100% { transform: none;             color: inherit; }
}
.bumped { animation: bumpUp .5s var(--ease-out); }

/* ── 예약중 — 지금 이야기가 오가는 중이라는 뜻 ──────────────────── */
.st-RESERVED::before { animation: softBlink 1.9s var(--ease-out) infinite; }
@keyframes softBlink { 0%,100% { opacity: 1 } 50% { opacity: .35 } }

/* ── 기다리는 동안 ──────────────────────────────────────────────────
   회색 상자가 가만히 있으면 멈춘 것처럼 보인다. 빛이 한 번씩 지나간다. */
.sk, .skeleton {
  position: relative; overflow: hidden;
  background: var(--surface-2);
}
.sk::after, .skeleton::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 20%,
              rgba(255,255,255,.055) 42%, rgba(255,255,255,.055) 58%, transparent 80%);
  transform: translateX(-100%);
  animation: shimmer 1.35s linear infinite;
}
@keyframes shimmer { to { transform: translateX(100%); } }

/* ── 실시간 소식 줄 ──────────────────────────────────────────────────
   한 줄씩 올라오며 바뀐다. 내용은 실제로 일어난 일만 넣는다. */
.livebar {
  display: flex; align-items: center; gap: var(--s3);
  min-height: 42px; padding: 0 var(--s4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: linear-gradient(180deg, var(--surface) 0%, var(--bg-2) 100%);
  overflow: hidden;
}
.livebar .lb-head {
  display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
  font-size: var(--f-xs); font-weight: 800; letter-spacing: .06em;
  color: var(--text-3); text-transform: uppercase;
}
.livebar .lb-track { position: relative; flex: 1; height: 42px; overflow: hidden; }
.livebar .lb-item {
  position: absolute; inset: 0; display: flex; align-items: center; gap: var(--s2);
  font-size: var(--f-md); color: var(--text-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.livebar .lb-item b { color: var(--text); font-weight: 700; }
.livebar .lb-item .when { color: var(--text-4); font-size: var(--f-xs); margin-left: auto; flex-shrink: 0; }
.lb-item.enter { animation: lbEnter var(--t-slow) var(--ease-out); }
.lb-item.leave { animation: lbLeave var(--t-base) var(--ease-out) forwards; }
@keyframes lbEnter { from { opacity: 0; transform: translateY(100%); } to { opacity: 1; transform: none; } }
@keyframes lbLeave { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-100%); } }

/* ── 숫자 세기 ───────────────────────────────────────────────────────
   0 에서 실제 값까지 짧게 올라간다. 값은 JS 가 채운다(자릿수 흔들림 방지). */
.tnum { font-variant-numeric: tabular-nums; }
.counting { color: var(--text); }

/* ── 강조 ────────────────────────────────────────────────────────────
   첫 화면 큰 글씨의 한 낱말에만. 배경이 흐르는 것이 아니라 글자 안에서만 움직인다. */
.shine {
  background: linear-gradient(100deg,
              var(--text) 0%, var(--text) 38%,
              #9FD2FA 50%, var(--text) 62%, var(--text) 100%);
  background-size: 260% 100%;
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  animation: shineSweep 5.5s var(--ease-out) infinite;
}
@keyframes shineSweep {
  0%, 62%  { background-position: 160% 0; }
  100%     { background-position: -60% 0; }
}

/* ── 화면이 바뀔 때 ──────────────────────────────────────────────── */
#view > * { animation: pageIn var(--t-base) var(--ease-out); }
@keyframes pageIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ── 움직임을 줄여 달라고 한 사람에게는 전부 멈춘다 ─────────────────
   어지럼증·멀미가 있는 분들에게 이 설정은 편의가 아니라 필요다. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  .shine { animation: none; background: none; -webkit-text-fill-color: var(--text); color: var(--text); }
}
