/* ═══════════════════════════════════════════════════════════════
   등장 연출

   내용이 먼저고 연출은 그다음이다. 자바스크립트가 없거나 실패해도
   화면은 그대로 다 보여야 한다. 그래서 숨기는 규칙은 전부
   html.js 아래에만 둔다.

   첫 화면 인트로는 html.playing-intro가 붙었을 때만 재생한다. 한 세션에
   한 번이다. 매주 들어오는 학생에게 매번 재생하면 방해가 된다.
   ═══════════════════════════════════════════════════════════════ */

/* ── 첫 화면: 아래에서 올라오며 나타난다 ──────────────────────── */

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

html.playing-intro .screen.is-dark .kicker,
html.playing-intro .screen.is-dark h1,
html.playing-intro .screen.is-dark > .wrap > p {
  animation: rise .7s cubic-bezier(.22, .61, .36, 1) backwards;
}
html.playing-intro .screen.is-dark .kicker          { animation-delay: .05s; }
html.playing-intro .screen.is-dark h1               { animation-delay: .16s; }
html.playing-intro .screen.is-dark > .wrap > p      { animation-delay: .30s; }

/* ── 히어로 그래픽: 선이 그려진다 ─────────────────────────────
   polyline에 pathLength="1"을 줘서 길이를 1로 정규화했다.
   그래서 좌표가 바뀌어도 이 값들을 고칠 필요가 없다. */

@keyframes draw      { to { stroke-dashoffset: 0; } }
@keyframes fade-in   { to { opacity: 1; } }
@keyframes grow-up   { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes pulse-dot {
  0%, 100% { r: 9; opacity: .18; }
  50%      { r: 14; opacity: .05; }
}

html.playing-intro .g-line {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: draw 1.9s cubic-bezier(.4, 0, .25, 1) .35s backwards;
}
html.playing-intro .g-line-2 {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: draw 2.1s cubic-bezier(.4, 0, .25, 1) .5s backwards;
}
html.playing-intro .g-area,
html.playing-intro .g-grid,
html.playing-intro .g-dots {
  opacity: 0;
  animation: fade-in .9s ease-out 1.5s forwards;
}
html.playing-intro .g-bars rect {
  transform-origin: 50% 100%;
  animation: grow-up .5s cubic-bezier(.22, .61, .36, 1) backwards;
}
html.playing-intro .g-bars rect:nth-child(1)  { animation-delay: .40s; }
html.playing-intro .g-bars rect:nth-child(2)  { animation-delay: .46s; }
html.playing-intro .g-bars rect:nth-child(3)  { animation-delay: .52s; }
html.playing-intro .g-bars rect:nth-child(4)  { animation-delay: .58s; }
html.playing-intro .g-bars rect:nth-child(5)  { animation-delay: .64s; }
html.playing-intro .g-bars rect:nth-child(6)  { animation-delay: .70s; }
html.playing-intro .g-bars rect:nth-child(7)  { animation-delay: .76s; }
html.playing-intro .g-bars rect:nth-child(8)  { animation-delay: .82s; }
html.playing-intro .g-bars rect:nth-child(9)  { animation-delay: .88s; }
html.playing-intro .g-bars rect:nth-child(10) { animation-delay: .94s; }
html.playing-intro .g-bars rect:nth-child(11) { animation-delay: 1.0s; }

html.playing-intro .g-head { opacity: 0; animation: fade-in .5s ease-out 2.1s forwards; }

/* 마지막 지점은 계속 옅게 뛴다. 데이터가 아직 쌓이는 중이라는 표시다. */
.g-head-halo { animation: pulse-dot 2.6s ease-in-out 2.6s infinite; }

/* ── 스크롤하며 섹션이 올라온다 ───────────────────────────────── */

html.reveal-ready [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
}
html.reveal-ready [data-reveal].is-in {
  opacity: 1;
  transform: none;
  transition: opacity .6s ease-out, transform .6s cubic-bezier(.22, .61, .36, 1);
}
/* 같은 줄에 있는 것들은 조금씩 시차를 둔다 */
html.reveal-ready [data-reveal][data-delay="1"].is-in { transition-delay: .08s; }
html.reveal-ready [data-reveal][data-delay="2"].is-in { transition-delay: .16s; }

/* ── 손이 닿는 것들 ───────────────────────────────────────────── */

.list a.row {
  transition: background-color .18s ease, padding-left .18s ease;
}
.list a.row:hover { padding-left: .7rem; }

/* 목록 항목에 마우스를 올리면 화살표가 밀려 들어온다 */
.list a.row::after {
  content: "→";
  font-family: var(--lt-serif);
  font-style: italic;
  color: var(--accent-ink);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity .18s ease, transform .18s ease;
  margin-left: .3rem;
}
.list a.row:hover::after { opacity: 1; transform: none; }

.intro-item { transition: background-color .2s ease; }
.intro-item .n { display: inline-block; transition: transform .25s cubic-bezier(.22,.61,.36,1); }
.intro-item:hover .n { transform: translateY(-3px); }

/* 메뉴: 밑줄이 왼쪽에서 그어진다 */
.nav a { position: relative; }
.nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -4px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .22s cubic-bezier(.22,.61,.36,1);
}
.nav a:hover::after,
.nav a[aria-current="page"]::after { transform: scaleX(1); }
.nav a:hover { text-decoration: none; }

