/* =========================================================================
   수학 풀이 플레이어 — 스타일
   분필 필기 효과는 GPU 가속 위해 opacity/transform 기반 (clip-path 미사용).
   밝은 화이트보드 배경.
   ========================================================================= */

* { box-sizing: border-box; margin: 0; padding: 0; }

/* hidden 속성은 display 를 지정한 요소(.loading, .error-panel 등)에서
   무시되므로 명시적으로 강제한다. */
[hidden] { display: none !important; }

:root {
  --bg: #2a2f3a;
  --board-bg: #fbfaf4;
  --ink: #2b2b2b;
  --accent: #1b6ca8;
  --accent-problem: #c0392b;
  --accent-check: #2f8f4f;
}

body {
  font-family: system-ui, -apple-system, "Helvetica Neue", sans-serif;
  background: var(--bg);
  color: #e6e6e6;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px 14px 40px;
}

.app { width: min(760px, 100%); }

.app-head { text-align: center; margin-bottom: 16px; }
.app-head h1 { font-size: 24px; color: #fff; font-weight: 700; }
.sub { font-size: 13px; color: #9aa5b1; margin-top: 4px; }

/* ===== 화이트보드 ===== */
.board {
  position: relative;
  background: var(--board-bg);
  border-radius: 14px;
  padding: 24px 28px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, .4);
  color: var(--ink);
  /* 미세한 종이 질감 */
  background-image:
    radial-gradient(circle at 20% 30%, rgba(0,0,0,.012) 0, transparent 60%),
    radial-gradient(circle at 80% 70%, rgba(0,0,0,.012) 0, transparent 60%);
  /* 보드는 고정 크기 — 풀이가 길어지면 내부 스크롤 */
  height: 56vh;
  overflow-y: auto;
}
.board-title {
  font-size: 20px;
  color: var(--accent);
  font-weight: 700;
  border-bottom: 2px dashed #d6d2c4;
  padding-bottom: 8px;
  margin-bottom: 12px;
}

/* ===== 분필 커서 =====
   board 안에 position:absolute 로 띄워 writing 글리프를 따라다닌다.
   분필 스틱: 짧고 끝이 닳은 막대, 28deg 기울임 (쓰는 손 쪽으로 — 글자를 안 가림).
   transform 으로 위치를 잡으므로 top/left 는 0으로 고정. */
#chalk-cursor {
  position: absolute;
  pointer-events: none;
  top: 0; left: 0;
  z-index: 10;
  width: 12px;
  height: 34px;
  opacity: 0;
  /* GPU 가속 transition — 글리프를 부드럽게 따라감 */
  transition: transform 0.07s linear, opacity 0.12s ease;
  will-change: transform, opacity;
}
#chalk-cursor.visible {
  opacity: 1;
}

/* 분필 몸통: 육각형 스틱 느낌의 크림/베이지 막대 */
#chalk-cursor::before {
  content: '';
  position: absolute;
  bottom: 4px; left: 50%;
  transform: translateX(-50%) rotate(28deg);
  transform-origin: bottom center;
  width: 8px;
  height: 26px;
  border-radius: 2px 2px 0 0;
  background: linear-gradient(
    to right,
    #e8dfc8 0%, #f5f0e8 35%, #ede5d0 60%, #d4c9a8 100%
  );
  box-shadow:
    inset -1.5px 0 0 rgba(0,0,0,.13),
    inset 1px 0 0 rgba(255,255,255,.4),
    0 2px 4px rgba(0,0,0,.22);
}

/* 분필 끝(tip): 닳아서 뭉툭해진 느낌의 작은 타원 */
#chalk-cursor::after {
  content: '';
  position: absolute;
  bottom: 0; left: 50%;
  transform: translateX(-50%) rotate(28deg);
  transform-origin: bottom center;
  width: 6px;
  height: 7px;
  border-radius: 50% 50% 30% 30% / 60% 60% 40% 40%;
  background: radial-gradient(ellipse at 40% 35%, #f0ece0 0%, #c8b98a 70%, #b0a070 100%);
  box-shadow: 0 1px 2px rgba(0,0,0,.18);
}

/* ===== 단계 ===== */
.step {
  display: block;
  margin: 12px 0;
  /* 단계가 도착할 때 부드럽게 등장 */
  animation: stepIn .35s ease-out;
}
@keyframes stepIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

