/* ── Lectures Page ── */
function LecturesPage({ isLoggedIn, setShowLoginModal, user, setPage }) {
  const { t, lang } = useT();
  const sb = window.supabaseClient;

  /* ── 차년도 탭 & Supabase 강좌 목록 ── */
  const [yearTab,      setYearTab]      = useState(() => {
    // sessionStorage에 마지막 차년도 저장된 경우 복원
    const saved = sessionStorage.getItem('_lastYearTab');
    return saved ? Number(saved) : 4;
  });
  const [majorFilter,  setMajorFilter]  = useState('전체');
  const [dbCourses,    setDbCourses]    = useState([]);
  const [coursesLoading, setCoursesLoading] = useState(false);

  /* ── 스크립트 키워드 검색 ── */
  const [scriptSearch,    setScriptSearch]    = useState('');       // 입력값
  const [scriptResults,   setScriptResults]   = useState(null);     // null=미검색, []이상=결과
  const [scriptSearching, setScriptSearching] = useState(false);
  const [searchKeyword,   setSearchKeyword]   = useState('');       // 현재 하이라이트 키워드

  /* ── AI 시맨틱 검색 ── */
  const [aiQuery,     setAiQuery]     = useState('');
  const [aiSearching, setAiSearching] = useState(false);
  const [aiAnswer,    setAiAnswer]    = useState(null);  // { text, sources }
  const [showAiPanel, setShowAiPanel] = useState(false);       // 현재 하이라이트 키워드

  // yearTab에 따라 사용할 강좌 배열 결정
  // - 4차: DB 없으면 LECTURES 하드코딩 폴백 (year4 폴더)
  // - 나머지: DB 전용 (없으면 빈 배열)
  const _allCourses = (() => {
    if (dbCourses.length > 0) return dbCourses;
    if (yearTab !== 4) return [];
    return LECTURES.map(course => ({
      ...course,
      _yearFolder: 'year4',
      _preview: NAS_BASE + '/year4/' + course.folder + '/preview.mp4',
      sessions: course.sessions.map(sess => ({
        ...sess,
        clips: sess.clips.map(clip => {
          const parts = clip.file.split('-').map(Number);
          return { ...clip, _year: 'year4', _lesson: parts[0], _week: parts[1], _part: parts[2] };
        })
      }))
    }));
  })();
  const activeCourses = majorFilter === '전체'
    ? _allCourses
    : _allCourses.filter(c => c.major === majorFilter);

  /* ── 선택 상태 ── */
  const [selCourse,  setSelCourse]  = useState(null);
  const [selSession, setSelSession] = useState(null);
  const [clipIdx,    setClipIdx]    = useState(0);
  const [playing,    setPlaying]    = useState(false);

  /* ── 수강신청 상태 ── */
  const [enrollments,   setEnrollments]   = useState(new Set()); // Set<course_id(string)>
  const [enrollLoading, setEnrollLoading] = useState(null);      // 처리 중인 course_id | null

  /* ── 진도율 상태 ── */
  const [progressMap, setProgressMap] = useState({});   // { "folder_clipFile": seconds }
  const progressMapRef = useRef({});                     // 최신값 ref (타이머 클로저 문제 해결)
  const progressTimer = useRef(null);
  const resumeOfferedRef = useRef(new Set());
  const showResumeRef   = useRef(false);   // 사용자가 직접 강좌 클릭했을 때만 true            // 이미 팝업 띄운 progressKey 기록

  /* ── 미리보기 모달 상태 ── */
  const [previewCourse, setPreviewCourse] = useState(null); // null이면 모달 닫힘
  const previewVideoRef = useRef(null);

  /* ── 자막 상태 ── */
  const [activeSub,  setActiveSub]  = useState(lang === 'en' ? 'en' : lang === 'zh' ? 'zh' : 'ko');
  const [vttUrls,    setVttUrls]    = useState({});
  const [subLoading, setSubLoading] = useState(false);
  const videoRef     = useRef(null);
  const prevBlobsRef = useRef({});

  /* ── 트랜스크립트 상태 ── */
  const [transcript,      setTranscript]      = useState([]);   // [{start, end, text}]
  const [activeScriptIdx, setActiveScriptIdx] = useState(-1);
  const [showTranscript,  setShowTranscript]  = useState(true);
  const transcriptRef    = useRef(null);  // 컨테이너 ref (자동 스크롤용)

  /* 파생값 */
  const currentClip  = selSession?.clips?.[clipIdx] ?? null;
  // progressKey: yearTab_lesson_clipFile (차년도 구분)
  const progressKey  = currentClip ? `${yearTab}_${String(selCourse?.folder)}_${currentClip.file}` : null;
  const courseKey    = selCourse ? `${yearTab}_${selCourse.folder}` : null;
  const isEnrolled   = courseKey ? enrollments.has(courseKey) : false;
  const canWatch     = isLoggedIn && isEnrolled && !!selCourse;

  /* ════════════════════════════════════════════
     마이페이지 이어보기 + 검색어 딥링크 처리
  ════════════════════════════════════════════ */
  useEffect(() => {
    // 검색어 복원
    const kw = sessionStorage.getItem('_searchKeyword');
    if (kw) {
      sessionStorage.removeItem('_searchKeyword');
      setSearchKeyword(kw);
      setScriptSearch(kw);
    }

    const courseId = sessionStorage.getItem('resumeCourseId');
    const clipFile = sessionStorage.getItem('resumeClipFile');
    if (!courseId) return;
    sessionStorage.removeItem('resumeCourseId');
    sessionStorage.removeItem('resumeClipFile');
    // courseId 형식: "4_1" (yearTab_folder) 또는 레거시 "1" (4차)
    const parts     = String(courseId).split('_');
    const tabYear   = parts.length === 2 ? Number(parts[0]) : 4;
    const folderNum = parts.length === 2 ? String(parts[1]) : String(courseId);

    setYearTab(tabYear);
    // activeCourses는 yearTab 변경 후 useEffect로 로드됨
    // 딥링크 정보를 ref에 저장해 두고 courses 로드 완료 후 처리
    sessionStorage.setItem('_deeplink_year',   String(tabYear));
    sessionStorage.setItem('_deeplink_folder', folderNum);
    if (clipFile) sessionStorage.setItem('_deeplink_clip', clipFile);
  }, []);

  /* ════════════════════════════════════════════
     차년도 탭 변경 → Supabase에서 강좌 로드
     courses 테이블: id, name, folder(lesson번호),
       year_segment, thumbnail_url,
       sessions: [{session, group, clips:[{file}]}]
     getNasPaths(year, lesson, week, part) 로 URL 조립
  ════════════════════════════════════════════ */
  useEffect(() => {
    setCoursesLoading(true);
    setDbCourses([]);
    // 선택 상태 초기화
    setSelSession(null);
    setClipIdx(0);
    setPlaying(false);

    sb.from('courses')
      .select('*')
      .eq('year_segment', yearTab)
      .order('folder', { ascending: true })
      .then(({ data, error }) => {
        setCoursesLoading(false);
        if (error || !data?.length) {
          // DB에 데이터 없음 → 1차년도면 하드코딩 폴백 사용
          setDbCourses([]);
                // 4차 폴백일 때 딥링크 처리
          const dlYear2   = sessionStorage.getItem('_deeplink_year');
          const dlFolder2 = sessionStorage.getItem('_deeplink_folder');
          const dlClip2   = sessionStorage.getItem('_deeplink_clip');
          if (dlYear2 && dlFolder2 && Number(dlYear2) === yearTab && yearTab === 4) {
            sessionStorage.removeItem('_deeplink_year');
            sessionStorage.removeItem('_deeplink_folder');
            sessionStorage.removeItem('_deeplink_clip');
            const lec = LECTURES.find(c => String(c.folder) === dlFolder2);
            if (lec) {
              const withMeta = { ...lec, _yearFolder:'year4',
                sessions: lec.sessions.map(s => ({ ...s, clips: s.clips.map(clip => {
                  const p = clip.file.split('-').map(Number);
                  return { ...clip, _year:'year4', _lesson:p[0], _week:p[1], _part:p[2] };
                })}))
              };
              setSelCourse(withMeta);
              if (dlClip2) {
                for (const sess of withMeta.sessions) {
                  const idx = sess.clips.findIndex(c => c.file === dlClip2);
                  if (idx !== -1) { setSelSession(sess); setClipIdx(idx); break; }
                }
              } else { setSelSession(withMeta.sessions[0]); setClipIdx(0); }
              return;
            }
          }
          setSelCourse(null);
          return;
        }

        // Supabase rows → LECTURES 형식으로 변환
        // 각 row: { id, name, folder, year_segment, sessions: [...] }
        // sessions[].clips[]: { week, part } → getNasPaths로 url/file 생성
        const yearFolder = YEAR_FOLDER[yearTab] || `year${yearTab}`;
        const converted = data.map(row => {
          const lesson    = Number(row.folder);            // DB 표시순서(목록 정렬·딥링크용)
          const nasLesson = nasLessonFor(yearTab, lesson);  // NAS 실제 폴더번호(영상·자막·프리뷰 경로용)
          const paths0 = getNasPaths(yearFolder, nasLesson, 1, 1); // thumbnail/preview용
          const sessions = (row.sessions || []).map(sess => {
            const clips = (sess.clips || []).map(clip => {
              const week = Number(clip.week ?? clip.week_num ?? 1);
              const part = Number(clip.part ?? clip.part_num ?? 1);
              const p = getNasPaths(yearFolder, nasLesson, week, part);
              return {
                ...clip,            // topic 등 원본 필드 유지
                file: `${nasLesson}-${week}-${part}`,
                url:  p.video,
                _year: yearFolder,
                _lesson: nasLesson,
                _week: week,
                _part: part,
              };
            });
            return { ...sess, clips };
          });
          return {
            folder:    lesson,
            name:      row.name,
            nameEn:    row.name_en || '',  // 영문 강좌명 (DB name_en 컬럼)
            major:     row.major || '',
            thumbnail: row.thumbnail_url || paths0.thumbnail,
            _yearFolder: yearFolder,
            _preview:  paths0.preview,
            sessions,
          };
        });

        setDbCourses(converted);

        // 딥링크 처리 (sessionStorage에 저장된 경우)
        const dlYear   = sessionStorage.getItem('_deeplink_year');
        const dlFolder = sessionStorage.getItem('_deeplink_folder');
        const dlClip   = sessionStorage.getItem('_deeplink_clip');
        if (dlYear && dlFolder && Number(dlYear) === yearTab) {
          sessionStorage.removeItem('_deeplink_year');
          sessionStorage.removeItem('_deeplink_folder');
          sessionStorage.removeItem('_deeplink_clip');
          // 검색어 복원 (검색 결과에서 넘어온 경우)
          const dlKw = sessionStorage.getItem('_searchKeyword');
          if (dlKw) sessionStorage.removeItem('_searchKeyword');

          const target = converted.find(c => String(c.folder) === dlFolder);
          if (target) {
            if (dlKw) {
              // 검색어 있으면 키워드 포함 클립 탐색
              setSearchKeyword(dlKw);
              findAndGoToKeywordClip(target, dlKw);
            } else if (dlClip) {
              setSelCourse(target);
              let found = false;
              for (const sess of target.sessions) {
                const idx = sess.clips.findIndex(c => c.file === dlClip);
                if (idx !== -1) {
                  setSelSession(sess);
                  setClipIdx(idx);
                  setPlaying(true);
                  // 이어보기 시간 — progressMapRef에서 가져오기
                  const progKey = `${yearTab}_${target.folder}_${dlClip}`;
                  const savedPos = progressMapRef.current[progKey];
                  if (savedPos && savedPos > 5) {
                    sessionStorage.setItem('_jump_time', String(savedPos));
                  }
                  found = true;
                  break;
                }
              }
              if (!found) { setSelSession(target.sessions[0]); setClipIdx(0); }
            } else {
              setSelCourse(target);
              setSelSession(target.sessions[0]);
              setClipIdx(0);
            }
            return;
          }
        }

        setSelCourse(converted[0]);
        setSelSession(converted[0]?.sessions?.[0] || null);
      });
  }, [yearTab]);

  // 마지막 차년도 저장 + 전공필터 초기화
  useEffect(() => {
    sessionStorage.setItem('_lastYearTab', String(yearTab));
    setMajorFilter('전체');
  }, [yearTab]);

  /* ════════════════════════════════════════════
     이용 통계 — 강의 탭 진입 시 view_count +1
  ════════════════════════════════════════════ */
  useEffect(() => {
    const yearFolder = YEAR_FOLDER[yearTab] || `year${yearTab}`;
    sb.from('stats_usage')
      .upsert(
        { year_segment: yearTab, view_count: 1, last_viewed: new Date().toISOString() },
        { onConflict: 'year_segment', ignoreDuplicates: false }
      )
      .then(() => {})
      .catch(() => {});
    // 강좌별 상세 통계는 selCourse 변경 시 업데이트
  }, [yearTab]);

  useEffect(() => {
    if (!selCourse) return;
    const yearFolder = YEAR_FOLDER[yearTab] || `year${yearTab}`;
    sb.rpc('increment_course_views', {
      p_year_segment: yearTab,
      p_lesson:       selCourse.folder,
    }).then(() => {}).catch(() => {});
  }, [selCourse?.folder, yearTab]);

  /* ════════════════════════════════════════════
     수강신청 목록 로드 (로그인 시)
  ════════════════════════════════════════════ */
  useEffect(() => {
    if (!isLoggedIn || !user?.id) { setEnrollments(new Set()); return; }
    sb.from('enrollments')
      .select('course_id')
      .eq('user_id', user.id)
      .then(({ data, error }) => {
        if (error) { console.error('[Enroll] fetch:', error.message); return; }
        // 레거시(숫자만) → '4_N', 신규('yearTab_folder') 그대로
        const keys = (data || []).map(r => {
          const id = String(r.course_id);
          return /^[0-9]+$/.test(id) ? '4_' + id : id;
        });
        setEnrollments(new Set(keys));
      });
  }, [isLoggedIn, user?.id]);

  /* ════════════════════════════════════════════
     진도율 전체 로드 (로그인 시)
  ════════════════════════════════════════════ */
  useEffect(() => {
    if (!isLoggedIn || !user?.id) { setProgressMap({}); return; }
    sb.from('progress')
      .select('course_id, clip_file, last_position')
      .eq('user_id', user.id)
      .then(({ data, error }) => {
        if (error) { console.error('[Progress] fetch:', error.message); return; }
        const map = {};
        // course_id 형식: "yearTab_folder" 또는 레거시 "folder"
        (data || []).forEach(r => {
          const cid = String(r.course_id);
          const cf  = r.clip_file;
          // 신규 형식 그대로 등록 (예: "4_1_1-1-1")
          map[`${cid}_${cf}`] = r.last_position;
          // 레거시(숫자만) → 4차년도로 취급하여 "4_N_clip" 도 등록
          if (/^[0-9]+$/.test(cid)) {
            map[`4_${cid}_${cf}`] = r.last_position;
          }
        });
        progressMapRef.current = map;
        setProgressMap(map);

        // 마지막으로 본 강좌의 차년도로 탭 자동 설정
        // (이미 sessionStorage에 저장된 경우 그것 우선)
        if (!sessionStorage.getItem('_lastYearTab') && data?.length > 0) {
          // course_id에서 yearTab 추출
          const lastCid = data[0]?.course_id;
          if (lastCid) {
            const yr = parseInt(String(lastCid).split('_')[0]);
            if (yr >= 1 && yr <= 5) setYearTab(yr);
          }
        }
      });
  }, [isLoggedIn, user?.id]);

  /* ════════════════════════════════════════════
     수강신청 핸들러
  ════════════════════════════════════════════ */
  const handleEnroll = async (course) => {
    if (!isLoggedIn) {
      Swal.fire({
        icon: 'info',
        title: t('swal_login_needed_title'),
        text: '수강신청은 로그인 후 가능합니다.',
        confirmButtonText: t('swal_login_needed_confirm'),
        cancelButtonText:  t('swal_login_needed_cancel'),
        confirmButtonColor: '#0f172a',
        showCancelButton: true,
      }).then(r => { if (r.isConfirmed) setShowLoginModal('login'); });
      return;
    }
    const cid = `${yearTab}_${course.folder}`;  // 차년도_강좌번호 형식
    setEnrollLoading(cid);

    const { error } = await sb.from('enrollments').insert({ user_id: user.id, course_id: cid });
    setEnrollLoading(null);

    if (error) {
      if (error.code === '23505') {           // 이미 신청됨 (unique constraint)
        setEnrollments(prev => new Set([...prev, cid]));
        Swal.fire({ icon:'info', title:'이미 수강신청된 강좌입니다.', timer:1800, showConfirmButton:false });
      } else {
        Swal.fire({ icon:'error', title:'오류 발생', text: error.message });
      }
      return;
    }

    setEnrollments(prev => new Set([...prev, cid]));
    Swal.fire({
      icon: 'success',
      title: '수강신청 완료!',
      html: `<b>${course.name}</b><br/>지금 바로 학습을 시작하세요.`,
      confirmButtonText: '학습하기',
      confirmButtonColor: '#0f172a',
    }).then(() => pickCourse(course));
  };

  /* ════════════════════════════════════════════
     진도율 저장 (upsert) — useCallback으로 최신 ref 참조
  ════════════════════════════════════════════ */
  const saveProgress = useCallback(async () => {
    const v = videoRef.current;
    if (!v || !isLoggedIn || !user?.id || !currentClip || v.currentTime < 2) return;
    const pos = Math.floor(v.currentTime);
    // ── max 진도 유지: ref로 최신값 참조 (타이머 클로저 문제 없음) ──
    const key     = `${yearTab}_${String(selCourse?.folder)}_${currentClip.file}`;
    const prevPos = progressMapRef.current[key] || 0;
    const savePos = Math.max(pos, prevPos);
    const cKey    = selCourse ? `${yearTab}_${selCourse.folder}` : String(selCourse?.folder);
    const { error } = await sb.from('progress').upsert(
      { user_id: user.id,
        course_id: cKey,
        clip_file: String(currentClip.file),
        last_position: savePos },
      { onConflict: 'user_id,course_id,clip_file' }
    );
    if (!error) {
      progressMapRef.current = { ...progressMapRef.current, [key]: savePos };
      setProgressMap(prev => ({ ...prev, [key]: savePos }));
      console.log(`[Progress ✅] saved ${savePos}s → ${cKey}_${currentClip.file}`);
    } else {
      console.warn('[Progress ❌] upsert:', error.message);
    }
  }, [isLoggedIn, user?.id, currentClip, selCourse?.folder, yearTab]);

  /* 10초 타이머 관리 */
  useEffect(() => {
    if (progressTimer.current) clearInterval(progressTimer.current);
    if (!isLoggedIn || !canWatch || !currentClip) return;
    progressTimer.current = setInterval(saveProgress, 10000);
    return () => clearInterval(progressTimer.current);
  }, [saveProgress, isLoggedIn, canWatch, currentClip]);

  /* ════════════════════════════════════════════
     이어보기 팝업 (클립 바뀔 때)
  ════════════════════════════════════════════ */
  useEffect(() => {
    if (!canWatch || !selCourse) return;
    // 사용자가 직접 강좌 클릭했을 때만 팝업
    if (!showResumeRef.current) return;
    showResumeRef.current = false;
    // 이미 팝업 띄운 강좌면 스킵
    if (resumeOfferedRef.current.has(selCourse.folder)) return;

    // 이 강좌의 모든 클립 중 진도 기록이 있는 가장 마지막 클립 찾기
    const allClips = (selCourse.sessions || []).flatMap(sess =>
      (sess.clips || []).map(clip => ({ sess, clip }))
    );

    // 진도 기록이 있는 클립 중 가장 마지막 인덱스
    let lastIdx = -1;
    let lastSaved = 0;
    let lastSess = null;
    let lastClip = null;

    allClips.forEach(({ sess, clip }, idx) => {
      const key = `${yearTab}_${selCourse.folder}_${clip.file}`;
      const pos = progressMapRef.current[key] || 0;
      if (pos >= 5) {
        lastIdx  = idx;
        lastSaved = pos;
        lastSess  = sess;
        lastClip  = clip;
      }
    });

    if (lastIdx < 0 || !lastSess || !lastClip) return;

    resumeOfferedRef.current.add(selCourse.folder);
    const fmt = s => `${Math.floor(s / 60)}분 ${String(s % 60).padStart(2,'0')}초`;

    const tryOffer = () => {
      Swal.fire({
        icon: 'question',
        title: t('lec_resume_title'),
        text: `${lastSess.session || ''} ${lastClip.file || ''} — ${fmt(lastSaved)}까지 시청했습니다. 이어서 보시겠습니까?`,
        confirmButtonText: t('lec_resume_btn').replace('{t}', fmt(lastSaved)),
        cancelButtonText:  t('lec_restart'),
        confirmButtonColor: '#0f172a',
        showCancelButton: true,
      }).then(r => {
        if (r.isConfirmed) {
          // 마지막으로 본 클립으로 이동
          setSelSession(lastSess);
          const ci = (lastSess.clips || []).findIndex(c => c.file === lastClip.file);
          setClipIdx(ci >= 0 ? ci : 0);
          setPlaying(true);
          // 시간 점프는 영상 로드 후
          setTimeout(() => {
            if (videoRef.current) {
              videoRef.current.currentTime = lastSaved;
              videoRef.current.play().catch(() => {});
            }
          }, 800);
        }
      });
    };

    // 약간 딜레이 후 팝업 (영상 초기화 완료 후)
    setTimeout(tryOffer, 500);

  }, [selCourse?.folder, canWatch]);  // 강좌 바뀔 때만

  /* ════════════════════════════════════════════
     SRT → VTT / 자막 fetch
  ════════════════════════════════════════════ */
  /* SRT → VTT (video track용) */
  const srtToVtt = (srt) =>
    'WEBVTT\n\n' + srt.trim()
      .replace(/\r\n/g, '\n').replace(/\r/g, '\n')
      .replace(/(\d{2}:\d{2}:\d{2}),(\d{3})/g, '$1.$2');

  /* SRT → [{start(초), end(초), text}] 배열 파서 */
  const parseSrt = (srt) => {
    const lines = srt.trim().replace(/\r\n/g,'\n').replace(/\r/g,'\n').split('\n');
    const result = [];
    let i = 0;
    const toSec = (ts) => {
      const [h,m,s] = ts.replace(',','.').split(':');
      return Number(h)*3600 + Number(m)*60 + parseFloat(s);
    };
    while (i < lines.length) {
      // 번호 줄 스킵
      if (/^\d+$/.test(lines[i]?.trim())) i++;
      // 타임스탬프 줄
      const tsLine = lines[i]?.trim() || '';
      const tsMatch = tsLine.match(/(\d{2}:\d{2}:\d{2}[,.]\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2}[,.]\d{3})/);
      if (tsMatch) {
        i++;
        const textLines = [];
        while (i < lines.length && lines[i].trim() !== '') {
          textLines.push(lines[i].trim());
          i++;
        }
        const text = textLines.join(' ').trim();
        if (text) result.push({ start: toSec(tsMatch[1]), end: toSec(tsMatch[2]), text });
      } else {
        i++;
      }
    }
    return result;
  };

  useEffect(() => {
    if (!currentClip || !selCourse) return;
    Object.values(prevBlobsRef.current).forEach(u => URL.revokeObjectURL(u));
    prevBlobsRef.current = {};
    setVttUrls({});
    setSubLoading(true);
    setTranscript([]);      // 클립 바뀌면 트랜스크립트 초기화
    setActiveScriptIdx(-1);

    const getSubUrl = (code) => currentClip._year
      ? getNasPaths(currentClip._year, currentClip._lesson, currentClip._week, currentClip._part).subtitle(code)
      : subUrl(selCourse.folder, currentClip.file, code);

    Promise.all(
      [{ key:'ko', code:'k' }, { key:'en', code:'e' }, { key:'zh', code:'c' }].map(({ key, code }) => {
        const url = getSubUrl(code);
        return fetch(url)
          .then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.text(); })
          .then(srt => {
            // 현재 lang에 맞는 자막은 트랜스크립트 파싱도 수행
            const transcriptLang = lang === 'en' ? 'en' : lang === 'zh' ? 'zh' : 'ko';
            if (key === transcriptLang) {
              const parsed = parseSrt(srt);
              setTranscript(parsed);
              console.info(`[Transcript ✅] ${parsed.length}개 문장 파싱`);
            }
            const blobUrl = URL.createObjectURL(new Blob([srtToVtt(srt)], { type:'text/vtt' }));
            console.info(`[Subtitle ✅] ${key}:`, url);
            return { key, url: blobUrl };
          })
          .catch(err => { console.warn(`[Subtitle ❌] ${key}:`, err.message); return { key, url: null }; });
      })
    ).then(results => {
      const map = {};
      results.forEach(({ key, url }) => { if (url) map[key] = url; });
      prevBlobsRef.current = map;
      setVttUrls(map);
      // lang에 맞는 자막 자동 선택
      const preferLang = lang === 'en' ? 'en' : lang === 'zh' ? 'zh' : 'ko';
      if (map[preferLang]) setActiveSub(preferLang);
      else if (map.ko) setActiveSub('ko');
      setSubLoading(false);
    });

    return () => { Object.values(prevBlobsRef.current).forEach(u => URL.revokeObjectURL(u)); };
  }, [currentClip?.url]);

  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    const apply = () => {
      Array.from(v.textTracks).forEach(track => {
        track.mode = (activeSub !== 'off' && track.language === activeSub) ? 'showing' : 'disabled';
      });
    };
    if (v.readyState >= 1) apply();
    else v.addEventListener('loadedmetadata', apply, { once: true });
  }, [activeSub, vttUrls]);

  /* ════════════════════════════════════════════
     트랜스크립트 — timeupdate 연동
  ════════════════════════════════════════════ */
  useEffect(() => {
    const v = videoRef.current;
    if (!v || transcript.length === 0) return;
    const onTimeUpdate = () => {
      const ct = v.currentTime;
      // 이진탐색으로 현재 시간에 해당하는 자막 찾기
      let lo = 0, hi = transcript.length - 1, found = -1;
      while (lo <= hi) {
        const mid = (lo + hi) >> 1;
        if (transcript[mid].end < ct) lo = mid + 1;
        else if (transcript[mid].start > ct) hi = mid - 1;
        else { found = mid; break; }
      }
      setActiveScriptIdx(prev => {
        if (prev === found) return prev;
        // 자동 스크롤
        if (found >= 0 && transcriptRef.current) {
          const el = transcriptRef.current.querySelector(`[data-idx="${found}"]`);
          if (el) el.scrollIntoView({ block:'nearest', behavior:'smooth' });
        }
        return found;
      });
    };
    v.addEventListener('timeupdate', onTimeUpdate);
    return () => v.removeEventListener('timeupdate', onTimeUpdate);
  }, [transcript, videoRef.current]);

  /* ════════════════════════════════════════════
     검색어 하이라이트 — 트랜스크립트 로드 후
  ════════════════════════════════════════════ */
  useEffect(() => {
    if (!searchKeyword || transcript.length === 0) return;
    const kw = searchKeyword.toLowerCase();
    const firstIdx = transcript.findIndex(s => s.text.toLowerCase().includes(kw));
    if (firstIdx < 0) return;

    const targetTime = transcript[firstIdx].start;

    // 영상 시간 이동
    if (videoRef.current && canWatch) {
      setTimeout(() => {
        if (videoRef.current) {
          videoRef.current.currentTime = targetTime;
          videoRef.current.play().catch(() => {});
        }
      }, 400);
    }

    // 트랜스크립트 스크롤
    setTimeout(() => {
      const el = transcriptRef.current?.querySelector(`[data-idx="${firstIdx}"]`);
      if (el) el.scrollIntoView({ block: 'center', behavior: 'smooth' });
    }, 300);
  }, [transcript, searchKeyword]);

  /* ════════════════════════════════════════════
     강좌 / 차시 / 클립 선택
  ════════════════════════════════════════════ */
  const pickCourse = (course) => {
    resumeOfferedRef.current.clear();
    showResumeRef.current = true;   // 직접 강좌 클릭 시만 팝업 허용
    setSelCourse(course);
    setSelSession(course.sessions[0]);
    setClipIdx(0);
    setPlaying(false);
  };

  const pickSession = (session) => {
    if (!session) { setSelSession(null); return; }
    if (!isLoggedIn) {
      Swal.fire({
        icon:'info', title: t('swal_login_needed_title'), text: t('swal_login_needed_text'),
        confirmButtonText: t('swal_login_needed_confirm'), confirmButtonColor:'#0f172a',
        cancelButtonText: t('swal_login_needed_cancel'), showCancelButton: true,
      }).then(r => { if (r.isConfirmed) setShowLoginModal('login'); });
      return;
    }
    if (!isEnrolled) {
      Swal.fire({
        icon:'info', title: t('swal_enroll_required') || '수강신청이 필요합니다',
        text:'이 강좌는 수강신청 후 시청하실 수 있습니다.',
        confirmButtonText:'수강신청하기', cancelButtonText:'취소',
        confirmButtonColor:'#0f172a', showCancelButton: true,
      }).then(r => { if (r.isConfirmed) handleEnroll(selCourse); });
      return;
    }
    // 다른 주차로 이동 전 현재 클립 저장
    if (videoRef.current && canWatch && currentClip && progressKey) {
      const v = videoRef.current;
      const prevPos = progressMapRef.current[progressKey] || 0;
      if (v.currentTime >= 2 || prevPos >= 2) saveProgress();
    }
    setSelSession(session);
    setClipIdx(0);
    setPlaying(true);
    // 모바일: 영상 영역으로 스크롤
    setTimeout(() => {
      const el = document.querySelector('.lectures-player-area');
      if (el && window.innerWidth < 1024) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }, 100);
  };

  const pickClip = (idx) => {
    // 현재 클립 진도 저장 (다른 클립으로 이동 전)
    if (videoRef.current && canWatch && currentClip && progressKey) {
      const v = videoRef.current;
      const prevPos = progressMap[progressKey] || 0;
      // 영상이 실제로 재생됐으면 현재 위치 저장 (최소 2초 이상)
      if (v.currentTime >= 2 || prevPos >= 2) saveProgress();
    }
    setClipIdx(idx);
    setPlaying(true);
    // 모바일: 영상 영역으로 스크롤
    setTimeout(() => {
      const el = document.querySelector('.lectures-player-area');
      if (el && window.innerWidth < 1024) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }, 100);
  };

  const onClipEnded = () => {
    saveProgress();
    if (clipIdx < selSession.clips.length - 1) setClipIdx(i => i + 1);
    else setPlaying(false);
  };

  /* 강좌별 진도율 0~100% — 순서 기준: 시청된 가장 마지막 클립까지의 비율 */
  const getCourseProgress = (course) => {
    const clips = course.sessions.flatMap(s => s.clips);
    if (!clips.length) return 0;
    // 전체 클립 중 진도 기록이 있는 마지막 인덱스 찾기
    let lastIdx = -1;
    clips.forEach((c, i) => {
      if ((progressMapRef.current[`${yearTab}_${course.folder}_${c.file}`] || 0) > 0) lastIdx = i;
    });
    if (lastIdx < 0) return 0;
    return Math.round((lastIdx + 1) / clips.length * 100);
  };

  /* ════════════════════════════════════════════
     스크립트 키워드 검색
  ════════════════════════════════════════════ */
  /* ════ AI 시맨틱 검색 ════ */
  const handleAiSearch = async () => {
    const q = aiQuery.trim();
    if (!q) return;

    // 로그인 세션 확인 — 비로그인 호출 차단 (무인증 API 남용 방지)
    const { data: { session } } = await window.supabaseClient.auth.getSession();
    if (!session) {
      setShowAiPanel(true);
      setAiAnswer({ text: 'AI 검색을 이용하려면 먼저 로그인해주세요.', sources: [] });
      return;
    }

    setAiSearching(true);
    setAiAnswer(null);
    setShowAiPanel(true);
    try {
      // 1) Supabase Edge Function으로 임베딩 + 검색 (유저 JWT 전달)
      const edgeRes = await fetch(
        'https://hhcwmvcrhfrbwwwwozld.supabase.co/functions/v1/ai-search',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'apikey':        SUPABASE_ANON,              // Supabase 게이트웨이 라우팅용
            'Authorization': `Bearer ${session.access_token}`,  // 유저 식별용
          },
          body: JSON.stringify({ query: q, match_count: 5, match_threshold: 0.25, lang: lang === 'en' ? 'en' : lang === 'zh' ? 'zh' : 'ko' }),
        }
      );
      const edgeData = await edgeRes.json();
      if (!edgeRes.ok || edgeData.error) {
        throw new Error(edgeData.error || '오류: ' + edgeRes.status);
      }
      const chunks = edgeData.chunks || [];
      const answerText = edgeData.answer || '';

      if (!chunks.length) {
        setAiAnswer({ text: answerText || '관련 강의 내용을 찾지 못했습니다.', sources: [] });
        setAiSearching(false); return;
      }

      setAiAnswer({
        text: answerText,
        sources: chunks.map(c => ({
          courseId:    c.course_id,
          yearSegment: c.year_segment,
          lesson:      c.folder ?? c.lesson,   // edge function 이 보정한 DB folder (year3 NAS→folder)
          clipFile:    c.clip_file,
          startTime:   c.start_time,
          courseName:  c.courseName || c.course_id,
          excerpt:     (c.content||'').slice(0,80)+'…',
          similarity:  Math.round((c.similarity||0)*100),
        })),
      });
    } catch(err) {
      console.error('[AI Search]', err);
      setAiAnswer({ text:`오류가 발생했습니다: ${err.message}`, sources:[] });
    }
    setAiSearching(false);
  };

  const goToAiSource = (src) => {
    // 패널 닫지 않음 — 답변 유지
    sessionStorage.setItem('_jump_time', String(src.startTime));
    if (src.yearSegment === yearTab) {
      const course = activeCourses.find(c => String(c.folder) === String(src.lesson));
      if (course) {
        for (const sess of course.sessions||[]) {
          const ci = (sess.clips||[]).findIndex(c => c.file === src.clipFile);
          if (ci !== -1) {
            setSelCourse(course); setSelSession(sess); setClipIdx(ci); setPlaying(true);
            setTimeout(()=>{ document.querySelector('.lectures-player-area')?.scrollIntoView({behavior:'smooth',block:'start'}); },100);
            return;
          }
        }
        setSelCourse(course); setSelSession(course.sessions?.[0]); setClipIdx(0);
        return;
      }
    }
    sessionStorage.setItem('_deeplink_year',   String(src.yearSegment));
    sessionStorage.setItem('_deeplink_folder', String(src.lesson));
    sessionStorage.setItem('_deeplink_clip',   src.clipFile);
    setYearTab(src.yearSegment);
  };

  const handleScriptSearch = async () => {
    const kw = scriptSearch.trim();
    if (!kw) { setScriptResults(null); return; }
    setScriptSearching(true);
    // Supabase full_script 컬럼 검색
    const { data, error } = await sb
      .from('courses')
      .select('year_segment, folder, name, full_script')
      .ilike('full_script', `%${kw}%`)
      .order('year_segment', { ascending: true })
      .order('folder', { ascending: true });
    setScriptSearching(false);
    if (error) { console.error('[ScriptSearch]', error.message); return; }
    setScriptResults(data || []);
  };

  const goToSearchResult = (row) => {
    const kw         = scriptSearch.trim();
    const targetYear = row.year_segment;
    const targetFold = String(row.folder);

    setScriptResults(null);
    setScriptSearch('');
    setShowTranscript(true);
    setSearchKeyword(kw);

    if (targetYear === yearTab) {
      // ── 같은 탭: activeCourses에서 바로 찾아 이동 ──
      const course = activeCourses.find(c => String(c.folder) === targetFold);
      if (course) {
        // 키워드 포함 클립 탐색 후 해당 클립으로 이동
        findAndGoToKeywordClip(course, kw);
        setTimeout(() => {
          const el = document.querySelector('.lectures-player-area');
          if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }, 100);
        return;
      }
    }

    // ── 다른 탭: sessionStorage 딥링크 방식 ──
    sessionStorage.setItem('_searchKeyword',   kw);
    sessionStorage.setItem('_deeplink_year',   String(targetYear));
    sessionStorage.setItem('_deeplink_folder', targetFold);
    setYearTab(targetYear);  // → courses load useEffect 재실행 → 딥링크 처리
  };

  /* ════════════════════════════════════════════
     키워드 포함 클립 탐색 → 해당 주차/클립으로 이동
  ════════════════════════════════════════════ */
  const findAndGoToKeywordClip = async (course, keyword) => {
    // 1) 일단 강좌 선택 (첫 세션/클립)
    setSelCourse(course);
    setSelSession(course.sessions?.[0] || null);
    setClipIdx(0);
    setPlaying(false);

    if (!keyword) return;

    const kw          = keyword.toLowerCase();
    const yearFolder  = course._yearFolder || YEAR_FOLDER[yearTab] || `year${yearTab}`;
    const lesson      = course.folder;
    const allSessions = course.sessions || [];

    // 2) 모든 클립을 순서대로 순회하며 자막 fetch
    for (const sess of allSessions) {
      for (let ci = 0; ci < sess.clips.length; ci++) {
        const clip = sess.clips[ci];
        // 자막 URL 생성
        const subUrlStr = clip._year
          ? getNasPaths(clip._year, clip._lesson, clip._week, clip._part).subtitle('k')
          : subUrl(lesson, clip.file, 'k');

        try {
          const r = await fetch(subUrlStr);
          if (!r.ok) continue;
          const srtText = await r.text();
          if (srtText.toLowerCase().includes(kw)) {
            // 키워드 발견 → 해당 세션/클립으로 이동
            setSelCourse(course);
            setSelSession(sess);
            setClipIdx(ci);
            setPlaying(true);
            console.log(`[KeywordNav ✅] "${keyword}" → ${sess.session} 클립 ${ci+1} (${clip.file})`);
            return;
          }
        } catch (e) { /* 자막 없으면 skip */ }
      }
    }
    // 못 찾으면 첫 클립 유지 (이미 set됨)
    console.log(`[KeywordNav] "${keyword}" 포함 클립 없음 → 첫 클립 유지`);
  };

  /* ════════════════════════════════════════════
     미리보기 모달 닫기 핸들러
  ════════════════════════════════════════════ */
  const closePreview = () => {
    if (previewVideoRef.current) {
      previewVideoRef.current.pause();
      previewVideoRef.current.src = '';
    }
    setPreviewCourse(null);
  };

  /* ════════════════════════════════════════════
     RENDER
  ════════════════════════════════════════════ */
  return (
    <div className="pt-[104px] min-h-screen bg-gray-50">

      {/* ══════════════════════════════════════
          미리보기 모달
      ══════════════════════════════════════ */}
      {previewCourse && (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center p-4"
          style={{ background: 'rgba(0,0,0,0.82)' }}
          onClick={e => { if (e.target === e.currentTarget) closePreview(); }}
        >
          <div className="relative w-full max-w-3xl bg-black rounded-2xl overflow-hidden shadow-2xl"
               style={{ animation: 'fadeInScale .2s ease' }}>

            {/* 모달 헤더 */}
            <div className="flex items-center justify-between px-5 py-3 bg-gray-950 border-b border-white/10">
              <div>
                <span className="text-xs font-bold text-blue-400 uppercase tracking-widest mr-2">미리보기</span>
                <span className="text-white font-semibold text-sm">{previewCourse.folder}강 — {previewCourse.name}</span>
              </div>
              <button
                onClick={closePreview}
                className="w-8 h-8 flex items-center justify-center rounded-lg bg-white/10 hover:bg-white/20 text-white/70 hover:text-white transition-colors text-sm"
              >
                <i className="fas fa-times" />
              </button>
            </div>

            {/* 비디오 (progress 저장 없음) */}
            <video
              ref={previewVideoRef}
              key={previewCourse.folder}
              src={previewCourse._preview || previewUrl(previewCourse.folder)}
              controls
              autoPlay
              playsInline
              onError={e => {
                e.target.style.display = 'none';
                e.target.nextSibling && (e.target.nextSibling.style.display = 'flex');
              }}
              style={{ width: '100%', maxHeight: '480px', display: 'block', background: '#000' }}
            />
            {/* 영상 없을 때 폴백 */}
            <div style={{ display:'none', height:'300px', alignItems:'center', justifyContent:'center', flexDirection:'column', gap:'10px' }}>
              <i className="fas fa-film text-5xl text-white/20" />
              <p className="text-white/50 text-sm">미리보기 영상이 준비 중입니다.</p>
              <p className="text-white/30 text-xs">{previewCourse._preview || previewUrl(previewCourse.folder)}</p>
            </div>

            {/* 모달 하단: 수강신청 유도 */}
            <div className="flex items-center justify-between px-5 py-3 bg-gray-950 border-t border-white/10">
              <p className="text-white/50 text-xs">전체 강의는 수강신청 후 시청하실 수 있습니다.</p>
              <button
                onClick={() => { closePreview(); handleEnroll(previewCourse); }}
                disabled={enrollments.has(`${yearTab}_${previewCourse.folder}`) || enrollLoading === `${yearTab}_${previewCourse.folder}`}
                className="flex items-center gap-1.5 px-4 py-1.5 bg-white text-navy-900 text-xs font-bold rounded-full hover:bg-gray-100 transition disabled:opacity-50"
              >
                {enrollments.has(`${yearTab}_${previewCourse.folder}`)
                  ? <><i className="fas fa-check" />수강신청 완료</>
                  : enrollLoading === `${yearTab}_${previewCourse.folder}`
                    ? <><i className="fas fa-spinner fa-spin" />{t('lec_processing')}</>
                    : <><i className="fas fa-plus" />{t('lec_enroll_now')}</>
                }
              </button>
            </div>
          </div>
        </div>
      )}

      {/* ── 헤더 배너 ── */}
      <div className="bg-navy-900 pt-14 pb-0">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-5">
          <div className="text-white/40 text-xs tracking-[0.25em] uppercase mb-3">{t('lectures_label')}</div>
          <h1 className="font-gothic text-4xl sm:text-5xl font-bold text-white mb-3">{t('lectures_title')}</h1>
          <p className="text-white/60 text-sm max-w-xl mb-5">
            {t('lectures_desc')}&nbsp;
            <span className="text-amber-400 font-medium">{t('lectures_members_only')}</span>
          </p>

          {/* ── 스크립트 검색창 ── */}
          <div className="relative max-w-xl" style={{marginBottom:'2px'}}>
            <div className="flex items-center bg-white/10 hover:bg-white/15 border border-white/20 hover:border-white/40 rounded-xl transition-all overflow-hidden">
              <i className="fas fa-search text-white/40 text-sm ml-4 mr-2 shrink-0" />
              <input
                type="text"
                value={scriptSearch}
                onChange={e => {
                  setScriptSearch(e.target.value);
                  if (!e.target.value.trim()) setScriptResults(null);
                }}
                onKeyDown={e => e.key === 'Enter' && handleScriptSearch()}
                {...{placeholder: t('lec_script_search_ph')}}
                className="flex-1 bg-transparent text-white placeholder-white/30 text-sm py-3 pr-2 outline-none"
              />
              {scriptSearch && (
                <button onClick={() => { setScriptSearch(''); setScriptResults(null); setSearchKeyword(''); }}
                  className="px-3 text-white/40 hover:text-white/80 transition text-xs">
                  <i className="fas fa-times" />
                </button>
              )}
              <button
                onClick={handleScriptSearch}
                disabled={scriptSearching || !scriptSearch.trim()}
                className="bg-amber-400 hover:bg-amber-300 disabled:bg-white/10 text-navy-900 disabled:text-white/30 font-semibold text-xs px-5 py-3 transition-colors shrink-0"
              >
                {scriptSearching ? <i className="fas fa-spinner fa-spin" /> : '검색'}
              </button>
            </div>

            {/* 검색 결과 드롭다운 */}
            {scriptResults !== null && (
              <div className="absolute top-full left-0 right-0 mt-1 bg-white rounded-xl shadow-2xl border border-gray-100 z-50 overflow-hidden"
                   style={{maxHeight:'320px', overflowY:'auto'}}>
                {scriptResults.length === 0 ? (
                  <div className="px-5 py-6 text-center text-gray-400 text-sm">
                    <i className="fas fa-search mb-2 block text-xl opacity-30" />
                    <span>'{scriptSearch}'에 해당하는 강의 스크립트가 없습니다</span>
                  </div>
                ) : (
                  <>
                    <div className="px-4 py-2.5 bg-gray-50 border-b border-gray-100 flex items-center justify-between">
                      <span className="text-xs font-semibold text-gray-500">
                        <i className="fas fa-file-alt mr-1.5 text-amber-500" />
                        '{scriptSearch}' 검색 결과 — {scriptResults.length}개 강의
                      </span>
                      <button onClick={() => setScriptResults(null)} className="text-gray-400 hover:text-gray-600 text-xs">
                        <i className="fas fa-times" />
                      </button>
                    </div>
                    {scriptResults.map((row, i) => (
                      <button key={i}
                        onClick={() => goToSearchResult(row)}
                        className="w-full text-left px-4 py-3.5 hover:bg-amber-50 transition-colors border-b border-gray-50 last:border-0 flex items-center gap-3"
                      >
                        <div className="shrink-0 w-8 h-8 bg-navy-900/8 rounded-lg flex items-center justify-center text-navy-900 font-bold text-xs">
                          {row.year_segment}차
                        </div>
                        <div className="flex-1 min-w-0">
                          <p className="text-sm font-semibold text-gray-900 truncate">{row.name}</p>
                          <p className="text-xs text-gray-400 mt-0.5">
                            {row.year_segment}차년도 {row.folder}강
                            {row.full_script && (
                              <span className="ml-2 text-amber-600">
                                — {(() => {
                                  const kw = scriptSearch.toLowerCase();
                                  const idx = row.full_script.toLowerCase().indexOf(kw);
                                  if (idx < 0) return '';
                                  const start = Math.max(0, idx - 20);
                                  const end = Math.min(row.full_script.length, idx + kw.length + 30);
                                  return '…' + row.full_script.slice(start, end).replace(
                                    new RegExp(scriptSearch, 'gi'),
                                    m => `"${m}"`
                                  ) + '…';
                                })()}
                              </span>
                            )}
                          </p>
                        </div>
                        <i className="fas fa-arrow-right text-gray-300 text-xs shrink-0" />
                      </button>
                    ))}
                  </>
                )}
              </div>
            )}
          </div>
        </div>

        {/* ── AI 시맨틱 검색창 ── */}
        <div className="bg-navy-950 border-t border-white/5 py-3">
          <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
            <div className="flex items-center gap-3 max-w-2xl">
              <div className="flex items-center gap-2 text-purple-400 shrink-0">
                <i className="fas fa-robot text-xs" />
                <span className="text-xs font-semibold tracking-wide uppercase">AI 검색</span>
              </div>
              <div className="flex-1 flex items-center bg-white/5 border border-white/10 hover:border-purple-400/40 rounded-lg overflow-hidden transition-all">
                <input
                  type="text"
                  value={aiQuery}
                  onChange={e => setAiQuery(e.target.value)}
                  onKeyDown={e => e.key === 'Enter' && handleAiSearch()}
                  placeholder="질문으로 강의 내용 검색 (예: 방언이 문학에 미친 영향은?)"
                  className="flex-1 bg-transparent text-white/80 placeholder-white/25 text-xs py-2.5 px-3 outline-none"
                />
                <button
                  onClick={handleAiSearch}
                  disabled={aiSearching || !aiQuery.trim()}
                  className="bg-purple-600 hover:bg-purple-500 disabled:bg-white/5 text-white disabled:text-white/20 text-xs font-semibold px-4 py-2.5 transition-colors shrink-0 flex items-center gap-1.5"
                >
                  {aiSearching
                    ? <><i className="fas fa-spinner fa-spin text-[10px]" />검색 중</>
                    : <><i className="fas fa-sparkles text-[10px]" />질문하기</>}
                </button>
              </div>
            </div>
          </div>
        </div>

        {/* ── AI 답변 패널 — 화면 우하단 고정 플로팅 ── */}
        {showAiPanel && (
          <div style={{
            position:'fixed', bottom:'24px', right:'24px',
            width:'380px', maxWidth:'calc(100vw - 48px)',
            maxHeight:'70vh', zIndex:9999,
            display:'flex', flexDirection:'column',
            boxShadow:'0 8px 32px rgba(88,28,220,0.18)',
          }} className="bg-white rounded-2xl border border-purple-100 overflow-hidden">
            {/* 패널 헤더 */}
            <div className="flex items-center justify-between px-5 py-3.5 bg-gradient-to-r from-purple-50 to-white border-b border-purple-100 shrink-0">
              <div className="flex items-center gap-2 min-w-0">
                <div className="w-6 h-6 bg-purple-600 rounded-full flex items-center justify-center shrink-0">
                  <i className="fas fa-robot text-white text-[9px]" />
                </div>
                <span className="text-sm font-semibold text-purple-900">AI 강의 도우미</span>
                <span className="text-xs text-purple-400 bg-purple-50 px-2 py-0.5 rounded-full border border-purple-100 truncate max-w-[120px]">
                  "{aiQuery}"
                </span>
              </div>
              <button onClick={() => setShowAiPanel(false)}
                className="w-6 h-6 flex items-center justify-center rounded text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition text-xs shrink-0 ml-1">
                <i className="fas fa-times" />
              </button>
            </div>

            {/* 패널 내용 — 스크롤 가능 */}
            <div style={{overflowY:'auto', flex:1}}>
              {aiSearching ? (
                <div className="px-5 py-8 flex items-center gap-3 text-purple-500">
                  <i className="fas fa-spinner fa-spin" />
                  <span className="text-sm">검색 중...</span>
                </div>
              ) : aiAnswer ? (
                <div>
                  <div className="px-5 py-4">
                    <p className="text-sm text-gray-800 leading-relaxed">{aiAnswer.text}</p>
                  </div>
                  {aiAnswer.sources?.length > 0 && (
                    <div className="border-t border-gray-100 px-5 py-3">
                      <p className="text-[10px] font-semibold text-gray-400 uppercase tracking-wide mb-2">
                        관련 강의 ({aiAnswer.sources.length}개)
                      </p>
                      <div className="space-y-1.5">
                        {aiAnswer.sources.map((src, i) => {
                          const min = Math.floor(src.startTime/60);
                          const sec = Math.floor(src.startTime%60);
                          return (
                            <button key={i}
                              onClick={() => goToAiSource(src)}
                              className="w-full text-left flex items-center gap-3 px-3 py-2.5 rounded-xl hover:bg-purple-50 transition-colors group border border-transparent hover:border-purple-100"
                            >
                              <div className="shrink-0 w-8 h-8 bg-purple-100 group-hover:bg-purple-200 rounded-lg flex items-center justify-center transition-colors">
                                <span className="text-purple-700 font-bold text-[10px]">{src.yearSegment}차</span>
                              </div>
                              <div className="flex-1 min-w-0">
                                <p className="text-xs font-semibold text-gray-800 truncate">{src.courseName}</p>
                                <p className="text-[10px] text-gray-400 mt-0.5 truncate">{src.excerpt}</p>
                              </div>
                              <div className="shrink-0 text-right">
                                <span className="text-[10px] font-mono font-bold text-purple-600 bg-purple-50 px-2 py-1 rounded-lg">
                                  {String(min).padStart(2,'0')}:{String(sec).padStart(2,'0')}
                                </span>
                                <p className="text-[9px] text-gray-300 mt-0.5">{src.similarity}%</p>
                              </div>
                              <i className="fas fa-play text-purple-400 group-hover:text-purple-600 text-[9px] shrink-0 transition-colors" />
                            </button>
                          );
                        })}
                      </div>
                    </div>
                  )}
                </div>
              ) : null}
            </div>
          </div>
        )}
      </div>{/* end bg-navy-950 */}

      {/* ── 차년도 탭 ── */}
      <div className="bg-navy-900 border-b border-white/10">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div className="flex gap-0 overflow-x-auto scrollbar-none">
            {[1,2,3,4,5].map(yr => (
              <button
                key={yr}
                onClick={() => setYearTab(yr)}
                className={`relative shrink-0 px-6 py-3.5 text-sm font-semibold transition-all whitespace-nowrap
                  ${yearTab === yr
                    ? 'text-white border-b-2 border-amber-400'
                    : 'text-white/40 hover:text-white/80 border-b-2 border-transparent'
                  }`}
              >
                {lang === 'en' ? `Year ${yr}` : `${yr}차년도`}
                {yearTab === yr && (
                  <span className="ml-2 text-[10px] font-bold text-amber-400 align-middle">●</span>
                )}
              </button>
            ))}
          </div>
        </div>
      </div>{/* end bg-navy-900 탭 */}

      {/* ── 전공 필터 ── */}
      <div className="bg-white border-b border-gray-100">
        <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-2.5 flex items-center gap-2 flex-wrap">
          <span className="text-xs text-gray-400 font-medium mr-1">전공</span>
          {['전체','국어학','고전문학','현대문학'].map(m => {
            const labelEn = m === '전체' ? 'All' : m === '국어학' ? 'Linguistics' : m === '고전문학' ? 'Classical' : 'Modern';
            return (
            <button key={m}
              onClick={() => { setMajorFilter(m); setSelCourse(null); setSelSession(null); }}
              className={`px-3 py-1 rounded-full text-xs font-semibold transition-all border ${
                majorFilter === m
                  ? m === '국어학'   ? 'bg-blue-600 text-white border-blue-600'
                  : m === '고전문학' ? 'bg-amber-600 text-white border-amber-600'
                  : m === '현대문학' ? 'bg-emerald-600 text-white border-emerald-600'
                  :                   'bg-navy-900 text-white border-navy-900'
                  : 'bg-white text-gray-600 border-gray-200 hover:border-gray-400'
              }`}
            >{lang === 'en' ? labelEn : m}</button>
            );
          })}
          {majorFilter !== '전체' && (
            <span className="text-xs text-gray-400 ml-1">{activeCourses.length}개 강좌</span>
          )}
        </div>
      </div>

      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
        <div className="flex flex-col lg:flex-row gap-6">

          {/* ══ 좌측 사이드바 — 강좌 목록 ══ */}
          <aside style={{ minWidth:'260px', maxWidth:'290px' }} className="w-full lg:w-72 shrink-0">
            <div className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
              <div className="bg-navy-900 px-4 py-3">
                <p className="text-white font-semibold text-sm">{t('lec_course_list')}</p>
                <p className="text-white/50 text-xs mt-0.5">{t('lec_total_courses').replace('{n}', activeCourses.length)}</p>
              </div>
              <ul className="divide-y divide-gray-100">
                {coursesLoading ? (
                  // 로딩 스켈레톤
                  Array(4).fill(0).map((_, i) => (
                    <li key={i} className="p-4 animate-pulse">
                      <div className="flex items-center gap-3">
                        <div className="w-14 h-10 bg-gray-100 rounded" />
                        <div className="flex-1">
                          <div className="h-2.5 bg-gray-100 rounded w-3/4 mb-2" />
                          <div className="h-2 bg-gray-100 rounded w-1/2" />
                        </div>
                      </div>
                    </li>
                  ))
                ) : activeCourses.length === 0 ? (
                  <li className="px-4 py-8 text-center text-gray-400 text-xs">
                    <i className="fas fa-inbox text-2xl mb-2 block opacity-30" />
                    해당 차년도 강좌가 없습니다
                  </li>
                ) : activeCourses.map(course => {
                  const enrolled   = enrollments.has(`${yearTab}_${course.folder}`);
                  const prog       = enrolled ? getCourseProgress(course) : 0;
                  const isEnrolling = enrollLoading === `${yearTab}_${course.folder}`;
                  const isSelected  = selCourse?.folder === course.folder;
                  return (
                    <li key={course.folder}>
                      {/* 강좌 선택 버튼 */}
                      <button
                        onClick={() => pickCourse(course)}
                        className={`w-full text-left flex items-center gap-3 px-4 pt-3 pb-1 transition-colors hover:bg-gray-50 ${
                          isSelected ? 'bg-navy-900/5 border-l-4 border-navy-900' : 'border-l-4 border-transparent'
                        }`}
                      >
                        <div className="shrink-0 w-14 h-10 rounded overflow-hidden bg-gray-100 relative">
                          <img src={course.thumbnail} alt={course.name}
                            className="w-full h-full object-cover"
                            onError={e => { e.target.style.display='none'; }} />
                          {enrolled && (
                            <div className="absolute inset-0 flex items-end justify-end p-0.5">
                              <span className="bg-green-500 rounded-full w-3 h-3 flex items-center justify-center">
                                <i className="fas fa-check text-white" style={{fontSize:'6px'}} />
                              </span>
                            </div>
                          )}
                        </div>
                        <div className="min-w-0 flex-1">

                          <p className="text-gray-800 text-xs font-medium leading-snug line-clamp-2">{lang === 'en' && course.nameEn ? course.nameEn : course.name}</p>
                        {course.major && (
                          <span className={`inline-block mt-1 px-2 py-0.5 rounded-full text-[10px] font-semibold ${
                            course.major === '국어학'   ? 'bg-blue-100 text-blue-700'
                            : course.major === '고전문학' ? 'bg-amber-100 text-amber-700'
                            : 'bg-emerald-100 text-emerald-700'
                          }`}>{
                            lang === 'en'
                              ? (course.major === '국어학' ? 'Korean Linguistics'
                                : course.major === '고전문학' ? 'Classical Literature'
                                : 'Modern Literature')
                              : course.major
                          }</span>
                        )}
                          <div className="flex items-center justify-between mt-0.5">
                            <p className="text-gray-400 text-[11px]">{course.sessions.length}차시</p>
                            {enrolled && prog > 0 && (
                              <span className="text-[10px] font-bold text-navy-900">{prog}%</span>
                            )}
                          </div>
                          {/* 진도율 바 */}
                          {enrolled && (
                            <div className="mt-1 h-1 bg-gray-100 rounded-full overflow-hidden">
                              <div className="h-full bg-navy-900 rounded-full transition-all duration-500"
                                   style={{ width:`${prog}%` }} />
                            </div>
                          )}
                        </div>
                      </button>

                      {/* 수강신청 / 학습하기 / 미리보기 버튼 */}
                      <div className="px-4 pb-3 pt-2">
                        {enrolled ? (
                          /* 수강 완료 → 학습하기 (강조) */
                          <button
                            onClick={() => pickCourse(course)}
                            className="w-full py-1.5 rounded-lg text-xs font-semibold transition-all flex items-center justify-center gap-1.5 bg-navy-900 text-white hover:bg-navy-800"
                          >
                            <i className="fas fa-play" />{t('lec_studying')}
                          </button>
                        ) : (
                          /* 미수강 → 미리보기 + 수강신청 나란히 */
                          <div className="flex gap-1.5">
                            <button
                              onClick={() => setPreviewCourse(course)}
                              className="flex-1 py-1.5 rounded-lg text-xs font-semibold transition-all flex items-center justify-center gap-1 border border-blue-200 bg-blue-50 text-blue-700 hover:bg-blue-100"
                            >
                              <i className="fas fa-eye" />미리보기
                            </button>
                            <button
                              onClick={() => handleEnroll(course)}
                              disabled={isEnrolling}
                              className={`flex-1 py-1.5 rounded-lg text-xs font-semibold transition-all flex items-center justify-center gap-1 ${
                                isEnrolling
                                  ? 'bg-gray-100 text-gray-400 cursor-not-allowed'
                                  : 'border border-gray-200 bg-gray-50 text-gray-700 hover:bg-navy-900 hover:text-white hover:border-navy-900'
                              }`}
                            >
                              {isEnrolling
                                ? <><i className="fas fa-spinner fa-spin" />{t('lec_processing')}</>
                                : <><i className="fas fa-plus" />{t('lec_enroll_btn')}</>}
                            </button>
                          </div>
                        )}
                      </div>
                    </li>
                  );
                })}
              </ul>
            </div>
          </aside>

          {/* ══ 우측 콘텐츠 ══ */}
          <div className="flex-1 min-w-0 flex flex-col gap-6">

            {/* 비디오 플레이어 + 트랜스크립트 */}
            <div className="flex gap-4" style={{alignItems:'flex-start'}}>

              {/* ─ 영상 영역 ─ */}
              <div className="bg-black rounded-xl overflow-hidden shadow-lg lectures-player-area" style={{flex: showTranscript && transcript.length > 0 ? '1 1 0' : '1 1 auto', minWidth:0}}>
              {canWatch && currentClip ? (
                <>
                  <video
                    key={currentClip.url}
                    ref={videoRef}
                    controls autoPlay={playing} playsInline preload="auto"
                    controlsList="nodownload"
                    onContextMenu={e => e.preventDefault()}
                    onEnded={onClipEnded}
                    onError={e => console.error(`[Video] code=${e.target?.error?.code ?? -1}`, currentClip.url)}
                    onLoadedMetadata={() => {
                      const jt = sessionStorage.getItem('_jump_time');
                      if (jt && videoRef.current) {
                        sessionStorage.removeItem('_jump_time');
                        videoRef.current.currentTime = parseFloat(jt);
                        videoRef.current.play().catch(()=>{});
                      }
                    }}
                    style={{ width:'100%', maxHeight:'480px', display:'block', background:'#000' }}
                  >
                    <source src={currentClip.url} type="video/mp4" />
                    {vttUrls.ko && <track kind="subtitles" src={vttUrls.ko} srclang="ko" label="한국어" default={activeSub==='ko'} />}
                    {vttUrls.en && <track kind="subtitles" src={vttUrls.en} srclang="en" label="English" default={activeSub==='en'} />}
                    {vttUrls.zh && <track kind="subtitles" src={vttUrls.zh} srclang="zh" label="中文" default={activeSub==='zh'} />}
                  </video>

                  {/* 자막 선택 바 */}
                  <div className="flex items-center gap-2 px-4 py-2.5 bg-gray-950 border-t border-white/5">
                    <i className="fas fa-closed-captioning text-white/40 text-xs mr-1" />
                    <span className="text-white/40 text-xs mr-2">자막</span>
                    {subLoading && <span className="text-white/30 text-xs animate-pulse mr-2">로딩 중…</span>}
                    {[{key:'ko',label:'한국어'},{key:'en',label:'English'},{key:'zh',label:'中文'},{key:'off',label: lang === 'en' ? 'Off' : lang === 'zh' ? '关闭' : '끄기'}].map(({key,label}) => (
                      <button key={key} onClick={() => setActiveSub(key)}
                        disabled={key !== 'off' && !vttUrls[key] && !subLoading}
                        className={`px-3 py-1 rounded-full text-xs transition-colors ${
                          activeSub === key ? 'bg-white text-gray-900 font-semibold'
                          : (key !== 'off' && !vttUrls[key]) ? 'text-white/20 cursor-not-allowed'
                          : 'text-white/50 hover:text-white hover:bg-white/10'
                        }`}>{label}</button>
                    ))}
                    {/* 스크립트 토글 */}
                    {transcript.length > 0 && (
                      <button
                        onClick={() => setShowTranscript(s => !s)}
                        className={`ml-auto px-3 py-1 rounded-full text-xs transition-colors flex items-center gap-1 ${
                          showTranscript ? 'bg-amber-400/20 text-amber-300' : 'text-white/50 hover:text-white hover:bg-white/10'
                        }`}
                      >
                        <i className="fas fa-align-left text-[10px]" />스크립트
                      </button>
                    )}
                  </div>
                </>
              ) : (
                /* ── 재생 불가 상태 안내 ── */
                <div className="flex flex-col items-center justify-center" style={{ height:'360px' }}>
                  <i className={`fas ${!isLoggedIn ? 'fa-lock' : !isEnrolled ? 'fa-graduation-cap' : 'fa-play-circle'} text-5xl mb-4 text-white/20`} />
                  <p className="font-semibold text-white/60 mb-1 text-sm">
                    {!isLoggedIn   ? t('lec_login_required')
                     : !isEnrolled ? t('lec_enroll_required')
                     :               t('lec_no_session')}
                  </p>
                  {!isLoggedIn && (
                    <button onClick={() => setShowLoginModal('login')}
                      className="mt-4 px-5 py-2 bg-white/10 hover:bg-white/20 text-white text-sm rounded-full transition">
                      { t('lec_login_btn') }
                    </button>
                  )}
                  {isLoggedIn && !isEnrolled && (
                    <div className="flex flex-col items-center gap-2 mt-4">
                      <button onClick={() => setPreviewCourse(selCourse)}
                        className="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white font-semibold text-sm rounded-full transition flex items-center gap-2">
                        <i className="fas fa-eye" />{t('lec_preview_play')}
                      </button>
                      <button onClick={() => handleEnroll(selCourse)}
                        disabled={enrollLoading === courseKey}
                        className="px-6 py-2 bg-white text-navy-900 font-semibold text-sm rounded-full hover:bg-gray-100 transition disabled:opacity-60 flex items-center gap-2">
                        {enrollLoading === courseKey
                          ? <><i className="fas fa-spinner fa-spin" />{t('lec_processing')}</>
                          : <><i className="fas fa-plus" />{t('lec_enroll_now')}</>}
                      </button>
                    </div>
                  )}
                </div>
              )}
              </div>{/* end 영상 영역 */}

              {/* ─ 트랜스크립트 패널 ─ */}
              {canWatch && showTranscript && transcript.length > 0 && (
                <div
                  style={{
                    width: '300px', minWidth: '260px', maxWidth: '320px',
                    flexShrink: 0,
                  }}
                  className="bg-white rounded-xl shadow-lg border border-gray-100 flex flex-col overflow-hidden"
                >
                  {/* 패널 헤더 */}
                  <div className="flex items-center justify-between px-4 py-3 bg-gray-50 border-b border-gray-100">
                    <div className="flex items-center gap-2 min-w-0 flex-1">
                      <i className="fas fa-align-left text-navy-900/60 text-xs shrink-0" />
                      <span className="text-xs font-semibold text-gray-700 shrink-0">{t('lec_script_panel')}</span>
                      <span className="text-[10px] text-gray-400 shrink-0">{transcript.length}문장</span>
                      {searchKeyword && (
                        <span className="text-[10px] bg-amber-100 text-amber-700 px-1.5 py-0.5 rounded font-medium truncate max-w-[80px]">
                          '{searchKeyword}'
                        </span>
                      )}
                    </div>
                    <div className="flex items-center gap-1 shrink-0">
                      {searchKeyword && (
                        <button onClick={() => setSearchKeyword('')}
                          className="text-[10px] text-amber-600 hover:text-amber-800 px-1.5 py-0.5 rounded bg-amber-50 hover:bg-amber-100 transition">
                          해제
                        </button>
                      )}
                      <button
                        onClick={() => setShowTranscript(false)}
                        className="w-6 h-6 flex items-center justify-center rounded text-gray-400 hover:text-gray-600 hover:bg-gray-200 transition text-xs"
                      >
                        <i className="fas fa-times" />
                      </button>
                    </div>
                  </div>

                  {/* 스크립트 목록 */}
                  <div
                    id="transcript-container"
                    ref={transcriptRef}
                    style={{ height: '460px', overflowY: 'auto', padding: '8px 4px' }}
                  >
                    {transcript.map((item, idx) => {
                      const isActive   = idx === activeScriptIdx;
                      const kwLower    = searchKeyword.toLowerCase();
                      const textLower  = item.text.toLowerCase();
                      const isMatched  = searchKeyword && textLower.includes(kwLower);

                      // 검색어 하이라이팅 렌더 함수
                      const renderText = () => {
                        if (!searchKeyword) return item.text;
                        const parts = item.text.split(new RegExp(`(${searchKeyword})`, 'gi'));
                        return parts.map((part, pi) =>
                          part.toLowerCase() === kwLower
                            ? <mark key={pi} className="bg-yellow-200 text-yellow-900 rounded px-0.5 font-semibold not-italic">{part}</mark>
                            : part
                        );
                      };

                      return (
                        <button
                          key={idx}
                          data-idx={idx}
                          data-start={item.start}
                          onClick={() => {
                            if (videoRef.current) {
                              videoRef.current.currentTime = item.start;
                              videoRef.current.play().catch(() => {});
                            }
                          }}
                          className={`w-full text-left px-3 py-2 rounded-lg text-xs leading-relaxed transition-all mb-0.5 ${
                            isActive
                              ? 'bg-amber-100 text-amber-900 font-medium border-l-2 border-amber-400 active-script'
                              : isMatched
                                ? 'bg-yellow-50 border-l-2 border-yellow-300 text-gray-800 hover:bg-yellow-100'
                                : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'
                          }`}
                        >
                          <span className="text-[10px] text-gray-400 font-mono mr-1.5 select-none">
                            {String(Math.floor(item.start/60)).padStart(2,'0')}:{String(Math.floor(item.start%60)).padStart(2,'0')}
                          </span>
                          {renderText()}
                        </button>
                      );
                    })}
                  </div>
                </div>
              )}

            </div>{/* end 비디오+트랜스크립트 flex */}

            {/* 강좌 정보 + 차시/클립 선택 */}
            {selCourse && (
              <div className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">

                {/* 강좌 헤더 */}
                <div className="flex items-center gap-4 p-5 border-b border-gray-100">
                  <div className="w-16 h-12 rounded-lg overflow-hidden bg-gray-100 shrink-0">
                    <img src={selCourse.thumbnail} alt={lang === 'en' && selCourse.nameEn ? selCourse.nameEn : selCourse.name}
                      className="w-full h-full object-cover"
                      onError={e => { e.target.style.display='none'; }} />
                  </div>
                  <div className="flex-1 min-w-0">

                    <h2 className="font-gothic text-gray-900 font-bold text-base leading-snug">{lang === 'en' && selCourse.nameEn ? selCourse.nameEn : selCourse.name}</h2>
                    {selSession && (
                      <p className="text-gray-500 text-xs mt-0.5">
                        {lang === 'en' ? selSession.session.replace(/([0-9]+)주차/, 'Week $1') : selSession.session}
                        {(selSession.unit || selSession.unit_en) && (
                          <span className="ml-1 text-gray-400">— {lang === 'en' && selSession.unit_en ? selSession.unit_en : selSession.unit}</span>
                        )}
                        {canWatch && currentClip && (
                          <span className="ml-2 text-navy-900 font-semibold">
                            {lang === 'en' ? `Clip ${clipIdx + 1}` : `${clipIdx + 1}차시`}
                            {(currentClip.topic || currentClip.topic_en) && <span className="ml-1 font-normal text-gray-500">— {lang === 'en' && currentClip.topic_en ? currentClip.topic_en : currentClip.topic}</span>}
                          </span>
                        )}
                      </p>
                    )}
                  </div>
                  {/* 수강신청 / 수강 중 뱃지 */}
                  <button
                    onClick={() => !isEnrolled && handleEnroll(selCourse)}
                    disabled={isEnrolled || enrollLoading === courseKey}
                    className={`shrink-0 px-4 py-2 rounded-lg text-xs font-semibold flex items-center gap-1.5 transition-all ${
                      isEnrolled
                        ? 'bg-green-50 text-green-700 border border-green-200 cursor-default'
                        : enrollLoading === courseKey
                          ? 'bg-gray-100 text-gray-400 cursor-not-allowed'
                          : 'bg-navy-900 text-white hover:bg-navy-800'
                    }`}
                  >
                    {enrollLoading === String(selCourse.folder) ? (
                      <><i className="fas fa-spinner fa-spin" />{t('lec_processing')}</>
                    ) : isEnrolled ? (
                      <><i className="fas fa-check" />{t('lec_enrolled')}</>
                    ) : (
                      <><i className="fas fa-plus" />{t('lec_enroll_btn')}</>
                    )}
                  </button>
                </div>

                {/* 차시 목록 */}
                <div className="p-4">
                  <p className="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3">{t('lec_session_list')}</p>
                  {/* ── 아코디언 단원 목록 ── */}
                  <div className="flex flex-col gap-1.5">
                    {selCourse.sessions.map(session => {
                      const isOpen = selSession?.group === session.group;
                      return (
                        <div key={session.group} className="rounded-lg border overflow-hidden">
                          {/* 단원 헤더 — 클릭 시 아코디언 토글 */}
                          <button
                            onClick={() => pickSession(isOpen ? null : session)}
                            className={`w-full text-left px-3 py-2.5 text-xs transition-colors flex items-start justify-between gap-2 ${
                              isOpen
                                ? 'bg-navy-900 text-white'
                                : 'bg-gray-50 text-gray-700 hover:bg-navy-50'
                            }`}
                          >
                            <div className="flex items-start gap-2 min-w-0">
                              <span className={`font-bold shrink-0 ${isOpen ? 'text-white' : 'text-navy-900'}`}>
                                {lang === 'en' ? session.session.replace(/([0-9]+)주차/, 'Week $1') : session.session}
                              </span>
                              {(session.unit || session.unit_en) && (
                                <span className={`leading-tight truncate ${isOpen ? 'text-white/80' : 'text-gray-500'}`}>
                                  {lang === 'en' && session.unit_en ? session.unit_en : session.unit}
                                </span>
                              )}
                            </div>
                            <div className="flex items-center gap-1.5 shrink-0">
                              <span className={`text-[10px] ${isOpen ? 'text-white/60' : 'text-gray-400'}`}>
                                {session.clips.length}{lang === 'en' ? ' clips' : '차시'}
                                {!isLoggedIn && <i className="fas fa-lock ml-1" />}
                                {isLoggedIn && !isEnrolled && <i className="fas fa-graduation-cap ml-1" />}
                              </span>
                              <i className={`fas fa-chevron-${isOpen ? 'up' : 'down'} text-[9px] ${isOpen ? 'text-white/60' : 'text-gray-400'}`} />
                            </div>
                          </button>
                          {/* 차시 목록 — 아코디언 열림 시 표시 */}
                          {isOpen && canWatch && (
                            <div className="bg-white border-t border-gray-100 p-2 flex flex-col gap-1">
                              {session.clips.map((clip, ci) => {
                                const hasProg = (progressMapRef.current[`${yearTab}_${selCourse.folder}_${clip.file}`] || 0) > 0;
                                return (
                                  <button key={clip.file} onClick={() => pickClip(ci)}
                                    className={`relative text-left w-full px-2.5 py-1.5 rounded text-[11px] transition-colors ${
                                      ci === clipIdx
                                        ? 'bg-navy-900 text-white'
                                        : 'bg-gray-50 text-gray-600 hover:bg-navy-900/10 hover:text-navy-900'
                                    }`}
                                  >
                                    <span className="flex items-center gap-1">
                                      {ci === clipIdx && <i className="fas fa-play text-[8px]" />}
                                      <span className="font-mono font-semibold">{lang === 'en' ? `Clip ${ci + 1}` : `${ci + 1}차시`}</span>
                                      {hasProg && ci !== clipIdx && <i className="fas fa-check-circle text-[8px] text-green-400" title="시청 기록 있음" />}
                                    </span>
                                    {(clip.topic || clip.topic_en) && (
                                      <span className={`block text-[10px] font-sans font-normal leading-snug mt-0.5 ${ci === clipIdx ? 'text-white/75' : 'text-gray-500'}`}>
                                        {lang === 'en' && clip.topic_en ? clip.topic_en : clip.topic}
                                      </span>
                                    )}
                                  </button>
                                );
                              })}
                            </div>
                          )}
                          {/* 비수강 상태 잠금 표시 */}
                          {isOpen && !canWatch && (
                            <div className="bg-gray-50 border-t border-gray-100 px-3 py-2 text-[11px] text-gray-400 flex items-center gap-1">
                              <i className="fas fa-lock text-[10px]" />
                              {isLoggedIn ? '수강신청 후 이용 가능합니다' : '로그인 후 수강신청이 필요합니다'}
                            </div>
                          )}
                        </div>
                      );
                    })}
                  </div>
                </div>
              </div>
            )}

          </div>{/* end 우측 */}
        </div>{/* end flex */}
      </div>{/* end max-w */}

      <Footer setPage={setPage} />
    </div>
  );
}