.btn { transition: filter .18s ease, transform .18s ease; }
.btn:hover { transform: translateY(-1px); }

.brand { transition: opacity .18s ease; }
.brand:hover { opacity: .78; }

/* ── 움직임을 줄이도록 설정한 사용자 ─────────────────────────── */
/* 위쪽에도 전역 규칙이 있지만, 연출 클래스가 붙은 경우까지 확실히 끈다. */

@media (prefers-reduced-motion: reduce) {
  html.playing-intro *,
  html.reveal-ready [data-reveal] {
    animation: none !important;
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
    stroke-dashoffset: 0 !important;
  }
}

/* ═══════════════════════════════════════════════════════════════
   여기부터 확장 연출
   ═══════════════════════════════════════════════════════════════ */

/* ── 상단 스크롤 진행 막대 ────────────────────────────────────
   데이터를 다루는 사이트답게, 읽은 만큼이 수치로 보이게 한다. */

.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 100%;
  z-index: 40;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  will-change: transform;
  pointer-events: none;
}
html:not(.js) .scroll-progress { display: none; }

/* ── 헤더: 스크롤하면 줄어든다 ───────────────────────────────── */

.site-header {
  transition: box-shadow .3s ease, background-color .3s ease;
}
.site-header .wrap { transition: min-height .3s cubic-bezier(.22,.61,.36,1); }
.brand small {
  transition: opacity .25s ease, max-height .3s ease, margin-top .3s ease;
  max-height: 1.2rem;
  overflow: hidden;
}
.site-header.is-scrolled .wrap { min-height: 50px; }
.site-header.is-scrolled .brand small { opacity: 0; max-height: 0; margin-top: 0; }
.site-header.is-scrolled { box-shadow: 0 1px 0 rgba(255,255,255,.09); }

@media (max-width: 640px) {
  /* 모바일은 메뉴가 아랫줄로 흐르므로 높이를 건드리지 않는다 */
  .site-header.is-scrolled .wrap { min-height: 0; }
}

/* ── 제목: 줄 단위로 밀려 올라온다 ───────────────────────────
   한글은 자모가 모여 한 글자를 이루므로 글자 단위로 쪼개면
   조합이 어색하게 보인다. 줄 단위가 안전하고 인상도 강하다. */

.line-mask { display: block; overflow: hidden; }
.line-mask > span { display: block; }

@keyframes line-up {
  from { transform: translateY(105%); }
  to   { transform: none; }
}

html.playing-intro .line-mask > span {
  animation: line-up .85s cubic-bezier(.16, 1, .3, 1) backwards;
}
html.playing-intro .line-mask:nth-of-type(1) > span { animation-delay: .12s; }
html.playing-intro .line-mask:nth-of-type(2) > span { animation-delay: .24s; }
html.playing-intro .line-mask:nth-of-type(3) > span { animation-delay: .36s; }

/* 제목이 줄 마스크를 쓰면 기존 rise 연출은 빼야 이중으로 걸리지 않는다 */
html.playing-intro .screen.is-dark h1:has(.line-mask) { animation: none; }

/* ── 히어로 그래픽: 스크롤·마우스에 따라 미세하게 움직인다 ──── */

.band-graphic {
  will-change: transform;
  transition: transform .5s cubic-bezier(.22,.61,.36,1);
}
html.js .band-graphic {
  transform: translate3d(var(--px, 0px), calc(var(--py, 0px) + var(--sy, 0px)), 0);
  transition: none;   /* 매 프레임 갱신하므로 전환을 걸지 않는다 */
}

/* ── 섹션 밑줄이 그어진다 ────────────────────────────────────── */

.section-head { position: relative; border-bottom-color: transparent; }
.section-head::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--line);
  transform: scaleX(0);
  transform-origin: left;
}
html.reveal-ready .section-head.is-in::after {
  transform: scaleX(1);
  transition: transform .8s cubic-bezier(.16, 1, .3, 1) .1s;
}
html:not(.reveal-ready) .section-head::after { transform: scaleX(1); }

/* ── 목록: 항목이 하나씩 순서대로 ────────────────────────────── */