.ink-wrap { min-width: 0; }
.ink {
  display: inline-block;
  padding: 6px 8px;
  border-radius: 8px;
}
.step.problem .ink { background: #fff3ef; }
.step.check   .ink { background: #eef8f0; }
.katex { font-size: 1.5em; }

/* ===== 혼합 콘텐츠 (텍스트 + 인라인 $...$ 수식) =====
   `.ink.mixed` 컨테이너 안에 .text-seg(텍스트) 와 .katex(인라인 수식)가
   DOM 순서로 섞여 한 줄로 자연스럽게 흐른다. */
.ink.mixed {
  font-size: 1.18em;
  line-height: 1.6;
  /* 줄바꿈 시 단어 단위로 끊기되 수식은 통째로 유지 */
  word-break: keep-all;
}
.ink.mixed .text-seg {
  /* 텍스트 조각 — 흐름 텍스트 */
  white-space: pre-wrap;
}
.ink.mixed .katex {
  /* 인라인 수식 — 주변 텍스트와 시각 균형. 베이스라인 정렬 유지. */
  font-size: 1.12em;
  white-space: nowrap;
}
/* 순수 텍스트(.plain-text)지만 .text-seg 래퍼를 거치는 경우 */
.ink.plain-text .text-seg { white-space: pre-wrap; }

/* ===== 마크다운 블록 (문단 / 불릿·번호 목록 / 굵게 / 디스플레이 수식) =====
   visual 은 `$$..$$` 디스플레이 수식, `$..$` 인라인 수식, `**굵게**`,
   `* `/`- ` 불릿, `1.` 번호 목록, 줄바꿈이 섞여 들어온다. parseVisual 이
   이를 블록(.md-para / .md-list)으로 나눠 `.ink` 안에 DOM 순서로 배치한다. */

/* 문단 블록 — 블록 사이 간격만 둔다 */
.md-para { display: block; }
.md-para + .md-para { margin-top: 5px; }
.md-para + .md-list,
.md-list + .md-para,
.md-list + .md-list { margin-top: 5px; }

/* 마크다운 굵게 — 분필 글자에 어울리는 강조 */
.bold-seg {
  font-weight: 700;
  color: var(--accent);
}

/* 불릿 / 번호 목록 — div 기반.
   마커(•/번호)는 .md-marker 텍스트로 렌더해 분필 글리프 수집 대상이 된다
   (CSS ::marker 는 글리프화할 수 없어 분필 효과에서 누락되므로 쓰지 않음). */
.md-list {
  display: block;
  margin: 4px 0;
}
.md-item {
  display: block;
  margin: 2px 0;
  padding-left: 1.4em;
  text-indent: -1.4em;   /* 마커는 내어쓰기로 본문 왼쪽에 정렬 */
  line-height: 1.55;
}
.md-marker {
  color: var(--ink);
  font-weight: 600;
}
.md-item-body { text-indent: 0; }

/* 디스플레이 수식 ($$..$$) — 자체 줄에 가운데 정렬된 블록.
   KaTeX 의 .katex-display 래퍼를 그대로 쓰되 잉크 톤에 맞게 여백 조정. */
.katex-display.display-seg {
  margin: 8px 0;
}
/* 디스플레이 수식은 인라인 수식보다 크게 — 강조 */
.ink .katex-display .katex { font-size: 1.32em; }
.ink.mixed .katex-display .katex { font-size: 1.26em; }

/* ===== 분필 필기 효과 =====
   각 글리프(.chalk-glyph)는 처음엔 안 보이다가 한 자씩 순차로 나타난다.
   GPU 가속: opacity/transform/filter 만 사용. 저가 기기 30fps 목표.

   상태 머신:
     (없음)           → .shown 추가     → chalkIn 애니메이션 (한 획 긋는 느낌)
     .shown.writing   → 현재 쓰는 중 글자. dim + blur 로 "닿는 순간" 강조.
     .shown (writing  → chalkSettle 애니메이션 — 글자가 자리잡음.
             제거)
     (없음) / 시크 후 → 즉시 opacity:0 (transition 없음)

   구조 요소(.chalk-struct = 분수선/근호선 등):
     텍스트 없이 border/bg 로 그려지므로 blur 없이 opacity 전환만.
*/

/* --- 키프레임 --- */

/* 텍스트 글리프 첫 등장: 분필이 닿는 순간의 번짐→선명해짐 */
@keyframes chalkIn {
  0%   { opacity: 0;    transform: translateY(2px) scale(.92); filter: blur(1.4px); }
  35%  { opacity: .65;  transform: translateY(1px) scale(.97); filter: blur(0.6px); }
  70%  { opacity: .88;  transform: translateY(0)   scale(1.01); filter: blur(0.15px); }
  100% { opacity: 1;    transform: translateY(0)   scale(1);    filter: none; }
}

/* writing → shown 전환: 글자가 안정적으로 자리잡는 느낌 */
@keyframes chalkSettle {
  0%   { opacity: .72; filter: blur(0.45px); }
  100% { opacity: 1;   filter: none; }
}

/* 구조 요소 등장: 분수선이 좌→우로 그어지는 느낌 */
@keyframes chalkStructIn {
  0%   { opacity: 0; transform: scaleX(.2) translateX(-30%); }
  60%  { opacity: .7; transform: scaleX(1.03) translateX(0); }
  100% { opacity: 1; transform: scaleX(1) translateX(0); }
}

/* 구조 요소 settle */
@keyframes chalkStructSettle {
  from { opacity: .65; }
  to   { opacity: 1; }
}

/* --- 기본 상태: 숨김 --- */
.chalk-glyph {
  opacity: 0;
  will-change: opacity, transform, filter;
}

/* 텍스트 글리프만 inline-block (transform 적용 위해).
   구조 요소(.chalk-struct)는 KaTeX 가 부여한 display 를 유지해야 레이아웃이 깨지지 않는다. */
.chalk-glyph:not(.chalk-struct) {
  display: inline-block;
}

/* --- 완전히 써진 상태 (처음 등장: chalkIn 애니메이션) --- */
.chalk-glyph.shown {
  animation: chalkIn 0.19s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
  text-shadow:
     0.45px  0.25px 0 rgba(43,43,43,.20),
    -0.35px  0.28px 0 rgba(43,43,43,.16),
     0.18px -0.22px 0 rgba(43,43,43,.11);
}

/* --- 이미 정착된 글자 (writing→shown 전환 후 or fillStep 으로 즉시 채움).
   chalk-settled 가 붙으면 chalkIn 재실행 없이 즉시 완전 불투명 상태로 고정.
   chalkSettle 을 쓰면 부드럽게 안정화되지만, fillStep 에서는 즉시여야 하므로
   animation: none + opacity:1 로 즉시 고정. --- */
.chalk-glyph.shown.chalk-settled {
  animation: none;
  opacity: 1;
  transform: translateY(0) scale(1);
  filter: none;
}

/* --- 구조 요소 완전히 써진 상태 --- */
.chalk-glyph.chalk-struct.shown {
  animation: chalkStructIn 0.16s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
  transform-origin: left center;   /* 분수선이 왼쪽에서 오른쪽으로 그어지는 느낌 */
  text-shadow: none;
  filter: none;
}
.chalk-glyph.chalk-struct.shown.chalk-settled {
  animation: none;
  opacity: 1;
  transform: scaleX(1);
  filter: none;
}

/* --- 현재 쓰는 중인 글자 (writing 상태) ---
   chalkIn 애니메이션이 실행 중이거나 바로 시작하는 글자.
   writing 이 붙으면 animation:none 으로 keyframe 을 취소하고
   직접 "닿는 순간" 스타일을 적용 (dim + blurry = 분필 선단). */
.chalk-glyph.shown.writing {
  animation: none;
  opacity: 0.72;
  transform: translateY(1px) scale(.97);
  filter: blur(0.45px);
  text-shadow:
     1.1px  0.4px 0 rgba(43,43,43,.20),
    -0.7px  0.55px 0 rgba(43,43,43,.15),
     0.35px -0.35px 0 rgba(43,43,43,.10);
}

/* chalk-settled 가 붙으면 writing 이 함께 있더라도 settled 가 우선 (specificity 동일,
   뒤에 오는 규칙 우선). 실제론 JS 가 writing 제거 후 chalk-settled 추가하므로
   둘이 동시에 붙는 경우는 없음. 방어 코드로만 존재. */
.chalk-glyph.shown.chalk-settled.writing {
  animation: none;
  opacity: 1;
  transform: translateY(0) scale(1);
  filter: none;
}

/* --- 구조 요소 쓰는 중 --- */
.chalk-glyph.chalk-struct.shown.writing {
  animation: none;
  opacity: 0.65;
  transform: scaleX(1);
  filter: none;
  text-shadow: none;
}

/* 다 써진 글자에 옅은 분필 질감 */
.ink .katex,
.plain-text {
  text-shadow: .3px .2px .4px rgba(43, 43, 43, .14);
}
.plain-text { font-size: 1.15em; line-height: 1.5; }

/* ===== 자막 ===== */
.subtitle {
  margin-top: 14px;
  min-height: 48px;
  display: flex; align-items: center; gap: 10px;
  background: rgba(255, 255, 255, .07);
  border-radius: 10px;
  padding: 12px 16px;
  font-size: 16px;
  line-height: 1.45;
}
.subtitle-icon { flex: none; }

/* ===== 다음 단계 준비 중 인디케이터 ===== */
.waiting {
  margin-top: 8px;
  display: flex; align-items: center; gap: 8px;
  font-size: 13px;
  color: #9aa5b1;
  padding: 6px 12px;
}
.waiting-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--accent);
  animation: waitingPulse 1s ease-in-out infinite;
}
@keyframes waitingPulse {
  0%, 100% { opacity: .25; transform: scale(.8); }
  50%      { opacity: 1;   transform: scale(1); }
}

/* ===== 재생 컨트롤 ===== */
.controls {
  margin-top: 14px;
  display: flex; align-items: center; gap: 12px;
}
button.ctrl {
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 8px;
  width: 44px; height: 44px;
  font-size: 17px;
  cursor: pointer;
  flex: none;
  transition: opacity .15s, transform .1s;
}
button.ctrl:active { transform: scale(.94); }
button.ctrl.ghost { background: #3e4c59; }
button.ctrl:disabled { opacity: .4; cursor: not-allowed; }

input[type=range]#seek {
  flex: 1;
  accent-color: var(--accent);
  height: 6px;
  cursor: pointer;
}
input[type=range]#seek:disabled { cursor: not-allowed; opacity: .5; }

.time {
  font-size: 12px;
  color: #9aa5b1;
  min-width: 96px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* ===== 로딩 인디케이터 ===== */
.loading {
  display: flex; flex-direction: column;
  align-items: center; gap: 12px;
  padding: 36px 0;
  color: #6b7280;
}
.spinner {
  width: 34px; height: 34px;
  border: 3px solid #d6d2c4;
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.loading-text { font-size: 14px; }

/* ===== 에러 패널 ===== */
.error-panel {
  display: flex; flex-direction: column;
  align-items: center; gap: 10px;
  padding: 30px 16px;
  text-align: center;
  color: #4b5563;
}
.error-icon { font-size: 38px; }
.error-title { font-size: 17px; font-weight: 700; color: var(--accent-problem); }
.error-msg { font-size: 14px; max-width: 420px; line-height: 1.5; }
.error-actions { display: flex; gap: 10px; margin-top: 8px; }
.error-actions button {
  background: var(--accent);
  color: #fff; border: none;
  border-radius: 8px;
  padding: 9px 16px;
  font-size: 14px; cursor: pointer;
}
.error-actions button.secondary { background: #6b7280; }

/* ===== 입력 패널 ===== */
.input-panel {
  margin-top: 18px;
  background: rgba(255, 255, 255, .05);
  border-radius: 10px;
  padding: 0 14px;
}
.input-panel summary {
  cursor: pointer;
  padding: 12px 0;
  font-size: 14px;
  color: #cdd5de;
  user-select: none;
}
.input-body { padding: 4px 0 16px; display: flex; flex-direction: column; gap: 12px; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field span { font-size: 12px; color: #9aa5b1; }
.field textarea,
.field input {
  background: #1f2530;
  border: 1px solid #3e4c59;
  border-radius: 6px;
  color: #e6e6e6;
  padding: 8px 10px;
  font-size: 14px;
  font-family: inherit;
  resize: vertical;
}
.field input[type=file] {
  padding: 6px 8px;
  font-size: 13px;
  cursor: pointer;
}
.image-preview {
  position: relative;
  display: inline-block;
  align-self: flex-start;
  border: 1px solid #3e4c59;
  border-radius: 6px;
  overflow: hidden;
  background: #1f2530;
}
.image-preview img {
  display: block;
  max-width: 220px;
  max-height: 160px;
  object-fit: contain;
}
.image-clear {
  position: absolute;
  top: 4px; right: 4px;
  width: 24px; height: 24px;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, .6);
  color: #fff;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
}

.input-actions { display: flex; gap: 10px; }
.btn-primary, .btn-secondary {
  border: none; border-radius: 6px;
  padding: 9px 16px;
  font-size: 14px; cursor: pointer;
}
.btn-primary { background: var(--accent); color: #fff; }
.btn-secondary { background: #3e4c59; color: #e6e6e6; }
.input-hint { font-size: 12px; color: #6b7280; line-height: 1.5; }
.input-hint code {
  background: #1f2530;
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 11px;
}