html.reveal-ready .list[data-reveal] > li {
  opacity: 0;
  transform: translateY(12px);
}
html.reveal-ready .list[data-reveal].is-in > li {
  opacity: 1;
  transform: none;
  transition: opacity .5s ease-out, transform .5s cubic-bezier(.22,.61,.36,1);
}
html.reveal-ready .list[data-reveal].is-in > li:nth-child(1) { transition-delay: .04s; }
html.reveal-ready .list[data-reveal].is-in > li:nth-child(2) { transition-delay: .11s; }
html.reveal-ready .list[data-reveal].is-in > li:nth-child(3) { transition-delay: .18s; }
html.reveal-ready .list[data-reveal].is-in > li:nth-child(4) { transition-delay: .25s; }
html.reveal-ready .list[data-reveal].is-in > li:nth-child(5) { transition-delay: .32s; }
html.reveal-ready .list[data-reveal].is-in > li:nth-child(6) { transition-delay: .39s; }
html.reveal-ready .list[data-reveal].is-in > li:nth-child(n+7) { transition-delay: .45s; }

/* ── 세 갈래 안내: 핑크가 아래에서 차오른다 ──────────────────── */

.intro-item { position: relative; overflow: hidden; isolation: isolate; }
.intro-item::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--accent-wash);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform .38s cubic-bezier(.22,.61,.36,1);
}
.intro-item:hover::before,
.intro-item:focus-visible::before { transform: scaleY(1); }
.intro-item:hover { background: transparent; }   /* ::before가 대신한다 */

.intro-item h3 { transition: transform .3s cubic-bezier(.22,.61,.36,1); }
.intro-item:hover h3 { transform: translateX(4px); }
.intro-item .n { transition: transform .35s cubic-bezier(.16,1,.3,1), color .3s ease; }
.intro-item:hover .n { transform: translateY(-4px) scale(1.12); }

/* ── 주차 번호: 크게 뛰어오른다 ──────────────────────────────── */

@keyframes no-pop {
  0%   { opacity: 0; transform: translateY(10px) scale(.86); }
  60%  { opacity: 1; transform: translateY(0) scale(1.04); }
  100% { opacity: 1; transform: none; }
}
html.reveal-ready .this-week.is-in .no {
  animation: no-pop .7s cubic-bezier(.22,.61,.36,1) .15s backwards;
}

/* ── 배지 ─────────────────────────────────────────────────────── */

.badge { transition: transform .2s cubic-bezier(.16,1,.3,1), background-color .2s ease, color .2s ease; }
.list .row:hover .badge { transform: translateY(-2px); background: var(--accent-wash); color: var(--accent-ink); }

/* ── 버튼: 글자가 위로 밀려 나가고 새로 올라온다 ─────────────── */

.btn {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink);
  transform: translateY(101%);
  transition: transform .34s cubic-bezier(.22,.61,.36,1);
}
.btn:hover::before { transform: none; }
.btn:hover { border-color: var(--ink); transform: none; }

/* ── 본문 링크: 밑줄이 좌에서 우로 ───────────────────────────── */

.prose a,
.notice a,
.section-head .more {
  position: relative;
  text-decoration: none;
  background-image: linear-gradient(var(--accent-ink), var(--accent-ink));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size .3s cubic-bezier(.22,.61,.36,1);
  padding-bottom: 1px;
}
.prose a:hover,
.notice a:hover,
.section-head .more:hover { background-size: 100% 1px; text-decoration: none; }

/* ── 로고 ─────────────────────────────────────────────────────── */

.brand { display: inline-block; }
.brand:hover { opacity: 1; }
.brand > :first-child, .brand small { transition: transform .3s cubic-bezier(.16,1,.3,1); }

/* ── 페이지 전환 ──────────────────────────────────────────────
   브라우저가 지원하면 페이지를 넘길 때 부드럽게 이어진다.
   지원하지 않으면 평소처럼 즉시 바뀔 뿐, 깨지지 않는다. */

@view-transition { navigation: auto; }

::view-transition-old(root) {
  animation: vt-out .22s cubic-bezier(.4,0,1,1) both;
}
::view-transition-new(root) {
  animation: vt-in .34s cubic-bezier(.16,1,.3,1) both;
}
@keyframes vt-out { to { opacity: 0; transform: translateY(-8px); } }
@keyframes vt-in  { from { opacity: 0; transform: translateY(12px); } }

/* 헤더는 페이지가 바뀌어도 제자리에 머문다 */
.site-header { view-transition-name: site-header; }
::view-transition-group(site-header) { animation-duration: .3s; }

/* ── 움직임 줄이기 ────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .scroll-progress { display: none; }
  .line-mask > span { transform: none !important; animation: none !important; }
  .section-head::after { transform: scaleX(1) !important; transition: none !important; }
  html.reveal-ready .list[data-reveal] > li { opacity: 1 !important; transform: none !important; }
  html.js .band-graphic { transform: none !important; }
  @view-transition { navigation: none; }
}
