PageSourceSearch

https://emongenglish.net/assets/VocabularyPage-ClOElDSG.js

js emongenglish.net collected 2026-10-05 18:05:14 UTC 157,355 bytes, 1,641 lines download raw bytes

1import { r as a, j as e, i as Xt, u as Dt, f as dt } from "./vendor-query-CnLZf_EB.js";
2import { u as Pn } from "./useMobileUpdateSave-anqCDGbY.js";
3import { r as fr, f as On } from "./vendor-react-CjjLCydY.js";
4import { u as Bn } from "./usePortalDropdown-C-mf-EoE.js";
5import { Q as Ke, $ as _t, bJ as Je, f_ as Oe, cp as on, M as Me, c9 as sr, aN as Vn, br as $n, X as Sr, ay as zn, bP as ln, d as Ln, d0 as xr, ex as gr, aH as Fn, cm as hr, b3 as Hn, aL as Ht, cw as de, bd as Ze, aM as _r, aF as $t, cg as pr, az as br, H as jt, bf as yr, f as yt, G as cn, P as dn, j as or, t as We, e as ir, aO as un, ax as Kn, l as qn, Z as Cr, bL as Un, bN as Wn, c7 as Yn, aP as mn } from "./App-BzxudLOB.js";
6import { u as fn } from "./useShiftSelect-CUvKmjGR.js";
7import { a as xn, b as gn, H as hn, i as Qn, p as Xn, u as Gn, c as Zn } from "./HandwritingSaveBanner-dObu8Eb3.js";
8import { u as pn } from "./useDisableBodyTextSelection-BmhABaHn.js";
9import { O as vr } from "./OfflineUnavailableNotice-CodyJ7Vu.js";
10import { u as bn } from "./useHandwritingPersistenceFeedback-DN76OoUv.js";
11import { S as Pt } from "./shuffle-o6vsobsx.js";
12import { C as Jn } from "./circle-check-eyHu01cN.js";
13import { a as ea, A as Er } from "./arrow-up-Ds4NPYNn.js";
14import { V as Ot } from "./volume-x-x6WChpUm.js";
15import { V as Nt } from "./volume-2-HNomr_3p.js";
16import { A as wr } from "./arrow-left-D-FUCoHx.js";
17import { R as ta } from "./rotate-ccw-DDCLHkiw.js";
18import { B as ra } from "./brain-B7RZAYl3.js";
19import { E as Kt } from "./eye-BiqUxfUl.js";
20import { E as qt } from "./eye-off-BaehqoVT.js";
21import { C as yn, a as Ut, M as Wt } from "./minimize-2-Anr46dAf.js";
22import { R as Ir } from "./refresh-cw-BT63URYv.js";
23import { T as Mr } from "./trash-2-BsEMyM_9.js";
24import { P as na } from "./plus-kvLLfmk2.js";
25import { S as aa } from "./star-CzdypP67.js";
26import { C as sa } from "./chevron-down-CCtAlXwd.js";
27import "./floatingPosition-CEeNxCs-.js";
28import "./index-W-g0kpIR.js";
29import "./vendor-socket-CzTGKfeH.js";
30import "./mobileOta-CYuBwxYO.js";
31import "./grip-vertical-J9BXZkrt.js";
32import "./pen-C3H1vK2L.js";
33import "./highlighter-BdBX-8K9.js";
34import "./undo-2-ovcv97Js.js";
35import "./wifi-off-DcEnYTf9.js";
36const oa = `
37`, lr = "\\t\\n\\v\\f\\r \\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff", ia = new RegExp(`^[${lr}]+|[${lr}]+$`, "g"), la = new RegExp(`[${lr}]+`, "g");
38function De(n) {
39  return n.trim().toLowerCase();
40}
41function vn(n) {
42  return n == null ? "" : n.normalize("NFC").replace(ia, "").replace(la, " ").toLowerCase();
43}
44function cr(n) {
45  if (n == null) return [];
46  const s = [];
47  for (const l of n.split(oa)) {
48    const d = vn(l);
49    d !== "" && s.push(d);
50  }
51  return s;
52}
53function ca(n, s) {
54  const l = vn(s);
55  return l === "" ? false : cr(n).includes(l);
56}
57function Yt(n, s) {
58  const l = De(n.word), d = s.filter((u) => u.is_active !== false && De(u.word) === l);
59  if (d.length === 0) return { verdict: "new", matchedRow: null, wordMatches: [] };
60  const f = new Set(cr(n.meaning));
61  if (f.size > 0) {
62    for (const u of d) if (cr(u.meaning).some((i) => f.has(i))) return { verdict: "duplicate", matchedRow: u, wordMatches: d };
63  }
64  return { verdict: "conflict", matchedRow: null, wordMatches: d };
65}
66const Rr = "\uC608\uBB38\uC774 \uAC19\uC544 \uBCC4\uB3C4 \uD56D\uBAA9\uC73C\uB85C \uC800\uC7A5\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uAE30\uC874 \uB2E8\uC5B4\uC5D0 \uD1B5\uD569\uD574 \uC8FC\uC138\uC694.";
67function Ar({ value: n }) {
68  return e.jsx("p", { className: "text-sm text-gray-800 whitespace-pre-line break-words", children: n });
69}
70function wn({ prompt: n, remainingCount: s = 0, onMerge: l, onSeparate: d, onDismiss: f, onDiscard: u }) {
71  var h;
72  return a.useEffect(() => {
73    const i = (x) => {
74      x.key === "Escape" && f();
75    };
76    return window.addEventListener("keydown", i), () => window.removeEventListener("keydown", i);
77  }, [f]), e.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 px-4", onClick: f, children: e.jsxs("div", { role: "dialog", "aria-modal": "true", "aria-labelledby": "duplicate-word-modal-title", className: "bg-white rounded-2xl shadow-xl w-full max-w-md max-h-[85vh] overflow-y-auto", onClick: (i) => i.stopPropagation(), children: [e.jsxs("div", { className: "flex items-start gap-3 px-5 pt-5 pb-3", children: [e.jsx("span", { className: "w-9 h-9 flex-none rounded-full bg-amber-50 flex items-center justify-center", children: e.jsx(Ke, { className: "w-[18px] h-[18px] text-amber-500" }) }), e.jsxs("div", { className: "min-w-0 flex-1", children: [e.jsx("h3", { id: "duplicate-word-modal-title", className: "font-semibold text-gray-900", children: "\uC774\uBBF8 \uC800\uC7A5\uB41C \uB2E8\uC5B4\uC785\uB2C8\uB2E4" }), e.jsxs("p", { className: "mt-0.5 text-sm text-gray-500 break-words", children: [e.jsx("span", { className: "font-semibold text-gray-700", children: n.word }), "\u2005", "\u2014 \uB73B\uC774 \uB2EC\uB77C \uC5B4\uB5BB\uAC8C \uC800\uC7A5\uD560\uC9C0 \uC120\uD0DD\uD574 \uC8FC\uC138\uC694."] })] }), e.jsx("button", { type: "button", "aria-label": "\uB2EB\uAE30", onClick: f, className: "p-1 -mr-1 rounded-lg hover:bg-gray-100 transition-colors flex-none", children: e.jsx(_t, { className: "w-4 h-4 text-gray-400" }) })] }), e.jsxs("div", { className: "px-5 pb-4 space-y-3", children: [e.jsxs("section", { children: [e.jsx("h4", { className: "text-xs font-semibold text-gray-400 mb-1.5", children: "\uB098\uC758 \uB2E8\uC5B4\uC7A5\uC5D0 \uC800\uC7A5\uB41C \uB73B" }), e.jsx("div", { className: "rounded-xl border border-gray-200 bg-gray-50/60 divide-y divide-gray-100", children: n.existingMeanings.map((i, x) => e.jsx("div", { className: "px-3 py-2", children: e.jsx(Ar, { value: i }) }, x)) })] }), e.jsxs("section", { children: [e.jsx("h4", { className: "text-xs font-semibold text-gray-400 mb-1.5", children: "\uCD94\uAC00\uD558\uB824\uB294 \uB73B" }), e.jsx("div", { className: "rounded-xl border border-primary/30 bg-primary/5 px-3 py-2", children: e.jsx(Ar, { value: (h = n.incomingMeaning) != null ? h : "-" }) })] }), !n.canAddSeparately && e.jsx("p", { className: "text-xs text-amber-600 bg-amber-50 rounded-lg px-3 py-2", children: Rr })] }), e.jsxs("div", { className: "px-5 pb-5 flex flex-col gap-2", children: [e.jsx("button", { type: "button", onClick: l, className: "w-full px-4 py-2.5 rounded-xl bg-primary text-white text-sm font-semibold hover:bg-primary/90 transition-colors", children: "\uAE30\uC874\uC5D0 \uD1B5\uD569" }), e.jsx("button", { type: "button", onClick: d, disabled: !n.canAddSeparately, title: n.canAddSeparately ? void 0 : Rr, className: "w-full px-4 py-2.5 rounded-xl border border-gray-200 text-gray-700 text-sm font-semibold hover:bg-gray-50 transition-colors disabled:opacity-40 disabled:hover:bg-white", children: "\uBCC4\uB3C4\uB85C \uCD94\uAC00" }), e.jsxs("div", { className: "flex items-center justify-between pt-0.5", children: [s > 0 ? e.jsxs("span", { className: "text-xs text-gray-400", children: [s, "\uAC1C \uB354 \uC120\uD0DD\uD574\uC57C \uD569\uB2C8\uB2E4"] }) : e.jsx("span", {}), u && e.jsx("button", { type: "button", onClick: u, className: "text-xs text-gray-400 hover:text-red-500 transition-colors", children: "\uC774 \uCD94\uAC00 \uCDE8\uC18C" })] })] })] }) });
78}
79function Ft() {
80  try {
81    return typeof window < "u" && typeof window.speechSynthesis < "u" && typeof window.SpeechSynthesisUtterance < "u";
82  } catch {
83    return false;
84  }
85}
86function Tr() {
87  return typeof window < "u" && typeof window.Audio < "u";
88}
89const jn = ["Google US English", "Google UK English", "Samantha", "Daniel", "Karen"], Nn = ["Google \uD55C\uAD6D\uC758", "Yuna", "Sora"];
90function dr(n, s) {
91  for (const l of s) {
92    const d = n.find((f) => f.name.includes(l));
93    if (d) return d;
94  }
95  return n[0];
96}
97function da(n, s) {
98  var l;
99  if (Je() || s != null && s.localService) return s;
100  const d = n.split("-")[0], f = window.speechSynthesis.getVoices().filter((h) => h.localService && h.lang.startsWith(d));
101  return (l = dr(f, d === "ko" ? Nn : jn)) != null ? l : s;
102}
103function ua(n, s, l, d) {
104  return new Promise((f) => {
105    if (!Ft()) {
106      f();
107      return;
108    }
109    try {
110      const u = new SpeechSynthesisUtterance(n);
111      u.lang = s, u.rate = l;
112      const h = da(s, d);
113      h && (u.voice = h), u.onend = () => f(), u.onerror = () => f(), window.speechSynthesis.speak(u);
114    } catch {
115      f();
116    }
117  });
118}
119const Dr = "vocabTTS_enVoice", Pr = "vocabTTS_koVoice";
120function jr(n) {
121  const [s, l] = a.useState(false), [d, f] = a.useState(-1), u = a.useRef(false), h = a.useRef(0), i = a.useRef(null), x = a.useRef(null), m = a.useRef(null), b = a.useRef(null), g = a.useRef(n);
122  g.current = n;
123  const v = n.some((R) => R.source === "book" && R.id != null), j = Ft() || v && Tr(), [C, M] = a.useState([]), [o, p] = a.useState([]), [y, S] = a.useState(""), [_, E] = a.useState("");
124  a.useEffect(() => {
125    if (!j) return;
126    const R = () => {
127      var D, K, ee, he;
128      try {
129        const te = window.speechSynthesis.getVoices();
130        if (te.length === 0) return;
131        const z = te.filter((L) => L.lang.startsWith("en")), H = te.filter((L) => L.lang.startsWith("ko"));
132        M(z.map((L) => ({ name: L.name, voice: L }))), p(H.map((L) => ({ name: L.name, voice: L })));
133        const U = localStorage.getItem(Dr), oe = localStorage.getItem(Pr), we = U && z.find((L) => L.name === U), le = oe && H.find((L) => L.name === oe);
134        S(we ? we.name : (K = (D = dr(z, jn)) == null ? void 0 : D.name) != null ? K : ""), E(le ? le.name : (he = (ee = dr(H, Nn)) == null ? void 0 : ee.name) != null ? he : "");
135      } catch {
136      }
137    };
138    R();
139    try {
140      window.speechSynthesis.addEventListener("voiceschanged", R);
141    } catch {
142      return;
143    }
144    return () => {
145      try {
146        window.speechSynthesis.removeEventListener("voiceschanged", R);
147      } catch {
148      }
149    };
150  }, [j]);
151  const T = a.useCallback((R) => {
152    S(R), localStorage.setItem(Dr, R);
153  }, []), P = a.useCallback((R) => {
154    E(R), localStorage.setItem(Pr, R);
155  }, []), V = a.useRef(void 0), xe = a.useRef(void 0);
156  a.useEffect(() => {
157    var R;
158    V.current = (R = C.find((D) => D.name === y)) == null ? void 0 : R.voice;
159  }, [C, y]), a.useEffect(() => {
160    var R;
161    xe.current = (R = o.find((D) => D.name === _)) == null ? void 0 : R.voice;
162  }, [o, _]);
163  const O = a.useCallback((R) => new Promise((D) => {
164    i.current = setTimeout(() => {
165      i.current = null, D(u.current);
166    }, R);
167  }), []), Y = a.useCallback(() => {
168    var R;
169    const D = x.current;
170    D && (D.onended = null, D.onerror = null, D.pause(), D.removeAttribute("src"), D.load(), x.current = null), m.current && (URL.revokeObjectURL(m.current), m.current = null), (R = b.current) == null || R.call(b, false), b.current = null;
171  }, []), A = a.useCallback(() => {
172    if (h.current += 1, u.current = false, Y(), Ft()) try {
173      window.speechSynthesis.cancel();
174    } catch {
175    }
176    i.current && (clearTimeout(i.current), i.current = null), l(false), f(-1);
177  }, [Y]), ge = a.useCallback((R) => new Promise((D) => {
178    Y();
179    const K = URL.createObjectURL(R), ee = new Audio(K);
180    x.current = ee, m.current = K, b.current = D;
181    const he = (te) => {
182      x.current === ee && (x.current = null), m.current === K && (URL.revokeObjectURL(K), m.current = null), b.current === D && (b.current = null), D(te);
183    };
184    ee.onended = () => he(true), ee.onerror = () => he(false), ee.play().catch(() => he(false));
185  }), [Y]), G = a.useCallback(async (R, D, K) => {
186    const ee = R[D], he = D === "meaning" ? "ko-KR" : "en-US", te = D === "meaning" ? 1 : 0.9, z = D === "meaning" ? xe.current : V.current;
187    if (ee && R.source === "book" && R.id != null && Je() && Tr()) try {
188      const H = await Oe.getBookEntryTtsAudio(R.id, D);
189      if (!u.current || h.current !== K || H.data.size > 0 && await ge(H.data)) return;
190    } catch {
191    }
192    u.current && h.current === K && ee && await ua(ee, he, te, z);
193  }, [ge]), ue = a.useCallback(async () => {
194    if (g.current.length === 0 || !j) return;
195    A();
196    const R = h.current;
197    u.current = true, l(true);
198    for (let D = 0; D < g.current.length && !(!u.current || h.current !== R); D++) {
199      const K = g.current[D];
200      if (K.word && (f(D), await G(K, "word", R), !u.current || h.current !== R || !await O(500) || K.meaning && (await G(K, "meaning", R), !u.current || h.current !== R) || D < g.current.length - 1 && !await O(800))) break;
201    }
202    h.current === R && (u.current = false, l(false), f(-1));
203  }, [O, j, G, A]), F = a.useCallback(() => {
204    j && (u.current ? A() : ue());
205  }, [j, ue, A]), Ne = a.useCallback((R) => {
206    const D = g.current[R];
207    if (!(D != null && D.word) || !j) return;
208    if (u.current && d === R) {
209      A();
210      return;
211    }
212    A();
213    const K = h.current;
214    u.current = true, l(true), f(R), G(D, "word", K).finally(() => {
215      !u.current || h.current !== K || (u.current = false, l(false), f(-1));
216    });
217  }, [d, j, G, A]);
218  return a.useEffect(() => () => {
219    if (u.current = false, Y(), Ft()) try {
220      window.speechSynthesis.cancel();
221    } catch {
222    }
223    i.current && clearTimeout(i.current);
224  }, [Y]), a.useEffect(() => {
225    s && A();
226  }, [n]), { isSupported: j, isPlaying: s, currentIndex: d, toggleTTS: F, stopTTS: A, playItem: Ne, enVoices: C, koVoices: o, selectedEnVoice: y, selectedKoVoice: _, setSelectedEnVoice: T, setSelectedKoVoice: P };
227}
228function kt(n) {
229  var s;
230  return (s = n.memorization_status) != null ? s : "default";
231}
232function Or(n, s, l) {
233  n.setQueryData(Me, (d) => {
234    if (!d) return d;
235    let f = false;
236    const u = d.items.map((h) => {
237      const i = s.get(h.id);
238      return !i || l && kt(h) !== l || kt(h) === i ? h : (f = true, { ...h, memorization_status: i });
239    });
240    return f ? { ...d, items: u } : d;
241  });
242}
243function Br(n, s, l, d) {
244  n.setQueryData(["vocabulary", "book-entries", s], (f) => {
245    var u;
246    if (!((u = f == null ? void 0 : f.data) != null && u.entries)) return f;
247    let h = false;
248    const i = f.data.entries.map((x) => {
249      const m = l.get(x.id);
250      return !m || d && kt(x) !== d || kt(x) === m ? x : (h = true, { ...x, memorization_status: m });
251    });
252    return h ? { ...f, data: { ...f.data, entries: i } } : f;
253  });
254}
255class Vr extends Error {
256  persistedEntryIds;
257  constructor(s, l) {
258    super(s instanceof Error && s.message ? s.message : "\uB2E8\uC5B4\uB97C \uC774\uB3D9\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4."), this.name = "MemorizationStatusBatchError", this.persistedEntryIds = l;
259  }
260}
261function kn(n) {
262  const s = Xt(), l = a.useRef(/* @__PURE__ */ new Map()), d = a.useRef(/* @__PURE__ */ new Map()), f = a.useRef(() => {
263  }), u = a.useRef(async () => {
264  }), h = a.useRef(0), i = a.useRef(/* @__PURE__ */ new Map());
265  a.useEffect(() => {
266    let g = false, v = 0, j = false;
267    l.current = /* @__PURE__ */ new Map(), d.current = /* @__PURE__ */ new Map();
268    const C = () => {
269      if (g || j) return;
270      const y = new Map(l.current);
271      d.current.forEach(({ status: S }, _) => {
272        y.set(_, S);
273      }), y.size !== 0 && (j = true, n.targetType === "personal" ? Or(s, y) : n.bookId != null && Br(s, n.bookId, y), j = false);
274    }, M = async () => {
275      const y = ++v;
276      try {
277        const S = await ln(n.academyId, n.userId);
278        if (g || y !== v) return;
279        const _ = /* @__PURE__ */ new Map();
280        for (const E of S) {
281          if (E.kind !== "vocab_memorization_status") continue;
282          const T = E.payload;
283          T.targetType === n.targetType && _.set(T.entryId, T.status);
284        }
285        l.current = _, C();
286      } catch {
287      }
288    };
289    f.current = C, u.current = M;
290    const o = on(() => {
291      M();
292    }), p = s.getQueryCache().subscribe((y) => {
293      if (j || l.current.size === 0 && d.current.size === 0) return;
294      const S = y.query.queryKey;
295      (n.targetType === "personal" ? S.length === Me.length && S.every((E, T) => E === Me[T]) : S[0] === "vocabulary" && S[1] === "book-entries" && S[2] === n.bookId) && C();
296    });
297    return M(), () => {
298      g = true, f.current = () => {
299      }, u.current = async () => {
300      }, o(), p();
301    };
302  }, [n.academyId, n.bookId, n.targetType, n.userId, s]);
303  const x = (g) => {
304    var v, j, C;
305    const M = new Set(g), o = /* @__PURE__ */ new Map();
306    if (n.targetType === "personal") {
307      const y = s.getQueryData(Me);
308      for (const S of (v = y == null ? void 0 : y.items) != null ? v : []) M.has(S.id) && o.set(S.id, kt(S));
309      return o;
310    }
311    const p = s.getQueryData(["vocabulary", "book-entries", n.bookId]);
312    for (const y of (C = (j = p == null ? void 0 : p.data) == null ? void 0 : j.entries) != null ? C : []) M.has(y.id) && o.set(y.id, kt(y));
313    return o;
314  }, m = (g, v) => {
315    if (n.targetType === "personal") {
316      Or(s, g, v);
317      return;
318    }
319    n.bookId != null && Br(s, n.bookId, g, v);
320  }, b = Dt({ networkMode: "offlineFirst", mutationFn: async ({ entryIds: g, status: v, intentId: j }) => {
321    const C = Array.from(new Set(g));
322    if (C.length === 0) throw new Error("memorization_entry_ids_required");
323    const M = [];
324    try {
325      return await sr(async () => {
326        var o;
327        const p = C.filter((P) => i.current.get(P) === j);
328        if (p.length === 0) return { queued: false };
329        if (n.targetType === "personal" && p.some((P) => P <= 0)) throw new Error("memorization_entry_not_synced");
330        let y = [], S = false;
331        try {
332          y = (o = await Vn({ academyId: n.academyId, userId: n.userId, deviceId: n.deviceId, targetType: n.targetType, entryIds: p, status: v })) != null ? o : [], S = true;
333        } catch (P) {
334          if (!Je()) throw P;
335        }
336        if (!Je()) return { queued: S };
337        let _ = y;
338        if (_.length > 0) try {
339          _ = await $n(_);
340        } catch {
341        }
342        const E = new Map(_.map((P) => [P.payload.entryId, P])), T = y.length > 0 ? p.filter((P) => E.has(P)) : p;
343        try {
344          for (let P = 0; P < T.length; P += Sr) {
345            const V = T.slice(P, P + Sr);
346            await Oe.updateMemorizationStatus(n.targetType, V, v), M.push(...V);
347            const xe = V.map((O) => E.get(O)).filter((O) => O != null);
348            await zn(xe);
349          }
350        } catch (P) {
351          if (S) return { queued: true };
352          throw P;
353        }
354        return { queued: false };
355      });
356    } catch (o) {
357      throw new Vr(o, M);
358    }
359  }, onMutate: async ({ entryIds: g, status: v, intentId: j }) => {
360    const C = Array.from(new Set(g)), M = n.targetType === "personal" ? Me : ["vocabulary", "book-entries", n.bookId];
361    await s.cancelQueries({ queryKey: M, exact: true });
362    const o = x(C);
363    C.forEach((y) => {
364      var S;
365      const _ = (S = i.current.get(y)) != null ? S : 0;
366      j > _ && i.current.set(y, j);
367    });
368    const p = C.filter((y) => i.current.get(y) === j);
369    return p.forEach((y) => {
370      d.current.set(y, { intentId: j, status: v });
371    }), m(new Map(p.map((y) => [y, v]))), { previousStatuses: o };
372  }, onSuccess: async (g, v) => {
373    const j = n.targetType === "personal" ? Me : ["vocabulary", "book-entries", n.bookId];
374    await s.cancelQueries({ queryKey: j, exact: true }), await u.current(), v.entryIds.forEach((M) => {
375      var o;
376      ((o = d.current.get(M)) == null ? void 0 : o.intentId) === v.intentId && d.current.delete(M);
377    });
378    const C = v.entryIds.filter((M) => i.current.get(M) === v.intentId);
379    m(new Map(C.map((M) => [M, v.status]))), f.current();
380  }, onError: async (g, v, j) => {
381    if (!j) return;
382    const C = n.targetType === "personal" ? Me : ["vocabulary", "book-entries", n.bookId];
383    await s.cancelQueries({ queryKey: C, exact: true }), await u.current(), v.entryIds.forEach((y) => {
384      var S;
385      ((S = d.current.get(y)) == null ? void 0 : S.intentId) === v.intentId && d.current.delete(y);
386    });
387    const M = new Set(g instanceof Vr ? g.persistedEntryIds : []), o = new Map([...j.previousStatuses].filter(([y]) => !M.has(y) && i.current.get(y) === v.intentId));
388    m(o, v.status);
389    const p = [...M].filter((y) => i.current.get(y) === v.intentId);
390    p.length > 0 && m(new Map(p.map((y) => [y, v.status]))), f.current();
391  } });
392  return { moveEntries: (g, v) => (h.current += 1, b.mutateAsync({ entryIds: g, status: v, intentId: h.current }).then(() => {
393  })), isPending: b.isPending, error: b.error };
394}
395const ut = { default: "\uAE30\uBCF8", memorized: "\uC554\uAE30\uB428", known: "\uC544\uB294 \uB2E8\uC5B4" };
396function ma(n) {
397  return n.reduce((s, l) => (s[l.memorization_status] += 1, s), { default: 0, memorized: 0, known: 0 });
398}
399function ur(n, s) {
400  return n.filter((l) => l.memorization_status === s);
401}
402function Sn(n, s = Math.random) {
403  const l = [...n];
404  for (let d = l.length - 1; d > 0; d -= 1) {
405    const f = Math.floor(s() * (d + 1));
406    [l[d], l[f]] = [l[f], l[d]];
407  }
408  return l;
409}
410function fa(n, s, l = Math.random) {
411  const d = Math.min(Math.max(Math.trunc(s), 0), n.length);
412  return Sn(n, l).slice(0, d);
413}
414function $r(n, s) {
415  return n instanceof Error && n.message.trim() ? n.message : s;
416}
417const xa = ["button:not([disabled])", "input:not([disabled])", "select:not([disabled])", "textarea:not([disabled])", "a[href]", '[tabindex]:not([tabindex="-1"])'].join(",");
418function zr(n) {
419  return [...n.querySelectorAll(xa)].filter((s) => !s.hidden && s.getAttribute("aria-hidden") !== "true");
420}
421function Lr(n) {
422  return !!(n != null && n.isConnected && !n.matches(':disabled, [aria-disabled="true"]') && !n.closest('[inert], [aria-hidden="true"]'));
423}
424function _n(n, s, l, d) {
425  a.useEffect(() => {
426    var f;
427    if (!n) return;
428    const u = document.activeElement instanceof HTMLElement ? document.activeElement : null, h = (f = d == null ? void 0 : d.current) != null ? f : null, i = document.body.style.overflow;
429    document.body.style.overflow = "hidden";
430    const x = requestAnimationFrame(() => {
431      var b;
432      const g = s.current;
433      if (!g) return;
434      const v = l == null ? void 0 : l.current;
435      ((b = v != null ? v : zr(g)[0]) != null ? b : g).focus();
436    }), m = (b) => {
437      if (b.key !== "Tab") return;
438      const g = s.current;
439      if (!g) return;
440      const v = zr(g);
441      if (v.length === 0) {
442        b.preventDefault(), g.focus();
443        return;
444      }
445      const j = v[0], C = v[v.length - 1], M = document.activeElement;
446      g.contains(M) ? b.shiftKey && M === j ? (b.preventDefault(), C.focus()) : !b.shiftKey && M === C && (b.preventDefault(), j.focus()) : (b.preventDefault(), (b.shiftKey ? C : j).focus());
447    };
448    return document.addEventListener("keydown", m, true), () => {
449      cancelAnimationFrame(x), document.removeEventListener("keydown", m, true), document.body.style.overflow = i;
450      const b = Lr(u) ? u : Lr(h) ? h : null;
451      b == null || b.focus({ preventScroll: true });
452    };
453  }, [s, l, n, d]);
454}
455const ga = 10, ha = 72, pa = 88, Fr = 180, Hr = 220, Kr = 80, qr = 180;
456function ba(n) {
457  return n === "default" ? "memorized" : "known";
458}
459function zt() {
460  return new Promise((n) => {
461    requestAnimationFrame(() => requestAnimationFrame(() => n()));
462  });
463}
464function ya({ open: n, sourceStatus: s, entries: l, onMoveEntries: d, onClose: f, random: u = Math.random, returnFocusRef: h, pronunciationSource: i }) {
465  var x, m;
466  const b = ur(l, s), [g, v] = a.useState(b), [j, C] = a.useState(0), [M, o] = a.useState(false), [p, y] = a.useState(false), [S, _] = a.useState({ x: 0, y: 0 }), [E, T] = a.useState(null), [P, V] = a.useState(false), [xe, O] = a.useState(null), [Y, A] = a.useState(false), [ge, G] = a.useState(false), [ue, F] = a.useState([]), [Ne, R] = a.useState(null), [D, K] = a.useState(""), ee = a.useRef(null), he = a.useRef(false), te = a.useRef(false), z = a.useRef(false), H = a.useRef(null), U = a.useRef(null), oe = a.useRef(false), we = a.useRef(s), le = a.useRef(null);
467  _n(n, le, void 0, h), a.useEffect(() => {
468    n && (!oe.current || we.current !== s) && (v(ur(l, s)), C(0), o(false), _({ x: 0, y: 0 }), T(null), V(false), O(null), G(false), F([]), R(null), K(""), z.current = false, U.current = null, we.current = s), n || (ee.current = null, y(false), T(null), V(false), z.current = false), oe.current = n;
469  }, [l, n, s]);
470  const L = g[j], Ee = a.useMemo(() => g.map((k) => {
471    var I;
472    return { id: k.id, source: i, word: k.word, meaning: (I = k.meaning) != null ? I : "" };
473  }), [g, i]), { isSupported: Be, isPlaying: pe, currentIndex: Ie, playItem: me, stopTTS: Le } = jr(Ee), Ve = ba(s), qe = s === "default" ? "\uC554\uAE30\uC644\uB8CC" : "\uC544\uB294 \uB2E8\uC5B4\uB85C \uBCF4\uB0B4\uAE30", se = Y || ge || E !== null || P, _e = ue[ue.length - 1], re = !!(U.current && U.current.record.entry.id === (_e == null ? void 0 : _e.entry.id) && U.current.record.targetStatus === (_e == null ? void 0 : _e.targetStatus)), et = !!(_e && !ge && E === null && !P && (!te.current || re)), Ye = () => {
474    o(false), _({ x: 0, y: 0 }), T(null), V(false), O(null), z.current = false;
475  }, tt = (k) => {
476    if (Y || z.current || E) return;
477    pe && Le();
478    const I = k === "next" ? Math.min(g.length - 1, j + 1) : Math.max(0, j - 1);
479    if (I === j) {
480      _({ x: 0, y: 0 });
481      return;
482    }
483    z.current = true, _({ x: 0, y: 0 }), O(null), R(null), T({ direction: k, phase: "exit", targetIndex: I });
484  }, be = () => tt("previous"), fe = () => {
485    tt("next");
486  }, Fe = a.useCallback(() => {
487    if (E) {
488      if (E.phase === "exit") {
489        C(E.targetIndex), o(false), _({ x: 0, y: 0 }), T({ ...E, phase: "prepare-enter" });
490        return;
491      }
492      E.phase === "enter" && (T(null), z.current = false);
493    }
494  }, [E]);
495  a.useEffect(() => {
496    if (!E) return;
497    if (E.phase === "prepare-enter") {
498      let W = 0;
499      const Z = requestAnimationFrame(() => {
500        W = requestAnimationFrame(() => {
501          T((ye) => (ye == null ? void 0 : ye.phase) === "prepare-enter" ? { ...ye, phase: "enter" } : ye);
502        });
503      });
504      return () => {
505        cancelAnimationFrame(Z), W && cancelAnimationFrame(W);
506      };
507    }
508    const k = E.phase === "exit" ? Fr : Hr, I = window.setTimeout(Fe, k + Kr);
509    return () => window.clearTimeout(I);
510  }, [Fe, E]);
511  const ae = a.useCallback(() => new Promise((k) => {
512    let I = 0;
513    const W = () => {
514      H.current === W && (H.current = null, window.clearTimeout(I), k());
515    };
516    H.current = W, I = window.setTimeout(W, qr + Kr);
517  }), []), He = a.useCallback(() => {
518    var k;
519    (k = H.current) == null || k.call(H);
520  }, []), Re = async (k, I) => {
521    if (te.current || z.current || !L) return;
522    pe && Le(), te.current = true;
523    const W = L.id, Z = g.length, ye = { entry: L, sourceStatus: s, index: j, targetStatus: k };
524    A(true), R(null), O(I), _({ x: 0, y: 0 });
525    const ce = ae(), $e = d([W], k).then(() => ({ ok: true }), (ke) => ({ ok: false, error: ke })), X = { record: ye, persistence: $e, undoRequested: false };
526    U.current = X;
527    let q = false;
528    try {
529      await ce, q = true, V(true), F((ne) => [...ne, ye]), v((ne) => ne.filter((ve) => ve.id !== W)), C((ne) => {
530        const ve = Math.max(0, Z - 1);
531        return ve === 0 ? 0 : Math.min(ne, ve - 1);
532      }), o(false), O(null), await zt(), V(false);
533      const ke = await $e;
534      if (!ke.ok) {
535        if (X.undoRequested) return;
536        throw ke.error;
537      }
538      X.undoRequested || K(`${L.word}\uC744 ${ut[k]} \uD3F4\uB354\uB85C \uC62E\uACBC\uC2B5\uB2C8\uB2E4.`);
539    } catch (ke) {
540      if (X.undoRequested) return;
541      He(), V(true), q && (F((ne) => {
542        var ve;
543        return ((ve = ne[ne.length - 1]) == null ? void 0 : ve.entry.id) === W ? ne.slice(0, -1) : ne;
544      }), v((ne) => {
545        if (ne.some((Xe) => Xe.id === W)) return ne;
546        const ve = [...ne];
547        return ve.splice(Math.min(j, ve.length), 0, L), ve;
548      }), C(Math.min(j, Z - 1)), o(false), _({ x: 0, y: 0 })), O(null), R($r(ke, "\uB2E8\uC5B4\uB97C \uC774\uB3D9\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694.")), await zt(), V(false);
549    } finally {
550      X.undoRequested || (U.current === X && (U.current = null), te.current = false), A(false);
551    }
552  }, rt = async () => {
553    const k = ue[ue.length - 1], I = U.current, W = !!(I && I.record.entry.id === (k == null ? void 0 : k.entry.id) && I.record.targetStatus === (k == null ? void 0 : k.targetStatus) && !I.undoRequested);
554    if (!k || z.current || E !== null || P || ge || te.current && !W) return;
555    I && W ? I.undoRequested = true : te.current = true;
556    const Z = g, ye = j, ce = M, $e = Math.min(k.index, g.length);
557    G(true), R(null);
558    try {
559      if (V(true), v((X) => {
560        if (X.some((ke) => ke.id === k.entry.id)) return X;
561        const q = [...X];
562        return q.splice(Math.min(k.index, q.length), 0, { ...k.entry, memorization_status: k.sourceStatus }), q;
563      }), C($e), o(false), _({ x: 0, y: 0 }), O(null), F((X) => {
564        var q;
565        return ((q = X[X.length - 1]) == null ? void 0 : q.entry.id) === k.entry.id ? X.slice(0, -1) : X;
566      }), await zt(), V(false), I && W) {
567        if ((await I.persistence).ok) {
568          const q = await d([k.entry.id], k.sourceStatus).then(() => ({ ok: true }), (ke) => ({ ok: false, error: ke }));
569          if (!q.ok) throw q.error;
570        }
571      } else {
572        const X = await d([k.entry.id], k.sourceStatus).then(() => ({ ok: true }), (q) => ({ ok: false, error: q }));
573        if (!X.ok) throw X.error;
574      }
575      K(`${k.entry.word}\uC758 ${ut[k.targetStatus]} \uD3F4\uB354 \uC774\uB3D9\uC744 \uCDE8\uC18C\uD588\uC2B5\uB2C8\uB2E4.`);
576    } catch (X) {
577      V(true), v(Z), C(ye), o(ce), _({ x: 0, y: 0 }), O(null), F(ue), R($r(X, "\uD3F4\uB354 \uC774\uB3D9\uC744 \uCDE8\uC18C\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694.")), await zt(), V(false);
578    } finally {
579      U.current === I && (U.current = null), te.current = false, A(false), G(false);
580    }
581  };
582  if (a.useEffect(() => {
583    if (!n) return;
584    const k = (I) => {
585      if (I.key === "Escape") {
586        se || (I.preventDefault(), f());
587        return;
588      }
589      !L || se || (I.key === "ArrowLeft" ? (I.preventDefault(), be()) : I.key === "ArrowRight" ? (I.preventDefault(), fe()) : I.key === "ArrowUp" ? (I.preventDefault(), Re(Ve, "up")) : I.key === "ArrowDown" && s === "memorized" && (I.preventDefault(), Re("default", "down")));
590    };
591    return window.addEventListener("keydown", k), () => window.removeEventListener("keydown", k);
592  }), !n) return null;
593  const Ae = (k) => {
594    if (!(se || z.current || k.isPrimary === false || k.pointerType === "mouse" && k.button !== 0)) {
595      ee.current = { pointerId: k.pointerId, startX: k.clientX, startY: k.clientY, axis: "pending" }, y(true);
596      try {
597        k.currentTarget.setPointerCapture(k.pointerId);
598      } catch {
599      }
600    }
601  }, mt = (k) => {
602    const I = ee.current;
603    if (!I || I.pointerId !== k.pointerId) return;
604    const W = k.clientX - I.startX, Z = k.clientY - I.startY;
605    if (I.axis === "pending") {
606      if (Math.max(Math.abs(W), Math.abs(Z)) < ga) return;
607      I.axis = Math.abs(W) >= Math.abs(Z) ? "horizontal" : "vertical";
608    }
609    if (k.preventDefault(), I.axis === "horizontal") _({ x: W, y: 0 });
610    else {
611      const ye = s === "default" && Z > 0 ? Math.min(Z * 0.18, 28) : Z;
612      _({ x: 0, y: ye });
613    }
614  }, nt = (k, I) => {
615    const W = ee.current;
616    if (!W || W.pointerId !== k.pointerId) return;
617    const Z = k.clientX - W.startX, ye = k.clientY - W.startY, ce = W.axis;
618    try {
619      k.currentTarget.hasPointerCapture(k.pointerId) && k.currentTarget.releasePointerCapture(k.pointerId);
620    } catch {
621    }
622    if (ee.current = null, y(false), I) {
623      _({ x: 0, y: 0 });
624      return;
625    }
626    if (ce !== "pending" && (he.current = true, window.setTimeout(() => {
627      he.current = false;
628    }, 0)), ce === "horizontal" && Math.abs(Z) >= ha) {
629      Z < 0 ? fe() : be();
630      return;
631    }
632    if (ce === "vertical" && Math.abs(ye) >= pa) {
633      if (ye < 0) {
634        Re(Ve, "up");
635        return;
636      }
637      if (s === "memorized") {
638        Re("default", "down");
639        return;
640      }
641    }
642    _({ x: 0, y: 0 });
643  }, at = () => {
644    se || g.length < 2 || (pe && Le(), v((k) => Sn(k, u)), C(0), Ye(), R(null), K("\uB0A8\uC740 \uCE74\uB4DC \uC21C\uC11C\uB97C \uC11E\uC5C8\uC2B5\uB2C8\uB2E4."));
645  }, Qe = E ? E.phase === "exit" ? E.direction === "next" ? "translate3d(-120vw, 0, 0) rotate(-8deg)" : "translate3d(120vw, 0, 0) rotate(8deg)" : E.phase === "prepare-enter" ? E.direction === "next" ? "translate3d(120vw, 0, 0) rotate(6deg)" : "translate3d(-120vw, 0, 0) rotate(-6deg)" : "translate3d(0px, 0px, 0) rotate(0deg)" : null, ft = Qe != null ? Qe : xe === "up" ? "translate3d(0, -130vh, 0) rotate(-4deg)" : xe === "down" ? "translate3d(0, 130vh, 0) rotate(4deg)" : `translate3d(${S.x}px, ${S.y}px, 0) rotate(${S.x / 28}deg)`, st = p || P || (E == null ? void 0 : E.phase) === "prepare-enter" ? "none" : (E == null ? void 0 : E.phase) === "exit" ? `transform ${Fr}ms cubic-bezier(0.4, 0, 1, 1)` : (E == null ? void 0 : E.phase) === "enter" ? `transform ${Hr}ms cubic-bezier(0.22, 1, 0.36, 1)` : xe ? `transform ${qr}ms cubic-bezier(0.4, 0, 1, 1)` : "transform 180ms ease-out", xt = { transform: ft, transition: st, touchAction: "none" };
646  return fr.createPortal(e.jsxs("div", { ref: le, tabIndex: -1, className: "fixed inset-0 z-[100] flex flex-col overflow-hidden bg-slate-950 text-white", role: "dialog", "aria-modal": "true", "aria-labelledby": "flashcard-deck-title", "aria-busy": se, children: [e.jsxs("header", { className: "flex items-center gap-3 pb-3 pl-[max(1rem,env(safe-area-inset-left))] pr-[max(1rem,env(safe-area-inset-right))] pt-[max(0.75rem,env(safe-area-inset-top))]", children: [e.jsxs("div", { className: "min-w-0 flex-1", children: [e.jsxs("h2", { id: "flashcard-deck-title", className: "truncate text-base font-bold", children: [ut[s], " \uC554\uAE30\uCE74\uB4DC"] }), e.jsx("p", { className: "mt-0.5 text-xs text-white/55", children: g.length > 0 ? `${j + 1} / ${g.length}` : "\uC138\uC158 \uC644\uB8CC" })] }), e.jsxs("button", { type: "button", onClick: at, disabled: se || g.length < 2, className: "flex min-h-10 items-center gap-1.5 rounded-xl border border-white/15 bg-white/10 px-3 text-sm font-semibold text-white transition-colors hover:bg-white/15 focus:outline-none focus:ring-2 focus:ring-white/40 disabled:opacity-35", children: [e.jsx(Pt, { className: "h-4 w-4", "aria-hidden": "true" }), "\uC11E\uAE30"] }), e.jsx("button", { type: "button", "aria-label": "\uC554\uAE30\uCE74\uB4DC \uB2EB\uAE30", disabled: se, onClick: f, className: "rounded-xl p-2.5 text-white/70 transition-colors hover:bg-white/10 hover:text-white focus:outline-none focus:ring-2 focus:ring-white/40 disabled:opacity-35", children: e.jsx(_t, { className: "h-5 w-5", "aria-hidden": "true" }) })] }), e.jsx("p", { className: "sr-only", "aria-live": "polite", children: D }), g.length === 0 ? e.jsxs("div", { className: "flex min-h-0 flex-1 flex-col items-center justify-center px-6 text-center", children: [e.jsx(Jn, { className: "h-16 w-16 text-emerald-400", "aria-hidden": "true" }), e.jsx("h3", { className: "mt-5 text-2xl font-bold", children: "\uC774\uBC88 \uC554\uAE30\uB97C \uC644\uB8CC\uD588\uC5B4\uC694" }), e.jsx("p", { className: "mt-2 text-sm text-white/60", children: "\uC774\uB3D9\uD55C \uB2E8\uC5B4\uB294 \uAC01 \uD3F4\uB354\uC5D0\uC11C \uB2E4\uC2DC \uD655\uC778\uD560 \uC218 \uC788\uC5B4\uC694." }), Ne && e.jsx("p", { role: "alert", className: "mt-3 text-sm text-red-300", children: Ne }), e.jsxs("div", { className: "mt-7 flex items-center gap-2", children: [e.jsx("button", { type: "button", onClick: () => {
647    rt();
648  }, disabled: !et, className: "flex h-12 shrink-0 items-center justify-center gap-1.5 rounded-xl border border-white/20 bg-white/10 px-4 text-xs font-semibold text-white transition-colors hover:bg-white/15 focus:outline-none focus:ring-2 focus:ring-white/40 disabled:opacity-35", children: "\uCDE8\uC18C" }), e.jsx("button", { type: "button", disabled: se, onClick: f, className: "h-12 rounded-xl bg-white px-7 text-sm font-bold text-slate-950 transition-colors hover:bg-white/90 focus:outline-none focus:ring-2 focus:ring-white/60 disabled:opacity-40", children: "\uD3F4\uB354\uB85C \uB3CC\uC544\uAC00\uAE30" })] })] }) : e.jsxs(e.Fragment, { children: [e.jsxs("main", { className: "flex min-h-0 flex-1 flex-col pl-[max(1rem,env(safe-area-inset-left))] pr-[max(1rem,env(safe-area-inset-right))]", children: [e.jsxs("div", { className: "flex h-10 shrink-0 items-center justify-center text-sm font-semibold text-emerald-300", children: [e.jsx(ea, { className: "mr-1.5 h-4 w-4", "aria-hidden": "true" }), qe] }), e.jsx("div", { className: "relative mx-auto flex min-h-0 w-full max-w-lg flex-1 items-center justify-center py-2 [perspective:1200px]", children: e.jsxs("div", { "data-testid": "flashcard-gesture-surface", onPointerDown: Ae, onPointerMove: mt, onPointerUp: (k) => nt(k, false), onPointerCancel: (k) => nt(k, true), onTransitionEnd: (k) => {
649    k.target !== k.currentTarget || k.propertyName !== "transform" || (E ? Fe() : xe && He());
650  }, className: "relative aspect-[4/5] max-h-full w-full max-w-[25rem] select-none rounded-[2rem]", style: xt, children: [e.jsx("button", { type: "button", "aria-label": M ? `${L == null ? void 0 : L.word} \uB73B \uCE74\uB4DC. \uB73B: ${((x = L == null ? void 0 : L.meaning) == null ? void 0 : x.trim()) || "\uB73B \uC815\uBCF4 \uC5C6\uC74C"}. \uC55E\uBA74\uC744 \uBCF4\uB824\uBA74 \uB204\uB974\uC138\uC694.` : `${L == null ? void 0 : L.word} \uB2E8\uC5B4 \uCE74\uB4DC. \uB73B\uC744 \uBCF4\uB824\uBA74 \uB204\uB974\uC138\uC694.`, disabled: se, onClick: (k) => {
651    if (he.current) {
652      k.preventDefault();
653      return;
654    }
655    o((I) => !I), R(null);
656  }, className: "absolute inset-0 rounded-[2rem] text-left outline-none focus-visible:ring-4 focus-visible:ring-primary/60 disabled:cursor-wait", children: e.jsxs("span", { className: "absolute inset-0 block transition-transform duration-500 [transform-style:preserve-3d]", style: { transform: M ? "rotateY(180deg)" : "rotateY(0deg)" }, children: [e.jsxs("span", { className: "absolute inset-0 flex flex-col items-center justify-center rounded-[2rem] border border-white/20 bg-gradient-to-br from-white to-slate-100 px-6 text-center text-slate-950 shadow-2xl [backface-visibility:hidden]", style: { WebkitBackfaceVisibility: "hidden" }, children: [e.jsx("span", { className: "break-words text-4xl font-extrabold tracking-tight sm:text-5xl", children: L == null ? void 0 : L.word }), e.jsx("span", { className: "absolute bottom-6 text-xs font-medium text-slate-400", children: "\uD0ED\uD558\uBA74 \uB73B\uC774 \uBCF4\uC5EC\uC694" })] }), e.jsxs("span", { className: "absolute inset-0 flex flex-col items-center justify-center rounded-[2rem] border border-primary/30 bg-gradient-to-br from-primary to-indigo-700 px-6 text-center text-white shadow-2xl [backface-visibility:hidden]", style: { transform: "rotateY(180deg)", WebkitBackfaceVisibility: "hidden" }, children: [e.jsx("span", { className: "whitespace-pre-line break-words text-2xl font-bold leading-relaxed sm:text-3xl", children: ((m = L == null ? void 0 : L.meaning) == null ? void 0 : m.trim()) || "\uB73B \uC815\uBCF4 \uC5C6\uC74C" }), e.jsx("span", { className: "absolute bottom-6 text-xs font-medium text-white/60", children: "\uD0ED\uD558\uBA74 \uB2E8\uC5B4\uB85C \uB3CC\uC544\uAC00\uC694" })] })] }) }), e.jsx("button", { type: "button", "aria-label": pe && Ie === j ? `${L == null ? void 0 : L.word} \uBC1C\uC74C \uC911\uC9C0` : `${L == null ? void 0 : L.word} \uBC1C\uC74C \uC7AC\uC0DD`, title: Be ? "\uBC1C\uC74C \uB4E3\uAE30" : "\uC774 \uAE30\uAE30\uC5D0\uC11C\uB294 \uBC1C\uC74C\uC744 \uC7AC\uC0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", disabled: !Be || se, onPointerDown: (k) => k.stopPropagation(), onClick: (k) => {
657    k.stopPropagation(), me(j);
658  }, className: "absolute right-5 top-5 z-10 inline-flex h-11 w-11 items-center justify-center rounded-full border border-slate-200/80 bg-white/90 text-slate-600 shadow-md backdrop-blur-sm transition-colors hover:bg-white hover:text-primary focus:outline-none focus:ring-4 focus:ring-primary/30 disabled:opacity-40", children: pe && Ie === j ? e.jsx(Ot, { className: "h-5 w-5", "aria-hidden": "true" }) : e.jsx(Nt, { className: "h-5 w-5", "aria-hidden": "true" }) })] }) }), e.jsx("div", { className: "flex h-10 shrink-0 items-center justify-center text-sm font-semibold text-amber-300", children: s === "memorized" && e.jsxs(e.Fragment, { children: [e.jsx(Er, { className: "mr-1.5 h-4 w-4", "aria-hidden": "true" }), "\uAE30\uBCF8 \uD3F4\uB354\uB85C \uBCF4\uB0B4\uAE30"] }) })] }), e.jsxs("footer", { className: "shrink-0 border-t border-white/10 bg-slate-950/95 pb-[max(0.75rem,env(safe-area-inset-bottom))] pl-[max(1rem,env(safe-area-inset-left))] pr-[max(1rem,env(safe-area-inset-right))] pt-3", children: [Ne && e.jsx("p", { role: "alert", className: "mx-auto mb-2 max-w-lg text-center text-sm text-red-300", children: Ne }), e.jsxs("div", { className: "mx-auto grid max-w-lg grid-cols-3 gap-2", children: [e.jsx("button", { type: "button", "aria-label": "\uC774\uC804 \uCE74\uB4DC", disabled: se || j === 0, onClick: be, className: "flex h-11 items-center justify-center rounded-xl border border-white/15 bg-white/10 text-white transition-colors hover:bg-white/15 focus:outline-none focus:ring-2 focus:ring-white/40 disabled:opacity-30", children: e.jsx(wr, { className: "h-5 w-5", "aria-hidden": "true" }) }), e.jsxs("button", { type: "button", disabled: se, onClick: () => {
659    o((k) => !k), R(null);
660  }, className: "flex h-11 items-center justify-center gap-1.5 rounded-xl border border-white/15 bg-white/10 px-2 text-xs font-semibold text-white transition-colors hover:bg-white/15 focus:outline-none focus:ring-2 focus:ring-white/40 disabled:opacity-30", children: [e.jsx(ta, { className: "h-4 w-4", "aria-hidden": "true" }), "\uCE74\uB4DC \uB4A4\uC9D1\uAE30"] }), e.jsx("button", { type: "button", "aria-label": "\uB2E4\uC74C \uCE74\uB4DC", disabled: se || j >= g.length - 1, onClick: fe, className: "flex h-11 items-center justify-center rounded-xl border border-white/15 bg-white/10 text-white transition-colors hover:bg-white/15 focus:outline-none focus:ring-2 focus:ring-white/40 disabled:opacity-30", children: e.jsx(Ln, { className: "h-5 w-5", "aria-hidden": "true" }) })] }), e.jsxs("div", { className: "mx-auto mt-2 flex max-w-lg gap-2", children: [s === "memorized" && e.jsxs("button", { type: "button", disabled: se, onClick: () => {
661    Re("default", "down");
662  }, className: "flex h-11 min-w-0 flex-1 items-center justify-center gap-1.5 rounded-xl bg-amber-400 px-3 text-sm font-bold text-slate-950 transition-colors hover:bg-amber-300 focus:outline-none focus:ring-2 focus:ring-amber-300 disabled:opacity-40", children: [e.jsx(Er, { className: "h-4 w-4", "aria-hidden": "true" }), "\uAE30\uBCF8 \uD3F4\uB354\uB85C"] }), e.jsx("button", { type: "button", onClick: () => {
663    rt();
664  }, disabled: !et, className: "flex h-11 shrink-0 items-center justify-center gap-1.5 rounded-xl border border-white/20 bg-white/10 px-3 text-xs font-semibold text-white transition-colors hover:bg-white/15 focus:outline-none focus:ring-2 focus:ring-white/40 disabled:opacity-35", children: "\uCDE8\uC18C" }), e.jsx("button", { type: "button", disabled: se, onClick: () => {
665    Re(Ve, "up");
666  }, className: "flex h-11 min-w-0 flex-1 items-center justify-center rounded-xl bg-emerald-400 px-3 text-sm font-bold text-slate-950 transition-colors hover:bg-emerald-300 focus:outline-none focus:ring-2 focus:ring-emerald-300 disabled:opacity-40", children: qe })] })] })] })] }), document.body);
667}
668function va({ status: n, entryCount: s, onOpenCards: l, disabled: d = false, className: f = "" }) {
669  if (n === "known") return null;
670  const u = d || s === 0;
671  return e.jsx("div", { className: f, children: e.jsxs("button", { type: "button", onClick: l, disabled: u, className: "inline-flex h-8 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-lg bg-primary px-2.5 text-xs font-semibold text-white transition-colors hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-primary/40 focu
671s:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-45", children: [e.jsx(ra, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), "\uC554\uAE30\uCE74\uB4DC"] }) });
672}
673const bt = ["default", "memorized", "known"];
674function wa({ activeStatus: n, counts: s, onChange: l, disabled: d = false, className: f = "", activeTabRef: u }) {
675  const h = a.useRef([]), i = (x, m) => {
676    var b;
677    if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(x.key)) return;
678    x.preventDefault();
679    let g = m;
680    x.key === "ArrowLeft" ? g = (m - 1 + bt.length) % bt.length : x.key === "ArrowRight" ? g = (m + 1) % bt.length : x.key === "Home" ? g = 0 : x.key === "End" && (g = bt.length - 1);
681    const v = bt[g];
682    l(v), (b = h.current[g]) == null || b.focus();
683  };
684  return e.jsx("div", { role: "tablist", "aria-label": "\uC554\uAE30 \uD3F4\uB354", className: `grid grid-cols-3 gap-1 rounded-2xl bg-gray-100 p-1 ${f}`, children: bt.map((x, m) => {
685    const b = x === n, g = ut[x];
686    return e.jsxs("button", { ref: (v) => {
687      h.current[m] = v, b && u && (u.current = v);
688    }, id: `memorization-tab-${x}`, type: "button", role: "tab", "aria-label": `${g} ${s[x]}\uAC1C`, "aria-selected": b, "aria-controls": `memorization-panel-${x}`, tabIndex: b ? 0 : -1, disabled: d, onClick: () => l(x), onKeyDown: (v) => i(v, m), className: `flex min-h-11 min-w-0 items-center justify-center gap-1 rounded-xl px-2 py-1.5 text-sm font-semibold transition-colors md:block focus:outline-none focus:ring-2 focus:ring-primary/40 disabled:cursor-not-allowed disabled:opacity-50 ${b ? "bg-white text-primary shadow-sm" : "text-gray-500 hover:bg-white/60 hover:text-gray-700"}`, children: [e.jsx("span", { className: "min-w-0 truncate md:block", children: g }), e.jsxs("span", { className: `shrink-0 text-xs font-medium md:mt-0.5 md:block ${b ? "text-primary/70" : "text-gray-400"}`, children: [s[x], "\uAC1C"] })] }, x);
689  }) });
690}
691const Ur = 20;
692function ja({ open: n, status: s, entries: l, onStart: d, onClose: f, random: u = Math.random, returnFocusRef: h }) {
693  const i = a.useMemo(() => ur(l, s), [l, s]), x = Math.min(Ur, i.length), [m, b] = a.useState(String(x)), [g, v] = a.useState(null), j = a.useRef(null), C = a.useRef(null);
694  if (_n(n, C, j, h), a.useEffect(() => {
695    n && (b(String(x)), v(null), requestAnimationFrame(() => {
696      var o;
697      return (o = j.current) == null ? void 0 : o.focus();
698    }));
699  }, [x, n, s]), a.useEffect(() => {
700    if (!n) return;
701    const o = (p) => {
702      p.key === "Escape" && (p.preventDefault(), f());
703    };
704    return window.addEventListener("keydown", o), () => window.removeEventListener("keydown", o);
705  }, [f, n]), !n) return null;
706  const M = (o) => {
707    o.preventDefault();
708    const p = Number(m);
709    if (!Number.isFinite(p) || p < 1 || i.length === 0) {
710      v("\uC554\uAE30\uD560 \uB2E8\uC5B4 \uAC1C\uC218\uB97C 1\uAC1C \uC774\uC0C1 \uC785\uB825\uD574 \uC8FC\uC138\uC694.");
711      return;
712    }
713    const y = Math.min(Math.trunc(p), i.length);
714    b(String(y)), v(null), d(fa(i, y, u));
715  };
716  return fr.createPortal(e.jsx("div", { className: "fixed inset-0 z-[100] flex items-center justify-center bg-black/50 px-4 py-[max(1rem,env(safe-area-inset-top))]", onClick: (o) => {
717    o.target === o.currentTarget && f();
718  }, children: e.jsxs("form", { ref: C, tabIndex: -1, role: "dialog", "aria-modal": "true", "aria-labelledby": "memorization-setup-title", "aria-describedby": "memorization-setup-description", onSubmit: M, className: "w-full max-w-sm rounded-2xl border border-gray-200 bg-white p-5 shadow-2xl", children: [e.jsxs("div", { className: "flex items-start gap-3", children: [e.jsxs("div", { className: "min-w-0 flex-1", children: [e.jsx("h2", { id: "memorization-setup-title", className: "text-lg font-bold text-gray-900", children: "\uC774\uBC88\uC5D0 \uC678\uC6B8 \uB2E8\uC5B4" }), e.jsxs("p", { id: "memorization-setup-description", className: "mt-1 text-sm text-gray-500", children: [ut[s], " \uD3F4\uB354\uC758 ", i.length, "\uAC1C \uC911 \uB79C\uB364\uC73C\uB85C \uACE8\uB77C \uCE74\uB4DC\uB97C \uB9CC\uB4ED\uB2C8\uB2E4."] })] }), e.jsx("button", { type: "button", "aria-label": "\uB2EB\uAE30", onClick: f, className: "-mr-1 rounded-lg p-2 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-primary/40", children: e.jsx(_t, { className: "h-5 w-5", "aria-hidden": "true" }) })] }), e.jsxs("div", { className: "mt-5", children: [e.jsx("label", { htmlFor: "memorization-study-count", className: "text-sm font-semibold text-gray-700", children: "\uB2E8\uC5B4 \uAC1C\uC218" }), e.jsxs("div", { className: "mt-2 flex gap-2", children: [e.jsxs("div", { className: "relative min-w-0 flex-1", children: [e.jsx("input", { ref: j, id: "memorization-study-count", type: "number", inputMode: "numeric", min: 1, step: 1, value: m, disabled: i.length === 0, "aria-invalid": g != null, "aria-describedby": g ? "memorization-count-error" : void 0, onChange: (o) => {
719    b(o.target.value), v(null);
720  }, className: "h-11 w-full rounded-xl border border-gray-300 px-3 pr-10 text-base text-gray-900 outline-none transition focus:border-primary focus:ring-2 focus:ring-primary/20 disabled:bg-gray-100" }), e.jsx("span", { className: "pointer-events-none absolute inset-y-0 right-3 flex items-center text-sm text-gray-400", children: "\uAC1C" })] }), e.jsx("button", { type: "button", disabled: i.length === 0, onClick: () => {
721    b(String(i.length)), v(null);
722  }, className: "h-11 shrink-0 rounded-xl border border-gray-300 bg-white px-4 text-sm font-semibold text-gray-700 transition-colors hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-primary/30 disabled:cursor-not-allowed disabled:opacity-45", children: "\uC804\uCCB4 \uC120\uD0DD" })] }), g && e.jsx("p", { id: "memorization-count-error", role: "alert", className: "mt-2 text-sm text-red-600", children: g }), i.length > 0 && e.jsxs("p", { className: "mt-2 text-xs text-gray-400", children: ["\uAE30\uBCF8 ", Math.min(Ur, i.length), "\uAC1C \xB7 \uCD5C\uB300 ", i.length, "\uAC1C"] })] }), e.jsxs("div", { className: "mt-6 flex gap-2", children: [e.jsx("button", { type: "button", onClick: f, className: "h-11 flex-1 rounded-xl border border-gray-300 text-sm font-semibold text-gray-600 transition-colors hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-gray-300", children: "\uCDE8\uC18C" }), e.jsx("button", { type: "submit", disabled: i.length === 0, className: "h-11 flex-[1.35] rounded-xl bg-primary text-sm font-semibold text-white transition-colors hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-primary/40 focu
722s:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-45", children: "\uC554\uAE30 \uC2DC\uC791" })] })] }) }), document.body);
723}
724const Wr = 120, Na = 60, Yr = 8, ka = "900px 0px 900px 0px", Sa = 6, ct = 56, Qr = 18;
725function Xr(n) {
726  const s = n == null ? void 0 : n.closest("[data-vocab-select-index]");
727  if (!s) return null;
728  const l = Number(s.dataset.vocabSelectIndex);
729  return Number.isInteger(l) ? l : null;
730}
731function ar(n, s, l) {
732  const d = Xr(n instanceof Element ? n : null);
733  if (d != null) return d;
734  if (typeof document.elementsFromPoint != "function") return null;
735  for (const f of document.elementsFromPoint(s, l)) {
736    const u = Xr(f);
737    if (u != null) return u;
738  }
739  return null;
740}
741function _a(n) {
742  let s = n.parentElement;
743  for (; s; ) {
744    const l = window.getComputedStyle(s).overflowY;
745    if ((l === "auto" || l === "scroll") && s.scrollHeight > s.clientHeight) return s;
746    s = s.parentElement;
747  }
748  return null;
749}
750function Cn(n, s, l) {
751  const d = a.useRef(s), f = a.useRef(null), u = a.useRef(false), h = a.useRef(null), i = a.useRef(() => {
752  });
753  a.useEffect(() => {
754    d.current = s;
755  }, [s]);
756  const x = a.useCallback((o, p, y) => {
757    const S = Math.max(0, Math.min(o, p)), _ = Math.min(n.length - 1, Math.max(o, p));
758    S > _ || l((E) => {
759      const T = new Set(E);
760      for (let P = S; P <= _; P += 1) {
761        const V = n[P];
762        y ? T.add(V) : T.delete(V);
763      }
764      return T;
765    });
766  }, [n, l]), m = a.useCallback((o) => {
767    const p = f.current;
768    !p || o == null || o < 0 || o >= n.length || (x(p.lastIndex, o, p.select), p.lastIndex = o);
769  }, [x, n.length]), b = a.useCallback(() => {
770    h.current != null && (cancelAnimationFrame(h.current), h.current = null);
771  }, []);
772  a.useEffect(() => {
773    i.current = () => {
774      const o = f.current;
775      if (!(o != null && o.dragging) || !o.scrollContainer || o.scrollStep === 0) {
776        h.current = null;
777        return;
778      }
779      const p = o.scrollContainer.scrollTop;
780      o.scrollContainer.scrollTop += o.scrollStep, o.scrollContainer.scrollTop !== p && m(ar(null, o.clientX, o.clientY)), h.current = requestAnimationFrame(() => i.current());
781    };
782  }, [m]);
783  const g = a.useCallback((o, p) => {
784    const y = f.current;
785    if (!(y != null && y.scrollContainer)) return;
786    y.clientX = o, y.clientY = p;
787    const S = y.scrollContainer.getBoundingClientRect();
788    if (S.height <= ct * 2) {
789      y.scrollStep = 0, b();
790      return;
791    }
792    if (p < S.top + ct) {
793      const _ = Math.min(1, (S.top + ct - p) / ct);
794      y.scrollStep = -Math.max(2, Math.round(Qr * _));
795    } else if (p > S.bottom - ct) {
796      const _ = Math.min(1, (p - (S.bottom - ct)) / ct);
797      y.scrollStep = Math.max(2, Math.round(Qr * _));
798    } else {
799      y.scrollStep = 0, b();
800      return;
801    }
802    h.current == null && (h.current = requestAnimationFrame(() => i.current()));
803  }, [b]);
804  a.useEffect(() => () => b(), [b]);
805  const v = a.useCallback((o) => {
806    if (d.current.size === 0 || o.isPrimary === false || o.pointerType === "mouse" && o.button !== 0) return;
807    const p = o.target instanceof Element ? o.target : null, y = p == null ? void 0 : p.closest("[data-vocab-drag-handle]");
808    if (o.pointerType !== "mouse" && !y || !y && (p != null && p.closest("button, input, a, [data-vocab-selection-ignore]"))) return;
809    const S = ar(o.target, o.clientX, o.clientY);
810    if (!(S == null || S < 0 || S >= n.length)) {
811      f.current = { pointerId: o.pointerId, startX: o.clientX, startY: o.clientY, startIndex: S, lastIndex: S, select: !d.current.has(n[S]), dragging: false, clientX: o.clientX, clientY: o.clientY, scrollContainer: _a(o.currentTarget), scrollStep: 0 };
812      try {
813        o.currentTarget.setPointerCapture(o.pointerId);
814      } catch {
815      }
816    }
817  }, [n]), j = a.useCallback((o) => {
818    const p = f.current;
819    if (!p || p.pointerId !== o.pointerId) return;
820    const y = ar(o.target, o.clientX, o.clientY);
821    if (p.dragging) m(y);
822    else {
823      if (Math.hypot(o.clientX - p.startX, o.clientY - p.startY) < Sa) return;
824      p.dragging = true, x(p.startIndex, y != null ? y : p.startIndex, p.select), p.lastIndex = y != null ? y : p.startIndex;
825    }
826    o.preventDefault(), g(o.clientX, o.clientY);
827  }, [m, x, g]), C = a.useCallback((o) => {
828    const p = f.current;
829    if (!(!p || p.pointerId !== o.pointerId)) {
830      p.dragging && (u.current = true, window.setTimeout(() => {
831        u.current = false;
832      }, 0)), b();
833      try {
834        o.currentTarget.hasPointerCapture(o.pointerId) && o.currentTarget.releasePointerCapture(o.pointerId);
835      } catch {
836      }
837      f.current = null;
838    }
839  }, [b]), M = a.useCallback((o) => {
840    o.preventDefault();
841  }, []);
842  return { "data-vocab-selection-mode": s.size > 0 ? "active" : "inactive", onPointerDown: v, onPointerMove: j, onPointerUp: C, onPointerCancel: C, onClickCapture: (o) => {
843    u.current && (o.preventDefault(), o.stopPropagation());
844  }, onContextMenu: M, onDragStart: M, style: { touchAction: "pan-y", userSelect: "none", WebkitUserSelect: "none", WebkitTouchCallout: "none" } };
845}
846function Qt(n) {
847  return n === "memorized" || n === "known" ? n : "default";
848}
849function vt(n) {
850  requestAnimationFrame(() => {
851    var s;
852    (s = document.getElementById(`memorization-tab-${n}`)) == null || s.focus({ preventScroll: true });
853  });
854}
855function En({ entries: n, actionableEntries: s = n, activeStatus: l, onStatusChange: d, onMoveEntries: f, onBeforeOpen: u, disabled: h = false, pronunciationSource: i }) {
856  const [x, m] = a.useState(false), [b, g] = a.useState(null), [v, j] = a.useState("default"), C = a.useRef(null), M = a.useMemo(() => ma(n), [n]), o = a.useMemo(() => s.filter((T) => T.memorization_status === l).length, [s, l]), p = l === "known" ? null : l, y = () => {
857    p && (u(), j(p), m(true));
858  }, S = e.jsx("section", { id: `memorization-panel-${l}`, role: "tabpanel", "aria-labelledby": `memorization-tab-${l}`, className: "mb-3 space-y-2 md:mb-4 md:space-y-2.5", children: e.jsx(wa, { activeStatus: l, counts: M, onChange: d, disabled: h, activeTabRef: C }) }), _ = p ? e.jsx(va, { status: l, entryCount: o, onOpenCards: y, disabled: h, className: "ml-auto -my-1.5" }) : null, E = e.jsxs(e.Fragment, { children: [p && e.jsx(ja, { open: x, status: p, entries: s, returnFocusRef: C, onClose: () => m(false), onStart: (T) => {
859    m(false), j(p), g(T);
860  } }), e.jsx(ya, { open: b != null, sourceStatus: v, entries: b != null ? b : [], onMoveEntries: f, onClose: () => g(null), returnFocusRef: C, pronunciationSource: i })] });
861  return { folderTabs: S, folderActions: _, overlays: E };
862}
863const Ca = "[data-native-vocab-draw-zone]", Ea = 'button[data-handwriting-tap-through], input[type="checkbox"]';
864function In(n, s, l, d) {
865  return `classro:vocab-native-drawing:v1:${n}:${s}:${l}:${d}`;
866}
867function Ia(n) {
868  try {
869    const s = window.localStorage.getItem(n);
870    if (!s) return {};
871    const l = JSON.parse(s);
872    return l && typeof l == "object" ? l : {};
873  } catch {
874    return {};
875  }
876}
877function Gr(n, s, l = false) {
878  try {
879    window.localStorage.setItem(n, JSON.stringify(s));
880  } catch (d) {
881    if (l) throw d;
882  }
883}
884function Ma(n) {
885  return -n;
886}
887function wt(n) {
888  return n < 0;
889}
890function Zr(n) {
891  return n.filter((s) => !wt(s));
892}
893function Ra(n, s) {
894  var l;
895  if (s) {
896    const { verdict: d } = Yt({ word: n.word, meaning: n.meaning }, s);
897    return d === "duplicate" ? "saved" : d === "conflict" ? "conflict" : "none";
898  }
899  return (l = n.membership) != null ? l : n.in_my_vocab ? "saved" : "none";
900}
901function Aa(n) {
902  var s;
903  const l = n.filter((d) => !wt(d.id));
904  return (s = hr(l, "newest")[0]) == null ? void 0 : s.id;
905}
906function Ta(n, s) {
907  var l;
908  const d = (l = n.example_sentence) != null ? l : "";
909  return s.some((f) => {
910    var u;
911    return f.word === n.word && ((u = f.sentence) != null ? u : "") === d;
912  });
913}
914function mr(n, s, l, d) {
915  return { bookEntryId: n.id, word: n.word, incomingMeaning: n.meaning, existingMeanings: s.map((f) => {
916    var u;
917    return (u = f.meaning) != null ? u : "-";
918  }), mergeTargetEntryId: Aa(s), canAddSeparately: d ? d !== "separate_unavailable" : !Ta(n, l) };
919}
920function Da(n) {
921  const s = Object.entries(n);
922  if (s.length === 0) return null;
923  const l = {};
924  for (const [d, f] of s) l[Number(d)] = f.action === "merge" ? { action: "merge", ...f.targetEntryId != null ? { target_entry_id: f.targetEntryId } : {} } : { action: "separate" };
925  return l;
926}
927function Jr(n, s) {
928  const l = (s != null ? s : "").trim();
929  return l === "" || ca(n, l) ? n : n == null || n === "" ? l : `${n}
930${l}`;
931}
932function Pa(n, s) {
933  var l, d;
934  return { id: Ma(n.id), word: n.word, base_form: n.word, meaning: (l = n.meaning) != null ? l : null, sentence: (d = n.example_sentence) != null ? d : "", source_type: "book", homework_title: null, source_label: s, ai_status: "completed", created_at: (/* @__PURE__ */ new Date()).toISOString() };
935}
936function Oa(n, s, l) {
937  if (s != null) {
938    const u = n.findIndex((h) => h.id === s);
939    if (u >= 0) return u;
940  }
941  const d = De(l), f = hr(n.filter((u) => De(u.word) === d), "newest")[0];
942  return f ? n.findIndex((u) => u.id === f.id) : -1;
943}
944function Ba(n, s, l, d, f) {
945  var u;
946  if (!l) {
947    const x = new Set(s.map((m) => De(m.word)));
948    return n.filter((m) => !(x.has(De(m.word)) && m.source_type === "book"));
949  }
950  const h = [...n], i = [];
951  for (const x of s) {
952    const m = f == null ? void 0 : f[x.id];
953    if ((m == null ? void 0 : m.action) === "merge") {
954      const v = Oa(h, m.targetEntryId, x.word);
955      if (v >= 0) {
956        const j = h[v];
957        h[v] = { ...j, meaning: Jr(j.meaning, x.meaning), sentence: (u = Jr(j.sentence, x.example_sentence)) != null ? u : "", source_type: "book", source_label: d, ai_status: "completed" };
958        continue;
959      }
960    }
961    const b = Pa(x, d), g = h.findIndex((v) => {
962      var j;
963      return De(v.word) === De(b.word) && ((j = v.sentence) != null ? j : "") === b.sentence;
964    });
965    if (g >= 0) {
966      h[g] = { ...h[g], base_form: b.base_form, meaning: b.meaning, source_type: "book", source_label: b.source_label, ai_status: "completed" };
967      continue;
968    }
969    i.push(b);
970  }
971  return i.length === 0 ? h : [...i, ...h];
972}
973function Va(n, s, l, d, f) {
974  if (s.length === 0) return null;
975  const u = n.getQueryData(Me);
976  if (!(u != null && u.items)) return null;
977  const h = Ba(u.items, s, l, d, f), i = h.length - u.items.length;
978  return n.setQueryData(Me, { ...u, items: h, total: Math.max(0, u.total + i), per_page: h.length }), i;
979}
980function en(n, s) {
981  if (s.length === 0) return 0;
982  const l = n.getQueryData(Me);
983  if (!(l != null && l.items)) return 0;
984  const d = new Set(s), f = new Set(l.items.filter((m) => d.has(m.id) && wt(m.id)).map((m) => De(m.word))), u = [], h = l.items.filter((m) => {
985    const b = d.has(m.id) || m.source_type === "book" && f.has(De(m.word));
986    return b && u.push(m), !b;
987  });
988  if (u.length === 0) return 0;
989  n.setQueryData(Me, { ...l, items: h, total: Math.max(0, l.total - u.length), per_page: h.length }), n.setQueryData(["vocabulary", "count"], (m) => {
990    var b;
991    return typeof ((b = m == null ? void 0 : m.data) == null ? void 0 : b.total) != "number" ? m : { ...m, data: { ...m.data, total: Math.max(0, m.data.total - u.length) } };
992  });
993  const i = new Set(h.filter((m) => m.source_type === "book").map((m) => De(m.word))), x = new Set(u.map((m) => De(m.word)).filter((m) => !i.has(m)));
994  return x.size > 0 && n.setQueriesData({ queryKey: ["vocabulary", "book-entries"] }, (m) => {
995    var b;
996    return (b = m == null ? void 0 : m.data) != null && b.entries ? { ...m, data: { ...m.data, entries: m.data.entries.map((g) => x.has(De(g.word)) ? { ...g, in_my_vocab: false } : g) } } : m;
997  }), u.length;
998}
999function $a(n, s = 0) {
1000  var l, d, f, u, h, i, x, m, b;
1001  const g = (l = n.rejected) != null ? l : [];
1002  for (const S of g) de.error(S.message);
1003  const v = (d = n.added_count) != null ? d : 0, j = (f = n.merged_count) != null ? f : 0, C = Math.max(0, ((u = n.updated_count) != null ? u : 0) - j), M = (h = n.blocked_count) != null ? h : 0, o = (b = (m = (i = n.needs_decision) == null ? void 0 : i.length) != null ? m : (x = n.needs_decision_book_entry_ids) == null ? void 0 : x.length) != null ? b : 0, p = Math.max(0, o - s), y = [];
1004  v > 0 && y.push(`${v}\uAC1C \uCD94\uAC00`), j > 0 && y.push(`${j}\uAC1C \uD1B5\uD569`), C > 0 && y.push(`${C}\uAC1C \uC5C5\uB370\uC774\uD2B8`), M > 0 && y.push(`${M}\uAC1C\uB294 \uC774\uBBF8 \uC800\uC7A5\uB428`), y.length > 0 ? de.success(`${y.join(", ")}\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`) : o === 0 && g.length === 0 && de.info("\uCD94\uAC00\uD560 \uB2E8\uC5B4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."), p > 0 && de.info(`${p}\uAC1C \uB2E8\uC5B4\uB294 \uC800\uC7A5 \uBC29\uC2DD\uC744 \uB2E4\uC2DC \uC120\uD0DD\uD574 \uC8FC\uC138\uC694.`);
1005}
1006const tn = "\uC628\uB77C\uC778 \uC5F0\uACB0 \uD6C4 \uAC00\uB2A5";
1007function rn() {
1008  return Je() ? "\uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB3D9\uAE30\uD654\uB420 \uB54C \uC11C\uBC84\uC5D0\uB3C4 \uBC18\uC601\uB429\uB2C8\uB2E4." : "\uC624\uD504\uB77C\uC778 \uC0C1\uD0DC\uB85C \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC5F0\uACB0\uB418\uBA74 \uC790\uB3D9\uC73C\uB85C \uBC18\uC601\uB429\uB2C8\uB2E4.";
1009}
1010function St(n) {
1011  if (!Qn()) return;
1012  const s = /* @__PURE__ */ new Date(), l = `${String(s.getMinutes()).padStart(2, "0")}:${String(s.getSeconds()).padStart(2, "0")}.${String(s.getMilliseconds()).padStart(3, "0")}`;
1013  Xn(`${l} VOCAB ${n}`);
1014}
1015function J({ disabled: n = false, className: s, title: l, ariaLabel: d, children: f, onClick: u }) {
1016  return e.jsx("button", { type: "button", disabled: n, "aria-label": d, title: l, className: s, onClick: u, children: f });
1017}
1018function Lt({ word: n, active: s, onPlay: l, handwriting: d = false }) {
1019  return e.jsx("button", { type: "button", ...d ? { "data-handwriting-tap-through": true } : {}, "aria-label": `${n} \uBC1C\uC74C \uC7AC\uC0DD`, title: `${n} \uBC1C\uC74C \uC7AC\uC0DD`, onClick: (f) => {
1020    f.stopPropagation(), l();
1021  }, className: `inline-flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full transition-colors ${s ? "bg-primary/10 text-primary" : "text-gray-400 hover:bg-gray-100 hover:text-primary"} ${d ? "pointer-events-auto" : ""}`, children: e.jsx(Nt, { className: "h-4 w-4" }) });
1022}
1023function Mn({ enVoices: n, koVoices: s, selectedEnVoice: l, selectedKoVoice: d, onEnVoiceChange: f, onKoVoiceChange: u, onClose: h, avoidNativeButtons: i = false }) {
1024  const x = (m, b) => {
1025    if (!(typeof window > "u" || typeof window.speechSynthesis > "u")) try {
1026      window.speechSynthesis.cancel();
1027      const g = new SpeechSynthesisUtterance(b);
1028      g.voice = m, g.rate = 0.9, window.speechSynthesis.speak(g);
1029    } catch {
1030    }
1031  };
1032  return e.jsxs("div", { className: "bg-white border border-gray-200 rounded-xl shadow-lg p-4 mb-3 space-y-3", children: [e.jsxs("div", { className: "flex items-center justify-between", children: [e.jsx("h3", { className: "text-sm font-semibold text-gray-800", children: "\uC74
1032C\uC131 \uC124\uC815" }), e.jsx(J, { avoidNativeButton: i, onClick: h, className: "p-1 hover:bg-gray-100 rounded-lg transition-colors", children: e.jsx(_t, { className: "w-4 h-4 text-gray-400" }) })] }), e.jsxs("div", { children: [e.jsx("label", { className: "text-xs font-medium text-gray-500 mb-1 block", children: "\uC601\uC5B4 \uC74C\uC131" }), e.jsx("div", { className: "flex items-center gap-2", children: e.jsx("select", { value: l, onChange: (m) => {
1033    f(m.target.value);
1034    const b = n.find((g) => g.name === m.target.value);
1035    b && x(b.voice, "Hello");
1036  }, className: "flex-1 text-sm border border-gray-200 rounded-lg px-2.5 py-1.5 text-gray-700 focus:outline-none focus:ring-2 focus:ring-primary/30", children: n.map((m) => e.jsx("option", { value: m.name, children: m.name }, m.name)) }) })] }), e.jsxs("div", { children: [e.jsx("label", { className: "text-xs font-medium text-gray-500 mb-1 block", children: "\uD55C\uAD6D\uC5B4 \uC74C\uC131" }), e.jsx("div", { className: "flex items-center gap-2", children: e.jsx("select", { value: d, onChange: (m) => {
1037    u(m.target.value);
1038    const b = s.find((g) => g.name === m.target.value);
1039    b && x(b.voice, "\uC548\uB155\uD558\uC138\uC694");
1040  }, className: "flex-1 text-sm border border-gray-200 rounded-lg px-2.5 py-1.5 text-gray-700 focus:outline-none focus:ring-2 focus:ring-primary/30", children: s.map((m) => e.jsx("option", { value: m.name, children: m.name }, m.name)) }) })] }), e.jsx("p", { className: "text-xs text-gray-400", children: "\uC74C\uC131\uC744 \uBCC0\uACBD\uD558\uBA74 \uBBF8\uB9AC\uB4E3\uAE30\uAC00 \uC7AC\uC0DD\uB429\uB2C8\uB2E4. \uC120\uD0DD\uD55C \uC74C\uC131\uC740 \uC800\uC7A5\uB429\uB2C8\uB2E4." })] });
1041}
1042function Rn() {
1043  const n = a.useMemo(() => un(), []), [s, l] = a.useState(false), [d, f] = a.useState("pen"), [u, h] = a.useState("#ef4444"), i = a.useRef(/* @__PURE__ */ new Map()), [x, m] = a.useState(null), [b, g] = a.useState(false), v = a.useRef(false), j = a.useRef(null), C = a.useRef(null), M = a.useCallback(() => {
1044    var S, _;
1045    if (v.current) {
1046      (S = j.current) == null || S.call(j);
1047      return;
1048    }
1049    x != null && ((_ = i.current.get(x)) == null || _.undo());
1050  }, [x]), o = a.useCallback(() => {
1051    var S;
1052    if (v.current) {
1053      (S = C.current) == null || S.call(C);
1054      return;
1055    }
1056    i.current.forEach((_) => _.clear());
1057  }, []), p = a.useCallback((S) => {
1058    const _ = S instanceof Element ? S : null;
1059    return !(_ != null && _.closest('svg[data-handwriting-surface="true"]'));
1060  }, []), y = a.useCallback((S) => {
1061    const _ = S instanceof Element ? S : null;
1062    return !!(_ != null && _.closest(["button", '[role="button"]', "input", "select", "textarea", "a[href]", "label", '[contenteditable="true"]'].join(",")));
1063  }, []);
1064  return a.useEffect(() => {
1065    if (window.dispatchEvent(new CustomEvent(Cr, { detail: { enabled: s } })), s || m(null), s) {
1066      const S = document.activeElement;
1067      S instanceof HTMLElement && S.blur();
1068    }
1069    return () => {
1070      s && window.dispatchEvent(new CustomEvent(Cr, { detail: { enabled: false } }));
1071    };
1072  }, [s]), a.useEffect(() => {
1073    if (!s) return;
1074    const S = (E) => {
1075      !E.cancelable || !p(E.target) || y(E.target) || !("pointerType" in E && E.pointerType === "pen") && !Zn(E) || (E.preventDefault(), St(`PEN_SCROLL_BLOCK ${E.type} target=${E.target instanceof Element ? E.target.tagName.toLowerCase() : "non-element"}`));
1076    }, _ = { capture: true, passive: false };
1077    return document.addEventListener("pointermove", S, _), document.addEventListener("touchmove", S, _), () => {
1078      document.removeEventListener("pointermove", S, _), document.removeEventListener("touchmove", S, _);
1079    };
1080  }, [s, p, y]), { deviceId: n, drawingEnabled: s, setDrawingEnabled: l, handwritingTool: d, setHandwritingTool: f, handwritingColor: u, setHandwritingColor: h, handwritingHandlesRef: i, activeHandwritingEntryId: x, setActiveHandwritingEntryId: m, handleHandwritingUndo: M, handleHandwritingClear: o, largeCards: b, setLargeCards: g, nativeActiveRef: v, nativeUndoRef: j, nativeClearRef: C };
1081}
1082function An(n) {
1083  const { entityId: s, enabled: l, containerRef: d, tool: f, color: u, scopeName: h, nativeDrawingStorageKey: i, buildStorageScope: x, recordDraft: m, setActiveEntryId: b, setPersistenceStatus: g } = n, [v, j] = a.useState(() => Ia(i)), C = a.useRef(v), M = a.useCallback((T, P) => {
1084    const V = String(T), xe = x(T);
1085    g(V, { target: "local", phase: "saving", retryable: false, updatedAt: P == null ? void 0 : P.updatedAt }), (P ? pr(xe, P) : br(xe)).then(() => {
1086      g(V, { target: "local", phase: "saved", retryable: false, updatedAt: P == null ? void 0 : P.updatedAt });
1087    }).catch((Y) => {
1088      const A = Y instanceof jt ? Y : new jt("unknown_local_error");
1089      g(V, { target: "local", phase: "error", reasonCode: A.reasonCode, message: yr(A.reasonCode, h), retryable: true, updatedAt: P == null ? void 0 : P.updatedAt });
1090    });
1091  }, [x, h, g]), o = a.useCallback((T) => {
1092    const P = Number(T);
1093    Number.isFinite(P) && b(P);
1094  }, [b]), p = a.useCallback((T, P) => {
1095    const V = Number(T);
1096    Number.isFinite(V) && (m(V, P), M(V, P));
1097  }, [M, m]), y = a.useCallback((T, P) => {
1098    const V = { ...C.current, [T]: P };
1099    C.current = V, Gr(i, V), j(V);
1100  }, [i]), { isNativeActive: S, undo: _, clear: E }
1100 = Gn({ entityType: "vocabulary", entityId: s, enabled: l, zoneCanvasMode: true, coordinateSpace: "document", tool: f, color: u, containerRef: d, drawZoneSelector: Ca, tapZoneSelector: Ea, nativeDrawingDataByZone: v, onActiveZoneChange: o, onDraftChangeByZone: p, onNativeDrawingDataByZone: y });
1101  return Pn({ label: `vocabulary-sidecar:${i}`, prepare: () => {
1102    S && Gr(i, C.current, true);
1103  } }), { isNativeActive: S, undo: _, clear: E };
1104}
1105function Tn({ entryId: n, index: s, active: l, largeCards: d, isNativeActive: f, onActivate: u, renderOverlay: h, children: i }) {
1106  const x = a.useRef(null), [m, b] = a.useState(s < Yr);
1107  a.useEffect(() => {
1108    if (s < Yr) {
1109      b(true);
1110      return;
1111    }
1112    if (typeof IntersectionObserver > "u") {
1113      b(true);
1114      return;
1115    }
1116    const C = x.current;
1117    if (!C) return;
1118    const M = new IntersectionObserver(([o]) => {
1119      var p;
1120      const y = (p = o == null ? void 0 : o.isIntersecting) != null ? p : false;
1121      b(y), St(`MOUNT_GATE entry=${n} visible=${y ? "Y" : "N"}`);
1122    }, { rootMargin: ka, threshold: 0 });
1123    return M.observe(C), () => M.disconnect();
1124  }, [n, s]);
1125  const g = m || l, j = { height: d ? Wr : Na };
1126  return e.jsxs("div", { ref: x, "data-native-vocab-draw-zone": true, "data-zone-id": String(n), className: "relative bg-white rounded-xl border border-gray-200 overflow-hidden", style: j, onPointerDown: u, children: [!f && g && e.jsx("div", { className: "absolute inset-x-0 top-1/2 -translate-y-1/2", style: { height: Wr }, children: h() }), i] });
1127}
1128const nn = [{ value: "newest", label: "\uCD5C\uC2E0\uC21C" }, { value: "oldest", label: "\uC624\uB798\uB41C\uC21C" }];
1129function ks() {
1130  const [n, s] = On(), l = n.get("view"), d = n.get("bookId"), f = d ? Number(d) : null, u = f ? "book-detail" : l === "my-vocab" ? "my-vocab" : "categories", h = () => {
1131    s({ view: "my-vocab" });
1132  }, i = (m) => {
1133    s({ bookId: String(m) });
1134  }, x = () => {
1135    s({});
1136  };
1137  return u === "my-vocab" ? e.jsx(La, { onBack: x }) : u === "book-detail" && f ? e.jsx(Fa, { bookId: f, onBack: x }) : e.jsx(za, { onSelectMyVocab: h, onSelectBook: i });
1138}
1139function za({ onSelectMyVocab: n, onSelectBook: s }) {
1140  var l, d, f;
1141  const u = gr(), h = Xt(), i = xr((z) => z.user), { data: x, isLoading: m, isError: b, refetch: g } = dt({ queryKey: ["vocabulary", "count"], queryFn: () => Oe.getList({ page: 1, per_page: 1 }), select: (z) => z.data }), { data: v, isLoading: j, isError: C, refetch: M } = dt({ queryKey: ["vocabulary", "books"], queryFn: () => Oe.listBooks(), select: (z) => z.data.books, staleTime: 6e4 }), o = m || j, p = (l = x == null ? void 0 : x.total) != null ? l : null, y = a.useMemo(() => v != null ? v : [], [v]), S = b && x === void 0, _ = C && v === void 0, E = !u && x === void 0, T = !u && v === void 0, P = E && T, V = E !== T, xe = u && S && _, O = u ? S !== _ : V, Y = () => {
1142    Promise.all([g(), M()]);
1143  }, A = a.useMemo(() => un(), []), ge = (d = i == null ? void 0 : i.academy_id) != null ? d : null, G = (f = i == null ? void 0 : i.id) != null ? f : null, [ue, F] = a.useState([]), [Ne, R] = a.useState([]);
1144  a.useEffect(() => {
1145    if (ge == null || G == null) {
1146      F([]);
1147      return;
1148    }
1149    let z = false;
1150    const H = () => {
1151      Wn(ge, G).then((oe) => {
1152        z || F(oe);
1153      }).catch(() => {
1154        z || F([]);
1155      });
1156    };
1157    H();
1158    const U = on(H);
1159    return () => {
1160      z = true, U();
1161    };
1162  }, [ge, G]);
1163  const D = a.useMemo(() => {
1164    var z, H, U, oe;
1165    const we = new Set(Ne);
1166    for (const le of ue) {
1167      if (we.has(le.key)) continue;
1168      const { bookId: L, bookEntryId: Ee } = le.payload, Be = (H = (z = h.getQueryData(["vocabulary", "book-entries", L])) == null ? void 0 : z.data) == null ? void 0 : H.entries, pe = Be == null ? void 0 : Be.find((Le) => Le.id === Ee);
1169      if (!pe) continue;
1170      const Ie = (oe = (U = h.getQueryData(Me)) == null ? void 0 : U.items) != null ? oe : [], me = Yt({ word: pe.word, meaning: pe.meaning }, Ie);
1171      return { job: le, prompt: mr(pe, me.wordMatches, Ie, le.payload.needsDecisionReason) };
1172    }
1173    return null;
1174  }, [ue, h, Ne]), K = (z) => R((H) => [...H, z]), ee = (z) => {
1175    if (!D) return;
1176    const { bookId: H, bookEntryId: U } = D.job.payload;
1177    K(D.job.key), Ht({ action: "add", academyId: ge != null ? ge : 0, userId: G != null ? G : 0, deviceId: A, bookId: H, bookEntryIds: [U], decisions: { [U]: z } }).then(() => Yn());
1178  }, he = a.useMemo(() => {
1179    var z;
1180    const H = [], U = /* @__PURE__ */ new Map();
1181    for (const oe of y) {
1182      const we = oe.classroom_id;
1183      let le = U.get(we);
1184      le || (le = { classroomId: we, classroomName: (z = oe.classroom_name) != null ? z : "\uAE30\uD0C0", books: [] }, U.set(we, le), H.push(le)), le.books.push(oe);
1185    }
1186    return H;
1187  }, [y]);
1188  let te = 0;
1189  return e.jsxs("div", { className: "max-w-[1120px] mx-auto px-2 sm:px-5 pt-6 pb-24 flex flex-col gap-4", children: [D && e.jsx(wn, { prompt: D.prompt, onMerge: () => ee({ action: "merge", targetEntryId: D.prompt.mergeTargetEntryId }), onSeparate: () => ee({ action: "separate" }), onDismiss: () => K(D.job.key), onDiscard: () => {
1190    K(D.job.key), Kn(D.job.key);
1191  } }), e.jsxs("div", { children: [e.jsx("h1", { className: "text-[21px] font-extrabold tracking-[-0.3px] text-ink", children: "\uB2E8\uC5B4\uC7A5" }), e.jsx("p", { className: "mt-[5px] text-[13.5px] text-muted", children: "\uC800\uC7A5\uD55C \uB2E8\uC5B4\uC640 \uD074\uB798\uC2A4 \uB2E8\uC5B4\uC7A5\uC73C\uB85C \uC554\uAE30 \uD559\uC2B5\uC744 \uC2DC\uC791\uD558\uC138\uC694" })] }), P ? e.jsx(vr, { message: "\uC624\uD504\uB77C\uC778 \uC0C1\uD0DC\uC774\uBA70 \uB2E8\uC5B4\uC7A5 \uC815\uBCF4\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." }) : o && !V ? e.jsx("div", { className: "flex items-center justify-center h-48", children: e.jsx(We, { className: "w-8 h-8 animate-spin text-primary" }) }) : xe ? e.jsxs("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [e.jsx(Ke, { className: "mb-4 h-12 w-12 text-amber-500" }), e.jsx("h2", { className: "mb-2 text-lg font-semibold text-gray-700", children: "\uB2E8\uC5B4\uC7A5 \uC815\uBCF4\uB97C \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4" }), e.jsx("p", { className: "mb-5 text-sm text-gray-500", children: "\uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694." }), e.jsx("button", { type: "button", onClick: Y, className: "rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", children: "\uB2E4\uC2DC \uC2DC\uB3C4" })] }) : e.jsxs("div", { className: "flex flex-col gap-4", children: [O && e.jsxs("div", { role: "alert", className: "flex flex-wrap items-center gap-2 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800", children: [e.jsx(Ke, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }), e.jsx("span", { className: "min-w-0 flex-1", children: u ? "\uC77C\uBD80 \uB2E8\uC5B4\uC7A5 \uC815\uBCF4\uB97C \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4." : "\uC624\uD504\uB77C\uC778 \uC0C1\uD0DC\uC774\uBA70 \uC77C\uBD80 \uB2E8\uC5B4\uC7A5 \uC815\uBCF4\uB9CC \uD45C\uC2DC\uB429\uB2C8\uB2E4." }), u && e.jsx("button", { type: "button", onClick: Y, className: "rounded-lg border border-amber-300 bg-white px-3 py-1.5 text-xs font-semibold hover:bg-amber-100", children: "\uB2E4\uC2DC \uC2DC\uB3C4" })] }), e.jsxs("button", { onClick: n, className: "w-full flex flex-wrap items-center gap-4 px-5 py-[18px] rounded-2xl text-white text-left hover:brightness-[1.04] transition-all duration-150", style: { background: "linear-gradient(135deg, #667EEA, #764BA2)" }, children: [e.jsx("span", { className: "w-12 h-12 flex-none rounded-[14px] bg-white/[.18] flex items-center justify-center", children: e.jsx(yt, { className: "w-[22px] h-[22px]", strokeWidth: 1.8 }) }), e.jsxs("div", { className: "flex-1 min-w-[160px]", children: [e.jsx("p", { className: "m-0 text-base font-extrabold", children: "\uB098\uC758 \uB2E8\uC5B4\uC7A5" }), e.jsxs("p", { className: "mt-[3px] mb-0 text-[12.5px] opacity-85 tabular-nums", children: ["\uC219\uC81C\xB7\uC624\uB2F5\uC5D0\uC11C \uC800\uC7A5\uD55C \uB2E8\uC5B4 ", e.jsx("b", { children: p != null ? p : "\u2014" }), p == null ? "" : "\uAC1C"] })] }), e.jsx("span", { className: "flex-none px-[18px] py-[9px] rounded-[10px] bg-white text-[#5A47A8] text-[13px] font-extrabold", children: "\uC554\uAE30 \uC2DC\uC791" })] }), he.map((z) => e.jsxs("div", { children: [e.jsx("div", { className: "text-xs font-extrabold tracking-[.06em] text-faint mb-2", children: z.classroomName }), e.jsx("div", { className: "grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))] gap-3", children: z.books.map((H) => {
1192    const U = te++;
1193    return e.jsxs("button", { onClick: () =>
1193 s(H.id), className: `flex items-center gap-[13px] px-4 py-[15px] rounded-[14px] border text-left transition-shadow duration-150 ${H.is_highlighted ? "bg-[#FFFBEB] border-[#F3D9A4] hover:shadow-[0_4px_14px_rgba(217,119,6,.12)]" : "bg-white border-line hover:shadow-[0_4px_14px_rgba(16,24,40,.07)]"}`, children: [e.jsx("span", { className: "w-11 h-11 flex-none rounded-xl text-white flex items-center justify-center", style: { background: H.is_highlighted ? "linear-gradient(135deg, #F59E0B, #F97316)" : an[U % an.length] }, children: e.jsx(ir, { className: "w-[19px] h-[19px]", strokeWidth: 1.8 }) }), e.jsxs("div", { className: "min-w-0 flex-1", children: [e.jsxs("p", { className: "m-0 text-sm font-bold text-ink-2 flex items-center gap-[5px]", children: [e.jsx("span", { className: "truncate", children: H.title }), H.is_highlighted && e.jsx(aa, { className: "w-[13px] h-[13px] text-[#F59E0B] fill-[#F59E0B] flex-shrink-0" })] }), e.jsxs("p", { className: "mt-0.5 mb-0 text-xs text-faint tabular-nums", children: [H.entry_count, "\uAC1C \uB2E8\uC5B4"] })] }), e.jsx(qn, { className: "w-[15px] h-[15px] text-[#C9CBD6] flex-shrink-0", strokeWidth: 2 })] }, H.id);
1194  }) })] }, z.classroomId)), y.length === 0 && p === 0 && !E && !T && e.jsxs("div", { className: "text-center py-12", children: [e.jsx(yt, { className: "w-16 h-16 mx-auto text-ghost mb-4" }), e.jsx("h2", { className: "text-lg font-bold text-ink-3 mb-2", children: "\uB2E8\uC5B4\uC7A5\uC774 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4" }), e.jsx("p", { className: "text-muted text-sm", children: "\uC219\uC81C \uBB38\uC81C\uB97C \uD480\uBA74\uC11C \uB2E8\uC5B4\uB97C \uD0ED\uD574\uC11C \uC800\uC7A5\uD574\uBCF4\uC138\uC694" })] })] })] });
1195}
1196const an = ["linear-gradient(135deg, #8B5CF6, #7C3AED)", "linear-gradient(135deg, #10B981, #0D9488)", "linear-gradient(135deg, #3B82F6, #4F46E5)"];
1197function sn({ sources: n, selected: s, onChange: l, compact: d = false, avoidNativeButtons: f = false }) {
1198  const u = Math.min(typeof window < "u" ? window.innerHeight * 0.7 : 500, n.length * 40 + 110), { isOpen: h, toggle: i, close: x, buttonRef: m, dropdownRef: b, dropdownStyle: g } = Bn({ dropdownWidth: 256, dropdownHeight: u }), v = (o) => {
1199    l(s.includes(o) ? s.filter((p) => p !== o) : [...s, o]);
1200  }, j = () => l([]), C = s.length > 0, M = C ? s.length === 1 ? s[0] : `${s.length}\uAC1C \uC120\uD0DD` : d ? "\uC804\uCCB4" : "\uC804\uCCB4 \uCD9C\uCC98";
1201  return e.jsxs(e.Fragment, { children: [e.jsxs("div", { ref: m, role: "button", tabIndex: 0, onClick: (o) => {
1202    o.stopPropagation(), i();
1203  }, onKeyDown: (o) => {
1204    o.key !== "Enter" && o.key !== " " || (o.preventDefault(), i());
1205  }, className: `flex items-center gap-1 text-sm border rounded-lg ${d ? "px-2 py-1.5 max-w-[120px]" : "px-3 py-1.5 max-w-[200px]"} focus:outline-none focus:ring-2 focus:ring-primary/30 ${C ? "border-primary/30 bg-primary/5 text-primary" : "border-gray-200 text-gray-700 bg-white hover:bg-gray-50"}`, title: C ? s.join(", ") : "\uCD9C\uCC98 \uD544\uD130", children: [e.jsx("span", { className: "truncate flex-1 text-left", children: M }), e.jsx(sa, { className: `w-3.5 h-3.5 flex-shrink-0 transition-transform ${h ? "rotate-180" : ""}` })] }), h && fr.createPortal(e.jsxs("div", { ref: b, style: g, className: "w-64 max-w-[calc(100vw-1.5rem)] max-h-[70vh] flex flex-col bg-white border border-gray-200 rounded-lg shadow-lg", children: [e.jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 bg-white border-b border-gray-100", children: [e.jsxs("span", { className: "text-xs font-medium text-gray-500", children: ["\uCD9C\uCC98 \uC120\uD0DD (", s.length, "/", n.length, ")"] }), C && e.jsx(J, { avoidNativeButton: f, onClick: j, className: "text-xs text-primary hover:underline", children: "\uC804\uCCB4 \uD574\uC81C" })] }), e.jsx("ul", { className: "flex-1 overflow-y-auto py-1", children: n.map((o) => {
1206    const p = s.includes(o);
1207    return e.jsx("li", { children: e.jsxs("label", { className: "flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 cursor-pointer", children: [e.jsx("input", { type: "checkbox", checked: p, onChange: () => v(o), className: "w-4 h-4 rounded border-gray-300 text-primary focus:ring-primary/30" }), e.jsx("span", { className: "flex-1 truncate", title: o, children: o })] }) }, o);
1208  }) }), e.jsx("div", { className: "px-3 py-2 border-t border-gray-100 bg-gray-50 rounded-b-lg", children: e.jsx(J, { avoidNativeButton: f, onClick: x, className: "w-full py-2 text-sm font-medium text-white bg-primary hover:brightness-110 rounded-lg transition-all", children: "\uC644\uB8CC" }) })] }), document.body)] });
1209}
1210function Dn(n, s) {
1211  var l, d;
1212  const f = (d = (l = n == null ? void 0 : n.current_device) == null ? void 0 : l.drafts_by_entry) != null ? d : {}, u = {};
1213  for (const [h, i] of Object.entries(f)) if (i) {
1214    if (!Un(i)) {
1215      console.warn("[buildServerDraftsByEntry] dropping non-v2 draft for entry", h);
1216      continue;
1217    }
1218    u[h] = i;
1219  }
1220  return u;
1221}
1222function La({ onBack: n }) {
1223  var s, l, d, f, u;
1224  const h = Xt(), i = xr((t) => t.user), [x, m] = a.useState("newest"), [b, g] = a.useState("default"), [v, j] = a.useState([]), [C, M] = a.useState(false), [o, p] = a.useState(false), [y, S] = a.useState(false), [_, E] = a.useState(0), [T, P] = a.useState(false), [V, xe] = a.useState(/* @__PURE__ */ new Set()), O = a.useRef(/* @__PURE__ */ new Map()), { deviceId: Y, drawingEnabled: A, setDrawingEnabled: ge, handwritingTool: G, setHandwritingTool: ue, handwritingColor: F, setHandwritingColor: Ne, handwritingHandlesRef: R, activeHandwritingEntryId: D, setActiveHandwritingEntryId: K, handleHandwritingUndo: ee, handleHandwritingClear: he, largeCards: te, setLargeCards: z, nativeActiveRef: H, nativeUndoRef: U, nativeClearRef: oe } = Rn(), we = a.useRef({}), le = a.useRef(null), { currentError: L, setPersistenceStatus: Ee, statusByKey: Be } = bn("local");
1225  pn(A);
1226  const pe = kn({ targetType: "personal", academyId: (s = i == null ? void 0 : i.academy_id) != null ? s : 0, userId: (l = i == null ? void 0 : i.id) != null ? l : 0, deviceId: Y }), Ie = a.useCallback((t) => {
1227    const r = O.current.get(t);
1228    r && (clearTimeout(r), O.current.delete(t)), xe((c) => {
1229      const N = new Set(c);
1230      if (N.has(t)) return N.delete(t), N;
1231      N.add(t);
1232      const w = setTimeout(() => {
1233        xe((B) => {
1234          const $ = new Set(B);
1235          return $.delete(t), $;
1236        }), O.current.delete(t);
1237      }, 3e3);
1238      return O.current.set(t, w), N;
1239    });
1240  }, []);
1241  a.useEffect(() => () => {
1242    O.current.forEach((t) => clearTimeout(t));
1243  }, []), a.useEffect(() => {
1244    o || (O.current.forEach((t) => clearTimeout(t)), O.current.clear(), xe(/* @__PURE__ */ new Set()));
1245  }, [o]);
1246  const { data: me, isLoading: Le, isError: Ve, refetch: qe } = dt({ queryKey: [...Me], queryFn: mn, placeholderData: (t) => t }), se = gr(), _e = a.useMemo(() => {
1247    var t;
1248    return (t = me == null ? void 0 : me.items) != null ? t : [];
1249  }, [me == null ? void 0 : me.items]), re = a.useMemo(() => _e.map((t) => {
1250    var r;
1251    return { id: t.id, word: (r = t.base_form) != null ? r : t.word, meaning: t.meaning, memorization_status: Qt(t.memorization_status) };
1252  }), [_e]), et = a.useMemo(() => re.filter((t) => !wt(t.id)), [re]), Ye = a.useMemo(() => Fn(me), [me]), tt = !se && me === void 0, be = se && me === void 0 && Ve, fe = a.useMemo(() => hr(Hn(_e, v), x), [_e, v, x]), Fe = a.useMemo(() => fe.filter((t) => Qt(t.memorization_status) === b), [b, fe]), ae = a.useMemo(() => {
1253    if (!y) return Fe;
1254    const t = [...Fe];
1255    let r = _;
1256    for (let c = t.length - 1; c > 0; c--) {
1257      r = (r * 16807 + 11) % 2147483647;
1258      const N = r % (c + 1);
1259      [t[c], t[N]] = [t[N], t[c]];
1260    }
1261    return t;
1262  }, [Fe, y, _]), He = () => {
1263    y ? S(false) : (E(Date.now()), S(true));
1264  }, Re = a.useMemo(() => ae.filter((t) => t.ai_status !== "pending" && t.ai_status !== "failed").map((t) => {
1265    var r, c;
1266    return { word: (r = t.base_form) != null ? r : t.word, meaning: (c = t.meaning) != null ? c : "" };
1267  }), [ae]), { isSupported: rt, isPlaying: Ae, currentIndex: mt, toggleTTS: nt, stopTTS: at, enVoices: Qe, koVoices: ft, selectedEnVoice: st, selectedKoVoice: xt, setSelectedEnVoice: k, setSelectedKoVoice: I } = jr(Re), [W, Z] = a.useState(false), ye = a.useMemo(() => {
1268    const t = [];
1269    return ae.forEach((r, c) => {
1270      r.ai_status !== "pending" && r.ai_status !== "failed" && t.push(c);
1271    }), t;
1272  }, [ae]), ce = mt >= 0 && (d = ye[mt]) != null ? d : -1, $e = a.useRef(null);
1273  a.useEffect(() => {
1274    var t;
1275    ce >= 0 && ((t = $e.current) == null || t.scrollIntoView({ behavior: "smooth", block: "center" }));
1276  }, [ce]);
1277  const X = a.useCallback((t) => t.id, []), { selectedIds: q, setSelectedIds: ke, handleSelect: ne, handleSelectAll: ve, clearSelection: Xe } = fn(ae, X), Bt = a.useMemo(() => ae.map((t) => t.id), [ae]), Ce = Cn(Bt, q, ke), Ct = a.useCallback(() => {
1278    Ae && at(), A && ge(false);
1279  }, [A, Ae, ge, at]), Pe = async (t, r) => {
1280    try {
1281      await pe.moveEntries(t, r);
1282    } finally {
1283      Xe();
1284    }
1285  }, Gt = (t) => {
1286    Ct(), Xe(), g(t);
1287  }, Se = async (t) => {
1288    try {
1289      await Pe([...q], t), de.success(`${t === "default" ? "\uAE30\uBCF8" : "\uC554\uAE30\uB428"} \uD3F4\uB354\uB85C \uC774\uB3D9\uD588\uC2B5\uB2C8\uB2E4.`);
1290    } catch (r) {
1291      de.error(Ze(r, "\uB2E8\uC5B4\uB97C \uC774\uB3D9\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4."));
1292    } finally {
1293      vt("known");
1294    }
1295  }, gt = async () => {
1296    try {
1297      await Pe([...q], "known"), de.success("\uC544\uB294 \uB2E8\uC5B4\uB85C \uC774\uB3D9\uD588\uC2B5\uB2C8\uB2E4.");
1298    } catch (t) {
1299      de.error(Ze(t, "\uC544\uB294 \uB2E8\uC5B4\uB85C \uC774\uB3D9\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4."));
1300    } finally {
1301      vt("known");
1302    }
1303  }, Vt = a.useCallback(async (t) => {
1304    var r, c;
1305    t.length !== 0 && await Ht({ action: "remove", academyId: (r = i == null ? void 0 : i.academy_id) != null ? r : 0, userId: (c = i == null ? void 0 : i.id) != null ? c : 0, deviceId: Y, bookId: null, bookEntryIds: t.map((N) => -N) });
1306  }, [Y, i == null ? void 0 : i.academy_id, i == null ? void 0 : i.id]), ot = a.useCallback(async (t) => {
1307    var r, c;
1308    if (t.length === 0) return;
1309    const N = (r = i == null ? void 0 : i.academy_id) != null ? r : 0, w = (c = i == null ? void 0 : i.id) != null ? c : 0;
1310    let B;
1311    try {
1312      B = await ln(N, w);
1313    } catch {
1314      return;
1315    }
1316    const $ = new Set(t), ie = B.filter((Q) => Q.kind === "vocab_book_add").map((Q) => Q.payload).filter((Q) => Q.decision === "merge" && Q.mergeTargetEntryId != null && $.has(Q.mergeTargetEntryId)).map((Q) => Q.bookEntryId);
1317    ie.length !== 0 && await Ht({ action: "remove", academyId: N, userId: w, deviceId: Y, bookId: null, bookEntryIds: ie });
1318  }, [Y, i == null ? void 0 : i.academy_id, i == null ? void 0 : i.id]), ht = Dt({ networkMode: "offlineFirst", mutationFn: async (t) => wt(t) ? (await Vt([t]), { mode: "superseded", ids: [t] }) : sr(async () => {
1319    var r, c, N, w, B, $;
1320    return await ot([t]), Je() ? (await Oe.deleteEntry(t), await $t({ academyId: (B = i == null ? void 0 : i.academy_id) != null ? B : 0, userId: ($ = i == null ? void 0 : i.id) != null ? $ : 0, targetType: "personal", entryIds: [t] }).catch(() => {
1321    }), { mode: "sent", ids: [t] }) : (await _r({ academyId: (r = i == null ? void 0 : i.academy_id) != null ? r : 0, userId: (c = i == null ? void 0 : i.id) != null ? c : 0, deviceId: Y, entryIds: [t] }), await $t({ academyId: (N = i == null ? void 0 : i.academy_id) != null ? N : 0, userId: (w = i == null ? void 0 : i.id) != null ? w : 0, targetType: "personal", entryIds: [t] }).catch(() => {
1322    }), { mode: "queued", ids: [t] });
1323  }), onSuccess: (t) => {
1324    if (en(h, t.ids), t.mode === "sent") {
1325      h.invalidateQueries({ queryKey: ["vocabulary"] }), de.success("\uC0AD\uC81C\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
1326      return;
1327    }
1328    de.success(rn());
1329  }, onError: (t) => {
1330    de.error(Ze(t, "\uC0AD\uC81C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."));
1331  } }), Et = Dt({ networkMode: "offlineFirst", mutationFn: async (t) => {
1332    const r = t.filter(wt), c = Zr(t);
1333    return await Vt(r), c.length === 0 ? { calledServer: false, ids: t } : sr(async () => {
1334      var N, w, B, $, ie, Q;
1335      return await ot(c), Je() ? (await Oe.batchRemove(c), await $t({ academyId: (ie = i == null ? void 0 : i.academy_id) != null ? ie : 0, userId: (Q = i == null ? void 0 : i.id) != null ? Q : 0, targetType: "personal", entryIds: c }).catch(() => {
1336      }), { calledServer: true, ids: t }) : (await _r({ academyId: (N = i == null ? void 0 : i.academy_id) != null ? N : 0, userId: (w = i == null ? void 0 : i.id) != null ? w : 0, deviceId: Y, entryIds: c }), await $t({ academyId: (B = i == null ? void 0 : i.academy_id) != null ? B : 0, userId: ($ = i == null ? void 0 : i.id) != null ? $ : 0, targetType: "personal", entryIds: c }).catch(() => {
1337      }), { calledServer: false, ids: t });
1338    });
1339  }, onSuccess: (t) => {
1340    if (en(h, t.ids), Xe(), M(false), t.calledServer) {
1341      h.invalidateQueries({ queryKey: ["vocabulary"] }), de.success("\uC120\uD0DD \uD56D\uBAA9\uC744 \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4.");
1342      return;
1343    }
1344    de.success(rn());
1345  }, onError: (t) => {
1346    de.error(Ze(t, "\uC0AD\uC81C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."));
1347  } }), Ge = Dt({ mutationFn: async (t) => {
1348    const r = Zr(t);
1349    r.length !== 0 && await Oe.retryAi(r);
1350  }, onSuccess: () => {
1351    h.invalidateQueries({ queryKey: ["vocabulary"] }), de.success("\uBD84\uC11D\uC744 \uB2E4\uC2DC \uC2DC\uC791\uD588\uC2B5\uB2C8\uB2E4.");
1352  }, onError: (t) => {
1353    de.error(Ze(t, "\uC7AC\uC2DC\uB3C4\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."));
1354  } }), { data: It } = dt({ queryKey: ["vocabulary", "handwriting", "personal", Y], queryFn: () => Oe.fetchHandwriting("personal", Y), select: (t) => t.data, enabled: A, staleTime: 6e4 }), Zt = a.useMemo(() => Dn(It), [It, Y]), ze = a.useCallback((t) => {
1355    var r, c;
1356    return { academyId: (r = i == null ? void 0 : i.academy_id) != null ? r : 0, userId: (c = i == null ? void 0 : i.id) != null ? c : 0, scope: "vocab-personal", containerId: "personal", itemId: t };
1357  }, [i == null ? void 0 : i.academy_id, i == null ? void 0 : i.id]), Jt = a.useCallback((t, r) => {
1358    Ee(String(t), r);
1359  }, [Ee]), Mt = a.useCallback((t, r) => {
1360    we.current[t] = r, St(r ? `SERVER_SAVE_DISABLED key=personal:${t} strokes=${r.strokes.length} updatedAt=${r.updatedAt}` : `SERVER_SAVE_DISABLED key=personal:${t} cleared`);
1361  }, []), er = a.useMemo(() => {
1362    var t, r;
1363    return In("vocab-personal", (t = i == null ? void 0 : i.academy_id) != null ? t : 0, (r = i == null ? void 0 : i.id) != null ? r : 0, "personal");
1364  }, [i == null ? void 0 : i.academy_id, i == null ? void 0 : i.id]), { isNativeActive: it, undo: Rt, clear: At }
1364 = An({ entityId: String((f = i == null ? void 0 : i.id) != null ? f : 0), enabled: A, containerRef: le, tool: G, color: F, scopeName: "vocab-personal", nativeDrawingStorageKey: er, buildStorageScope: ze, recordDraft: Mt, setActiveEntryId: K, setPersistenceStatus: Ee });
1365  a.useEffect(() => {
1366    H.current = it, U.current = Rt, oe.current = At;
1367  }, [it, Rt, At, H, U, oe]);
1368  const tr = a.useCallback(() => {
1369    Object.entries(Be).forEach(([t, r]) => {
1370      var c, N;
1371      const w = Number(t), B = (c = we.current[w]) != null ? c : null;
1372      if (((N = r.local) == null ? void 0 : N.phase) !== "error") return;
1373      Ee(t, { target: "local", phase: "saving", retryable: false, updatedAt: B == null ? void 0 : B.updatedAt }), (B ? pr(ze(w), B) : br(ze(w))).then(() => {
1374        Ee(t, { target: "local", phase: "saved", retryable: false, updatedAt: B == null ? void 0 : B.updatedAt });
1375      }).catch((ie) => {
1376        const Q = ie instanceof jt ? ie : new jt("unknown_local_error");
1377        Ee(t, { target: "local", phase: "error", reasonCode: Q.reasonCode, message: yr(Q.reasonCode, "vocab-personal"), retryable: true, updatedAt: B == null ? void 0 : B.updatedAt });
1378      });
1379    });
1380  }, [ze, Be, Ee]), Ue = q.size, pt = ae.length > 0 && ae.every((t) => q.has(t.id)), rr = ae.filter((t) => q.has(t.id) && t.ai_status === "failed").map((t) => t.id), Te = En({ entries: re, actionableEntries: et, activeStatus: b, onStatusChange: Gt, onMoveEntries: Pe, onBeforeOpen: Ct, disabled: pe.isPending });
1381  return e.jsxs("div", { className: `px-2 pt-4 pb-20 md:p-6 md:pb-6 max-w-5xl mx-auto ${Ue > 0 ? "pb-56 sm:pb-36 md:pb-28" : ""}`, children: [e.jsx(xn, { message: (u = L == null ? void 0 : L.message) != null ? u : null, onRetry: tr, className: "mb-4" }), e.jsxs("div", { className: "mb-4", children: [e.jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2", children: [e.jsx(J, { avoidNativeButton: A, onClick: n, className: "p-2 hover:bg-gray-100 rounded-lg transition-colors flex-shrink-0", children: e.jsx(wr, { className: "w-5 h-5 text-gray-600" }) }), e.jsxs("h1", { className: "text-xl md:text-2xl font-bold text-gray-900 flex items-center gap-2 flex-none whitespace-nowrap", children: [e.jsx(yt, { className: "w-6 h-6 text-primary flex-shrink-0" }), "\uB098\uC758 \uB2E8\uC5B4\uC7A5"] }), me && e.jsxs("span", { className: "text-sm text-gray-500 flex-shrink-0 whitespace-nowrap", children: [fe.length, "\uAC1C \uB2E8\uC5B4"] }), e.jsxs("div", { className: "hidden md:flex md:flex-wrap items-center justify-end gap-1.5 min-w-0 ml-auto", children: [e.jsx("select", { value: x, onChange: (t) => m(t.target.value), className: "text-sm border border-gray-200 rounded-lg px-3 py-1.5 text-gray-700 focus:outline-none focus:ring-2 focus:ring-primary/30", children: nn.map((t) => e.jsx("option", { value: t.value, children: t.label }, t.value)) }), Ye.length > 0 && e.jsx(sn, { sources: Ye, selected: v, onChange: j, avoidNativeButtons: A }), rt && e.jsxs(e.Fragment, { children: [e.jsxs(J, { avoidNativeButton: A, onClick: nt, disabled: Re.length === 0, className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${Ae ? "bg-red-500 text-white border-red-500" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"} disabled:opacity-40`, children: [Ae ? e.jsx(Ot, { className: "w-3.5 h-3.5" }) : e.jsx(Nt, { className: "w-3.5 h-3.5" }), Ae ? "\uC911\uC9C0" : "\uC7AC\uC0DD"] }), e.jsx(J, { avoidNativeButton: A, onClick: () => Z((t) => !t), className: `flex items-center justify-center w-7 h-7 rounded-lg border transition-colors ${W ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-400 hover:text-gray-600 hover:bg-gray-50"}`, title: "\uC74C\uC131 \uC124\uC815", children: e.jsx(cn, { className: "w-3.5 h-3.5" }) })] }), e.jsxs(J, { avoidNativeButton: A, onClick: He, className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${y ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [e.jsx(Pt, { className: "w-3.5 h-3.5" }), y ? "\uC6D0\uB798\uC21C\uC11C" : "\uB79C\uB364"] }), e.jsxs(J, { avoidNativeButton: A, onClick: () => p((t) => !t), className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${o ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [o ? e.jsx(Kt, { className: "w-3.5 h-3.5" }) : e.jsx(qt, { className: "w-3.5 h-3.5" }), o ? "\uB73B \uBCF4\uAE30" : "\uB73B \uAC00\uB9AC\uAE30"] }), e.jsxs(J, { avoidNativeButton: A, onClick: () => P((t) => !t), className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${T ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [e.jsx(yn, { className: "w-3.5 h-3.5" }), T ? "1\uC5F4" : "2\uC5F4"] }), A && e.jsxs(J, { avoidNativeButton: A, onClick: () => z((t) => !t), className: "flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-all bg-white border-gray-200 text-gray-600 hover:bg-gray-50", children: [te ? e.jsx(Ut, { className: "w-3.5 h-3.5" }) : e.jsx(Wt, { className: "w-3.5 h-3.5" }), te ? "\uCE74\uB4DC \uC791\uAC8C" : "\uCE74\uB4DC \uD06C\uAC8C"] }), e.jsxs(J, { avoidNativeButton: A, onClick: () => {
1382    Ae && at(), ge((t) => !t);
1383  }, className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-all ${A ? "bg-primary text-white border-primary shadow-sm" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [e.jsx(dn, { className: "w-3.5 h-3.5" }), A ? "\uD544\uAE30 ON" : "\uD544\uAE30"] })] })] }), e.jsxs("div", { className: "flex md:hidden items-center gap-1.5 mt-2", children: [e.jsx("select", { value: x, onChange: (t) => m(t.target.value), className: "text-sm border border-gray-200 rounded-lg px-2 py-1.5 text-gray-700 focus:outline-none focus:ring-primary/30", children: nn.map((t) => e.jsx("option", { value: t.value, children: t.label }, t.value)) }), Ye.length > 0 && e.jsx(sn, { sources: Ye, selected: v, onChange: j, compact: true, avoidNativeButtons: A }), rt && e.jsx(J, { avoidNativeButton: A, onClick: nt, disabled: Re.length === 0, className: `flex items-center justify-center w-8 h-8 rounded-lg border transition-colors ${Ae ? "bg-red-500 text-white border-red-500" : "bg-white border-gray-200 text-gray-600"} disabled:opacity-40`, title: Ae ? "\uC7AC\uC0DD \uC911\uC9C0" : "\uB2E8\uC5B4 \uC7AC\uC0DD", children: Ae ? e.jsx(Ot, { className: "w-3.5 h-3.5" }) : e.jsx(Nt, { className: "w-3.5 h-3.5" }) }), e.jsx(J, { avoidNativeButton: A, onClick: He, className: `flex items-center justify-center w-8 h-8 rounded-lg border transition-colors ${y ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600"}`, title: y ? "\uC6D0\uB798\uC21C\uC11C" : "\uB79C\uB364", children: e.jsx(Pt, { className: "w-3.5 h-3.5" }) }), e.jsx(J, { avoidNativeButton: A, onClick: () => p((t) => !t), className: `flex items-center justify-center w-8 h-8 rounded-lg border transition-colors ${o ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600"}`, title: o ? "\uB73B \uBCF4\uAE30" : "\uB73B \uAC00\uB9AC\uAE30", children: o ? e.jsx(Kt, { className: "w-3.5 h-3.5" }) : e.jsx(qt, { className: "w-3.5 h-3.5" }) }), A && e.jsx(J, { avoidNativeButton: A, onClick: () => z((t) => !t), className: "flex items-center justify-center w-8 h-8 rounded-lg border transition-all bg-white border-gray-200 text-gray-600", title: te ? "\uCE74\uB4DC \uC791\uAC8C" : "\uCE74\uB4DC \uD06C\uAC8C", children: te ? e.jsx(Ut, { className: "w-3.5 h-3.5" }) : e.jsx(Wt, { className: "w-3.5 h-3.5" }) })] })] }), Te.folderTabs, Te.overlays, W && Qe.length > 0 && e.jsx(Mn, { enVoices: Qe, koVoices: ft, selectedEnVoice: st, selectedKoVoice: xt, onEnVoiceChange: k, onKoVoiceChange: I, onClose: () => Z(false), avoidNativeButtons: A }), A && e.jsx(gn, { tool: G, onToolChange: ue, penColor: F, onPenColorChange: Ne, onUndo: ee, onClear: he, canUndo: D != null, canClear: true }), Ue > 0 && e.jsxs("div", { className: "fixed bottom-0 left-0 right-0 z-50 flex flex-wrap items-center justify-center gap-2 border-t border-gray-200 bg-white pb-[max(0.75rem,env(safe-area-inset-bottom))] pl-[max(1rem,env(safe-area-inset-left))] pr-[max(1rem,env(safe-area-inset-right))] pt-3 shadow-[0_-4px_12px_rgba(0,0,0,0.08)]", children: [e.jsxs("span", { className: "text-sm font-semibold text-primary", children: [Ue, "\uAC1C \uC120\uD0DD\uB428"] }), b === "known" && e.jsxs(e.Fragment, { children: [e.jsx("button", { onClick: () => {
1384    Se("default");
1385  }, disabled: pe.isPending, className: "flex items-center gap-1.5 text-sm px-3 py-1.5 rounded-lg border border-gray-300 text-gray-700 hover:bg-gray-50 transition-colors disabled:opacity-50", children: "\uAE30\uBCF8\uC73C\uB85C" }), e.jsx("button", { onClick: () => {
1386    Se("memorized");
1387  }, disabled: pe.isPending, className: "flex items-center gap-1.5 text-sm px-3 py-1.5 rounded-lg border border-primary/30 bg-primary/5 text-primary hover:bg-primary/10 transition-colors disabled:opacity-50", children: "\uC554\uAE30\uB428\uC73C\uB85C" })] }), b !== "known" && e.jsxs("button", { onClick: () => {
1388    gt();
1389  }, disabled: pe.isPending, className: "flex items-center gap-1.5 rounded-lg border border-primary/30 bg-primary/5 px-3 py-1.5 text-sm text-primary transition-colors hover:bg-primary/10 disabled:opacity-50", children: [e.jsx(or, { className: "h-3.5 w-3.5" }), "\uC544\uB294 \uB2E8\uC5B4\uB85C \uC774\uB3D9"] }), rr.length > 0 && e.jsxs("button", { onClick: () => Ge.mutate(rr), disabled: Ge.isPending || !se, title: se ? void 0 : tn, className: "flex items-center gap-1.5 text-sm px-3 py-1.5 rounded-lg border border-amber-300 text-amber-700 hover:bg-amber-50 transition-colors disabled:opacity-50", children: [e.jsx(Ir, { className: "w-3.5 h-3.5" }), "\uC7AC\uBD84\uC11D"] }), e.jsxs("button", { onClick: () => M(true), className: "flex items-center gap-1.5 text-sm px-3 py-1.5 rounded-lg text-red-600 bg-red-50 border border-red-200 hover:bg-red-100 transition-colors", children: [e.jsx(Mr, { className: "w-3.5 h-3.5" }), "\uC0AD\uC81C"] }), e.jsxs("button", { onClick: () => {
1390    Xe(), vt(b);
1391  }, className: "flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700 transition-colors", children: [e.jsx(_t, { className: "w-4 h-4" }), "\uD574\uC81C"] })] }), C && e.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40", children: e.jsxs("div", { className: "bg-white rounded-2xl p-6 shadow-xl max-w-sm w-full mx-4", children: [e.jsx("h3", { className: "font-semibold text-gray-900 mb-2", children: "\uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?" }), e.jsxs("p", { className: "text-sm text-gray-500 mb-5", children: [Ue, "\uAC1C\uC758 \uB2E8\uC5B4\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4. \uC774 \uC791\uC5C5\uC740 \uB418\uB3CC\uB9B4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."] }), e.jsxs("div", { className: "flex gap-2 justify-end", children: [e.jsx("button", { onClick: () => M(false), className: "px-4 py-2 rounded-lg border border-gray-200 text-sm text-gray-600 hover:bg-gray-50", children: "\uCDE8\uC18C" }), e.jsxs("button", { onClick: () => Et.mutate(Array.from(q)), disabled: Et.isPending, className: "px-4 py-2 rounded-lg bg-red-500 text-white text-sm hover:bg-red-600 disabled:opacity-50 flex items-center gap-1.5", children: [Et.isPending && e.jsx(We, { className: "w-3.5 h-3.5 animate-spin" }), "\uC0AD\uC81C"] })] })] }) }), tt ? e.jsx(vr, { message: "\uC624\uD504\uB77C\uC778 \uC0C1\uD0DC\uC774\uBA70 \uC800\uC7A5\uD55C \uB2E8\uC5B4\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." }) : Le ? e.jsx("div", { className: "flex items-center justify-center h-48", children: e.jsx(We, { className: "w-8 h-8 animate-spin text-primary" }) }) : be ? e.jsxs("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [e.jsx(Ke, { className: "mb-4 h-12 w-12 text-amber-500" }), e.jsx("h2", { className: "mb-2 text-lg font-semibold text-gray-700", children: "\uB2E8\uC5B4\uC7A5\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4" }), e.jsx("p", { className: "mb-5 text-sm text-gray-500", children: "\uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694." }), e.jsx("button", { type: "button", onClick: () => {
1392    qe();
1393  }, className: "rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", children: "\uB2E4\uC2DC \uC2DC\uB3C4" })] }) : _e.length === 0 ? e.jsxs("div", { className: "text-center py-16", children: [e.jsx(yt, { className: "w-16 h-16 mx-auto text-gray-300 mb-4" }), e.jsx("h2", { className: "text-xl font-semibold text-gray-700 mb-2", children: "\uB2E8\uC5B4\uC7A5\uC774 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4" }), e.jsx("p", { className: "text-gray-500", children: "\uC219\uC81C \uBB38\uC81C\uB97C \uD480\uBA74\uC11C \uB2E8\uC5B4\uB97C \uD0ED\uD574\uC11C \uC800\uC7A5\uD574\uBCF4\uC138\uC694" })] }) : fe.length === 0 ? e.jsxs("div", { className: "text-center py-16", children: [e.jsx(yt, { className: "w-16 h-16 mx-auto text-gray-300 mb-4" }), e.jsx("h2", { className: "text-xl font-semibold text-gray-700 mb-2", children: "\uD544\uD130\uC640 \uC77C\uCE58\uD558\uB294 \uB2E8\uC5B4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" }), e.jsx("p", { className: "text-gray-500 mb-4", children: "\uC120\uD0DD\uD55C \uCD9C\uCC98\uC5D0 \uC800\uC7A5\uB41C \uB2E8\uC5B4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" }), e.jsx("button", { onClick: () => j([]), className: "px-4 py-2 rounded-lg border border-gray-200 text-sm text-gray-700 hover:bg-gray-50", children: "\uD544\uD130 \uD574\uC81C" })] }) : ae.length === 0 ? e.jsxs("div", { className: "text-center py-14 rounded-xl border border-dashed border-gray-200 bg-gray-50/60", children: [e.jsx(yt, { className: "w-12 h-12 mx-auto text-gray-300 mb-3" }), e.jsxs("h2", { className: "text-base font-semibold text-gray-700", children: [ut[b], " \uD3F4\uB354\uC5D0 \uB2E8\uC5B4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4"] }), e.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "\uB2E4\uB978 \uD3F4\uB354\uC5D0\uC11C \uB2E8\uC5B4\uB97C \uC774\uB3D9\uD574 \uBCF4\uC138\uC694." })] }) : A ? e.jsxs(e.Fragment, { children: [Te.folderActions && e.jsx("div", { className: "py-1.5", children: Te.folderActions }), e.jsx("div", { ref: le, className: T ? "flex flex-col gap-0.5 md:grid md:grid-cols-2 md:grid-flow-col md:gap-x-2" : "space-y-0.5", style: T ? { gridTemplateRows: `repeat(${Math.ceil(ae.length / 2)}, auto)` } : void 0, children: ae.map((t, r) => {
1394    var c, N;
1395    const w = D === t.id;
1396    return e.jsx(Tn, { entryId: t.id, index: r, active: w, largeCards: te, isNativeActive: it, onActivate: () => K(t.id), renderOverlay: () => {
1397      var B;
1398      return e.jsx(hn, { ref: ($) => {
1399        $ ? R.current.set(t.id, $) : R.current.delete(t.id);
1400      }, questionId: t.id, sheetId: 0, enabled: A, disableNative: true, deviceId: Y, serverDraft: Zt[String(t.id)], onDraftChange: Mt, syncHydratedDraft: false, touchActionMode: "pan-y", debugPanelActive: w, storageKeyPrefix: "vocab-p-", storageScope: ze(t.id), onPersistenceStatusChange: ($) => Jt(t.id, $), tool: G, onToolChange: ue, penColor: F, onPenColorChange: Ne, hideToolbar: true, onActivate: () =>
1400 K(t.id), entityType: "vocabulary", entityId: String((B = i == null ? void 0 : i.id) != null ? B : 0), subEntityId: String(t.id), tapZoneSelector: "button[data-handwriting-tap-through]" });
1401    }, children: e.jsxs("div", { className: "absolute inset-0 z-[11] pointer-events-none flex items-center gap-3 px-4", children: [e.jsx("input", { type: "checkbox", checked: q.has(t.id), onChange: (B) => ne(r, B.nativeEvent.shiftKey), className: "w-5 h-5 md:w-4 md:h-4 rounded border-gray-300 text-primary focus:ring-primary/30 pointer-events-auto" }), e.jsx("span", { className: "font-semibold text-gray-900 text-base", children: (c = t.base_form) != null ? c : t.word }), t.base_form && t.base_form !== t.word && e.jsxs("span", { className: "text-sm text-gray-400", children: ["(", t.word, ")"] }), e.jsx("button", { type: "button", "data-handwriting-tap-through": true, onClick: o ? (B) => {
1402      B.stopPropagation(), Ie(t.id);
1403    } : void 0, className: `text-base ml-auto bg-transparent border-0 p-0 whitespace-pre-line text-right ${o ? "pointer-events-auto cursor-pointer select-none active:bg-gray-100 rounded px-1" : "pointer-events-none"} ${o && !V.has(t.id) ? "text-gray-400" : "text-gray-600"}`, children: !o || V.has(t.id) ? (N = t.meaning) != null ? N : "-" : "\u2022\u2022\u2022\u2022" })] }) }, t.id);
1404  }) })] }) : T ? e.jsxs(e.Fragment, { children: [e.jsxs("div", { className: "hidden md:block bg-white rounded-xl border border-gray-200 overflow-hidden", children: [Te.folderActions && e.jsx("div", { className: "flex items-center border-b border-gray-100 bg-gray-50/60 px-2 py-2.5", children: Te.folderActions }), e.jsx("div", { ...Ce, className: "grid grid-cols-2 grid-flow-col py-2", style: { ...Ce.style, gridTemplateRows: `repeat(${Math.ceil(ae.length / 2)}, auto)` }, children: ae.map((t, r) => {
1405    var c, N;
1406    return e.jsxs("div", { "data-vocab-select-index": r, ref: ce === r ? (w) => {
1407      $e.current = w;
1408    } : void 0, onClick: () => ne(r, false), className: `flex items-center gap-2 px-4 py-1.5 cursor-pointer transition-colors ${r < Math.ceil(ae.length / 2) ? "border-r border-gray-100" : ""} ${ce === r ? "bg-yellow-50" : q.has(t.id) ? "bg-primary/5" : "hover:bg-gray-50/50"}`, children: [e.jsx("span", { "data-vocab-drag-handle": true, onClick: (w) => {
1409      w.stopPropagation(), ne(r, false);
1410    }, className: "-m-3 flex flex-shrink-0 items-center justify-center p-3", style: { touchAction: "none" }, children: e.jsx("input", { type: "checkbox", checked: q.has(t.id), onChange: (w) => {
1411      w.stopPropagation(), ne(r, w.nativeEvent.shiftKey);
1412    }, onClick: (w) => w.stopPropagation(), className: "rounded border-gray-300 text-primary focus:ring-primary/30" }) }), e.jsxs("span", { className: "text-xs text-gray-400 w-6 text-right flex-shrink-0", children: [r + 1, "."] }), e.jsx("span", { className: "font-medium text-gray-900 truncate", children: (c = t.base_form) != null ? c : t.word }), e.jsx("span", { onClick: o && t.ai_status !== "pending" && t.ai_status !== "failed" ? (w) => {
1413      w.stopPropagation(), Ie(t.id);
1414    } : void 0, className: `text-sm ml-auto whitespace-pre-line text-right ${o ? "cursor-pointer select-none" : ""} ${o && !V.has(t.id) && t.ai_status !== "pending" && t.ai_status !== "failed" ? "text-gray-400" : "text-gray-600"}`, children: t.ai_status === "pending" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-amber-600", children: [e.jsx(We, { className: "w-3 h-3 animate-spin" }), "\uBD84\uC11D\uC911"] }) : t.ai_status === "failed" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-red-600", children: [e.jsx(Ke, { className: "w-3 h-3" }), "\uC2E4\uD328"] }) : !o || V.has(t.id) ? (N = t.meaning) != null ? N : "-" : "\u2022\u2022\u2022\u2022" })] }, t.id);
1415  }) })] }), e.jsxs("div", { ...Ce, "data-testid": "personal-vocabulary-selection-surface-mobile", className: "md:hidden bg-white rounded-xl border border-gray-200 overflow-hidden", children: [e.jsxs("div", { className: "flex items-center gap-1 px-2 py-2.5 border-b border-gray-100 bg-gray-50/60", children: [e.jsx("input", { type: "checkbox", checked: pt, onChange: (t) => ve(t.target.checked), className: "w-5 h-5 rounded border-gray-300 text-primary focus:ring-primary/30" }), e.jsx("span", { className: "text-sm text-gray-500", children: "\uC804\uCCB4 \uC120\uD0DD" }), Te.folderActions] }), ae.map((t, r) => {
1416    var c, N;
1417    return e.jsxs("div", { "data-vocab-select-index": r, ref: ce === r ? (w) => {
1418      $e.current = w;
1419    } : void 0, onClick: () => ne(r, false), className: `flex items-center gap-0.5 px-2 py-2.5 border-b border-gray-50 last:border-b-0 transition-colors cursor-pointer active:bg-gray-100 ${ce === r ? "bg-yellow-50 ring-1 ring-inset ring-yellow-300" : q.has(t.id) ? "bg-primary/5" : ""}`, children: [e.jsx("span", { "data-vocab-drag-handle": true, className: "-m-2.5 flex flex-shrink-0 items-center justify-center p-2.5", style: { touchAction: "
1419none" }, children: e.jsx("input", { type: "checkbox", checked: q.has(t.id), readOnly: true, className: "w-5 h-5 rounded border-gray-300 text-primary focus:ring-primary/30 pointer-events-none" }) }), e.jsx("span", { className: "text-xs text-gray-400 w-4 text-center flex-shrink-0", children: r + 1 }), e.jsx("span", { className: "font-medium text-gray-900 flex-1 min-w-0 line-clamp-2 ml-0.5", children: (c = t.base_form) != null ? c : t.word }), e.jsx("span", { onClick: o && t.ai_status !== "pending" && t.ai_status !== "failed" ? (w) => {
1420      w.stopPropagation(), Ie(t.id);
1421    } : void 0, className: `text-sm flex-shrink-0 whitespace-pre-line text-right ${o && t.ai_status !== "pending" && t.ai_status !== "failed" ? "w-[42%] py-3 -my-2.5 pl-2 -mr-1 pr-1 cursor-pointer select-none active:bg-gray-100 rounded-md" : "max-w-[40%]"} ${o && !V.has(t.id) && t.ai_status !== "pending" && t.ai_status !== "failed" ? "text-gray-400" : "text-gray-600"}`, children: t.ai_status === "pending" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-amber-600", children: [e.jsx(We, { className: "w-3 h-3 animate-spin" }), "\uBD84\uC11D\uC911"] }) : t.ai_status === "failed" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-red-600", children: [e.jsx(Ke, { className: "w-3 h-3" }), "\uC2E4\uD328"] }) : !o || V.has(t.id) ? (N = t.meaning) != null ? N : "-" : "\u2022\u2022\u2022\u2022" })] }, t.id);
1422  })] })] }) : e.jsxs(e.Fragment, { children: [e.jsxs("div", { className: "hidden md:block bg-white rounded-xl border border-gray-200 overflow-hidden", children: [Te.folderActions && e.jsx("div", { className: "flex items-center border-b border-gray-100 bg-gray-50/60 px-2 py-2.5", children: Te.folderActions }), e.jsxs("table", { className: "w-full", children: [e.jsx("thead", { children: e.jsxs("tr", { className: "border-b border-gray-100 bg-gray-50/60", children: [e.jsx("th", { className: "w-10 px-4 py-3", children: e.jsx("input", { type: "checkbox", checked: pt, onChange: (t) => ve(t.target.checked), className: "rounded border-gray-300 text-primary focus:ring-primary/30" }) }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-32", children: "\uC6D0\uD615" }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-40", children: "\uD55C\uAE00 \uB73B" }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider", children: "\uC608\uBB38" }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-36", children: "\uCD9C\uCC98" }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-28", children: "\uB0A0\uC9DC" }), e.jsx("th", { className: "w-10 px-4 py-3" })] }) }), e.jsx("tbody", { ...Ce, children: ae.map((t, r) => {
1423    var c, N, w, B, $, ie;
1424    return e.jsxs("tr", { "data-vocab-select-index": r, className: `border-b border-gray-50 last:border-b-0 hover:bg-gray-50/50 transition-colors ${ce === r ? "bg-yellow-50 ring-1 ring-inset ring-yellow-300" : q.has(t.id) ? "bg-primary/5" : ""}`, children: [e.jsx("td", { className: "px-4 py-3", children: e.jsx("span", { "data-vocab-drag-handle": true, onClick: (Q) => {
1425      Q.stopPropagation(), ne(r, false);
1426    }, className: "-m-3 inline-flex items-center justify-center p-3", style: { touchAction: "none" }, children: e.jsx("input", { type: "checkbox", checked: q.has(t.id), onChange: (Q) => ne(r, Q.nativeEvent.shiftKey), onClick: (Q) => Q.stopPropagation(), className: "rounded border-gray-300 text-primary focus:ring-primary/30" }) }) }), e.jsxs("td", { onClick: () => ne(r, false), className: "px-4 py-3 cursor-pointer", children: [e.jsx("div", { className: "font-medium text-gray-900", children: (c = t.base_form) != null ? c : t.word }), t.base_form && t.base_form !== t.word && e.jsx("div", { className: "text-xs text-gray-400 mt-0.5", children: t.word })] }), e.jsx("td", { onClick: o && t.ai_status !== "pending" && t.ai_status !== "failed" ? () => Ie(t.id) : void 0, className: `px-4 py-3 ${o && t.ai_status !== "pending" && t.ai_status !== "failed" ? "curs
1426or-pointer select-none" : ""}`, children: t.ai_status === "pending" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-amber-600 bg-amber-50 px-2 py-0.5 rounded-full", children: [e.jsx(We, { className: "w-3 h-3 animate-spin" }), "\uBD84\uC11D\uC911"] }) : t.ai_status === "failed" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-red-600 bg-red-50 px-2 py-0.5 rounded-full", children: [e.jsx(Ke, { className: "w-3 h-3" }), "\uBD84\uC11D \uC2E4\uD328"] }) : e.jsx("span", { className: `text-sm whitespace-pre-line ${o && !V.has(t.id) ? "text-gray-400" : "text-gray-700"}`, children: !o || V.has(t.id) ? (N = t.meaning) != null ? N : "-" : "\u2022\u2022\u2022\u2022" }) }), e.jsx("td", { className: "px-4 py-3", children: e.jsx("p", { className: "text-sm text-gray-600 whitespace-pre-line", children: t.sentence || "-" }) }), e.jsx("td", { className: "px-4 py-3", children: e.jsx("span", { className: "text-xs text-gray-400 truncate block max-w-[130px]", title: (B = (w = t.source_label) != null ? w : t.homework_title) != null ? B : void 0, children: (ie = ($ = t.source_label) != null ? $ : t.homework_title) != null ? ie : "-" }) }), e.jsx("td", { className: "px-4 py-3", children: e.jsx("span", { className: "text-xs text-gray-400", children: new Date(t.created_at).toLocaleDateString("ko-KR", { timeZone: "Asia/Seoul", month: "2-digit", day: "2-digit" }) }) }), e.jsx("td", { className: "px-4 py-3", children: e.jsxs("div", { className: "flex items-center gap-1", children: [t.ai_status === "failed" && e.jsx("button", { onClick: () => Ge.mutate([t.id]), disabled: Ge.isPending || !se, title: se ? "\uB2E4\uC2DC \uBD84\uC11D" : tn, className: "w-7 h-7 flex items-center justify-center rounded-lg text-amber-500 hover:bg-amber-50 transition-colors disabled:opacity-50", children: e.jsx(Ir, { className: "w-3.5 h-3.5" }) }), e.jsx("button", { onClick: () => ht.mutate(t.id), disabled: ht.isPending, title: "\uC0AD\uC81C", className: "w-7 h-7 flex items-center justify-center rounded-lg text-gray-400 hover:text-red-500 hover:bg-red-50 transition-colors disabled:opacity-50", children: e.jsx(Mr, { className: "w-3.5 h-3.5" }) })] }) })] }, t.id);
1427  }) })] })] }), e.jsxs("div", { ...Ce, "data-testid": "personal-vocabulary-selection-surface-mobile", className: "md:hidden bg-white rounded-xl border border-gray-200 overflow-hidden", children: [e.jsxs("div", { className: "flex items-center gap-1 px-2 py-2.5 border-b border-gray-100 bg-gray-50/60", children: [e.jsx("input", { type: "checkbox", checked: pt, onChange: (t) => ve(t.target.checked), className: "w-5 h-5 rounded border-gray-300 text-primary focus:ring-primary/30" }), e.jsx("span", { className: "text-sm text-gray-500", children: "\uC804\uCCB4 \uC120\uD0DD" }), Te.folderActions] }), ae.map((t, r) => {
1428    var c, N;
1429    return e.jsxs("div", { "data-vocab-select-index": r, ref: ce === r ? (w) => {
1430      $e.current = w;
1431    } : void 0, onClick: () => ne(r, false), className: `flex items-center gap-0.5 px-2 py-2.5 border-b border-gray-50 last:border-b-0 transition-colors cursor-pointer active:bg-gray-100 ${ce === r ? "bg-yellow-50 ring-1 ring-inset ring-yellow-300" : q.has(t.id) ? "bg-primary/5" : ""}`, children: [e.jsx("span", { "data-vocab-drag-handle": true, className: "-m-2.5 flex flex-shrink-0 items-center justify-center p-2.5", style: { touchAction: "none" }, children: e.jsx("input", { type: "checkbox", checked: q.has(t.id), readOnly: true, className: "w-5 h-5 rounded border-gray-300 text-primary focus:ring-primary/30 pointer-events-none" }) }), e.jsx("span", { className: "text-xs text-gray-400 w-4 text-center flex-shrink-0", children: r + 1 }), e.jsx("span", { className: "font-medium text-gray-900 flex-1 min-w-0 line-clamp-2 ml-0.5", children: (c = t.base_form) != null ? c : t.word }), e.jsx("span", { onClick: o && t.ai_status !== "pending" && t.ai_status !== "failed" ? (w) => {
1432      w.stopPropagation(), Ie(t.id);
1433    } : void 0, className: `text-sm flex-shrink-0 whitespace-pre-line text-right ${o && t.ai_status !== "pending" && t.ai_status !== "failed" ? "w-[42%] py-3 -my-2.5 pl-2 -mr-1 pr-1 cursor-pointer select-none active:bg-gray-100 rounded-md" : "max-w-[40%]"} ${o && !V.has(t.id) && t.ai_status !== "pending" && t.ai_status !== "failed" ? "text-gray-400" : "text-gray-600"}`, children: t.ai_status === "pending" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-amber-600", children: [e.jsx(We, { className: "w-3 h-3 animate-spin" }), "\uBD84\uC11D\uC911"] }) : t.ai_status === "failed" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-red-600", children: [e.jsx(Ke, { className: "w-3 h-3" }), "\uC2E4\uD328"] }) : !o || V.has(t.id) ? (N = t.meaning) != null ? N : "-" : "\u2022\u2022\u2022\u2022" })] }, t.id);
1434  })] })] })] });
1435}
1436function Fa({ bookId: n, onBack: s }) {
1437  var l, d, f, u, h;
1438  const i = Xt(), x = xr((r) => r.user), [m, b] = a.useState("default"), { data: g, isLoading: v, isError: j, refetch: C } = dt({ queryKey: ["vocabulary", "book-entries", n], queryFn: () => Oe.getBookEntries(n), select: (r) => r.data, staleTime: 6e4 }), M = gr(), o = g == null ? void 0 : g.book, p = a.useMemo(() => {
1439    var r;
1440    return (r = g == null ? void 0 : g.entries) != null ? r : [];
1441  }, [g == null ? void 0 : g.entries]), y = !M && g === void 0, S = M && g === void 0 && j, [_, E] = a.useState(false), [T, P] = a.useState(false), [V, xe] = a.useState(0), [O, Y] = a.useState(false), [A, ge] = a.useState(/* @__PURE__ */ new Set()), G = a.useRef(/* @__PURE__ */ new Map()), { deviceId: ue, drawingEnabled: F, setDrawingEnabled: Ne, handwritingTool: R, setHandwritingTool: D, handwritingColor: K, setHandwritingColor: ee, handwritingHandlesRef: he, activeHandwritingEntryId: te, setActiveHandwritingEntryId: z, handleHandwritingUndo: H, handleHandwritingClear: U, largeC
1441ards: oe, setLargeCards: we, nativeActiveRef: le, nativeUndoRef: L, nativeClearRef: Ee } = Rn(), Be = a.useRef({}), pe = a.useRef(null), { currentError: Ie, setPersistenceStatus: me, statusByKey: Le } = bn("local");
1442  pn(F);
1443  const Ve = kn({ targetType: "book", bookId: n, academyId: (l = x == null ? void 0 : x.academy_id) != null ? l : 0, userId: (d = x == null ? void 0 : x.id) != null ? d : 0, deviceId: ue }), qe = a.useCallback((r) => {
1444    const c = G.current.get(r);
1445    c && (clearTimeout(c), G.current.delete(r)), ge((N) => {
1446      const w = new Set(N);
1447      if (w.has(r)) return w.delete(r), w;
1448      w.add(r);
1449      const B = setTimeout(() => {
1450        ge(($) => {
1451          const ie = new Set($);
1452          return ie.delete(r), ie;
1453        }), G.current.delete(r);
1454      }, 3e3);
1455      return G.current.set(r, B), w;
1456    });
1457  }, []);
1458  a.useEffect(() => () => {
1459    G.current.forEach((r) => clearTimeout(r));
1460  }, []), a.useEffect(() => {
1461    O || (G.current.forEach((r) => clearTimeout(r)), G.current.clear(), ge(/* @__PURE__ */ new Set()));
1462  }, [O]);
1463  const se = a.useMemo(() => p.map((r) => ({ id: r.id, word: r.word, meaning: r.meaning, memorization_status: Qt(r.memorization_status) })), [p]), _e = a.useMemo(() => p.filter((r) => Qt(r.memorization_status) === m), [m, p]), re = a.useMemo(() => {
1464    if (!T) return _e;
1465    const r = [..._e];
1466    let c = V;
1467    for (let N = r.length - 1; N > 0; N--) {
1468      c = (c * 16807 + 11) % 2147483647;
1469      const w = c % (N + 1);
1470      [r[N], r[w]] = [r[w], r[N]];
1471    }
1472    return r;
1473  }, [_e, T, V]), et = () => {
1474    T ? P(false) : (xe(Date.now()), P(true));
1475  }, Ye = a.useMemo(() => re.map((r) => ({ id: r.id, source: "book", word: r.word, meaning: r.meaning })), [re]), { isSupported: tt, isPlaying: be, currentIndex: fe, toggleTTS: Fe, stopTTS: ae, playItem: He, enVoices: Re, koVoices: rt, selectedEnVoice: Ae, selectedKoVoice: mt, setSelectedEnVoice: nt, setSelectedKoVoice: at } = jr(Ye), [Qe, ft] = a.useState(false), st = a.useRef(null), xt = a.useRef(null);
1476  a.useEffect(() => {
1477    var r, c;
1478    fe >= 0 && ((r = st.current) == null || r.scrollIntoView({ behavior: "smooth", block: "center" }), (c = xt.current) == null || c.scrollIntoView({ behavior: "smooth", block: "center" }));
1479  }, [fe]);
1480  const k = a.useCallback((r) => r.id, []), { selectedIds: I, setSelectedIds: W, handleSelect: Z, handleSelectAll: ye, clearSelection: ce } = fn(re, k), $e = a.useMemo(() => re.map((r) => r.id), [re]), X = Cn($e, I, W), q = a.useCallback(() => {
1481    be && ae(), F && Ne(false);
1482  }, [F, be, Ne, ae]), ke = async (r, c) => {
1483    try {
1484      await Ve.moveEntries(r, c);
1485    } finally {
1486      ce();
1487    }
1488  }, ne = (r) => {
1489    q(), ce(), b(r);
1490  }, ve = async (r) => {
1491    try {
1492      await ke([...I], r), de.success(`${r === "default" ? "\uAE30\uBCF8" : "\uC554\uAE30\uB428"} \uD3F4\uB354\uB85C \uC774\uB3D9\uD588\uC2B5\uB2C8\uB2E4.`);
1493    } catch (c) {
1494      de.error(Ze(c, "\uB2E8\uC5B4\uB97C \uC774\uB3D9\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4."));
1495    } finally {
1496      vt("known");
1497    }
1498  }, Xe = async () => {
1499    try {
1500      await ke([...I], "known"), de.success("\uC544\uB294 \uB2E8\uC5B4\uB85C \uC774\uB3D9\uD588\uC2B5\uB2C8\uB2E4.");
1501    } catch (r) {
1502      de.error(Ze(r, "\uC544\uB294 \uB2E8\uC5B4\uB85C \uC774\uB3D9\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4."));
1503    } finally {
1504      vt("known");
1505    }
1506  }, { data: Bt } = dt({ queryKey: Me, queryFn: mn, enabled: false }), Ce = (f = Bt == null ? void 0 : Bt.items) != null ? f : null, Ct = a.useMemo(() => {
1507    const r = /* @__PURE__ */ new Map();
1508    for (const c of p) r.set(c.id, Ra(c, Ce));
1509    return r;
1510  }, [p, Ce]), Pe = a.useCallback((r) => {
1511    var c;
1512    return (c = Ct.get(r.id)) != null ? c : "none";
1513  }, [Ct]), Gt = a.useCallback((r, c, N) => {
1514    var w, B, $;
1515    const ie = new Set(r), Q = (B = (w = i.getQueryData(["vocabulary", "book-entries", n])) == null ? void 0 : w.data) == null ? void 0 : B.entries, lt = Q ? Q.filter((je) => ie.has(je.id) && (c ? Pe(je) !== "saved" : Pe(je) !== "none")) : null, Nr = lt ? Va(i, lt, c, ($ = o == null ? void 0 : o.title) != null ? $ : null, N) : null, kr = Nr != null ? Nr : (lt ? lt.length : r.length) * (c ? 1 : -1);
1516    kr !== 0 && i.setQueryData(["vocabulary", "count"], (je) => {
1517      var Tt;
1518      return typeof ((Tt = je == null ? void 0 : je.data) == null ? void 0 : Tt.total) != "number" ? je : { ...je, data: { ...je.data, total: Math.max(0, je.data.total + kr) } };
1519    }), i.setQueryData(["vocabulary", "book-entries", n], (je) => {
1520      var Tt;
1521      return (Tt = je == null ? void 0 : je.data) != null && Tt.entries ? { ...je, data: { ...je.data, entries: je.data.entries.map((nr) => ie.has(nr.id) ? { ...nr, in_my_vocab: c, membership: c ? "saved" : "none" } : nr) } } : je;
1522    });
1523  }, [o == null ? void 0 : o.title, n, Pe, i]), [Se, gt] = a.useState(null), Vt = (r) => {
1524    var c;
1525    const N = (c = r.needs_decision) != null ? c : [];
1526    if (N.length === 0 || !Ce) return 0;
1527    const w = [];
1528    for (const B of N) {
1529      const $ = p.find((Q) => Q.id === B.book_entry_id);
1530      if (!$) continue;
1531      const ie = Yt({ word: $.word, meaning: $.meaning }, Ce);
1532      w.push(mr($, ie.wordMatches, Ce, B.reason));
1533    }
1534    return w.length === 0 ? 0 : (gt({ readyIds: [], queue: w, decisions: {}, decidedIds: [] }), w.length);
1535  }, ot = Dt({ networkMode: "offlineFirst", mutationFn: async ({ ids: r, decisions: c }) => {
1536    var N, w;
1537    if (!Je()) return await Ht({ action: "add", academyId: (N = x == null ? void 0 : x.academy_id) != null ? N : 0, userId: (w = x == null ? void 0 : x.id) != null ? w : 0, deviceId: ue, bookId: n, bookEntryIds: r, decisions: c }), { queued: true, ids: r, decisions: c };
1538    const B = Da(c), $ = B ? await Oe.addFromBook(r, B) : await Oe.addFromBook(r);
1539    return { queued: false, ids: r, decisions: c, res: $ };
1540  }, onSuccess: (r) => {
1541    if (r.queued) {
1542      Gt(r.ids, true, r.decisions), ce(), de.success("\uC624\uD504\uB77C\uC778 \uC0C1\uD0DC\uB85C \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC5F0\uACB0\uB418\uBA74 \uC790\uB3D9\uC73C\uB85C \uBC18\uC601\uB429\uB2C8\uB2E4.");
1543      return;
1544    }
1545    i.invalidateQueries({ queryKey: ["vocabulary"] }), i.invalidateQueries({ queryKey: ["vocabulary", "book-entries", n] }), $a(r.res.data, Vt(r.res.data));
1546  }, onError: (r) => {
1547    de.error(Ze(r, "\uB2E8\uC5B4 \uCD94\uAC00\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4."));
1548  } }), ht = a.useCallback((r, c) => {
1549    r.length !== 0 && ot.mutate({ ids: r, decisions: c });
1550  }, [ot]), Et = a.useCallback((r) => {
1551    const c = new Set(r), N = p.filter(($) => c.has($.id)), w = [], B = [];
1552    for (const $ of N) {
1553      if (!Ce) {
1554        w.push($.id);
1555        continue;
1556      }
1557      const ie = Yt({ word: $.word, meaning: $.meaning }, Ce);
1558      ie.verdict === "conflict" ? B.push(mr($, ie.wordMatches, Ce)) : w.push($.id);
1559    }
1560    if (B.length === 0) {
1561      ht(w, {});
1562      return;
1563    }
1564    gt({ readyIds: w, queue: B, decisions: {}, decidedIds: [] });
1565  }, [p, Ce, ht]), Ge = (r) => {
1566    if (!Se) return;
1567    const [c, ...N] = Se.queue, w = r ? { ...Se.decisions, [c.bookEntryId]: r } : Se.decisions, B = r ? [...Se.decidedIds, c.bookEntryId] : Se.decidedIds;
1568    if (N.length > 0) {
1569      gt({ ...Se, queue: N, decisions: w, decidedIds: B });
1570      return;
1571    }
1572    gt(null), ht([...Se.readyIds, ...B], w);
1573  }, { data: It } = dt({ queryKey: ["vocabulary", "handwriting", "book", n, ue], queryFn: () => Oe.fetchHandwriting("book", ue, n), select: (r) => r.data, enabled: F, staleTime: 6e4 }), Zt = a.useMemo(() => Dn(It), [It, ue]), ze = a.useCallback((r) => {
1574    var c, N;
1575    return { academyId: (c = x == null ? void 0 : x.academy_id) != null ? c : 0, userId: (N = x == null ? void 0 : x.id) != null ? N : 0, scope: "vocab-book", containerId: String(n), itemId: r };
1576  }, [n, x == null ? void 0 : x.academy_id, x == null ? void 0 : x.id]), Jt = a.useCallback((r, c) => {
1577    me(String(r), c);
1578  }, [me]), Mt = a.useCallback((r, c) => {
1579    Be.current[r] = c, St(c ? `SERVER_SAVE_DISABLED key=book:${r} strokes=${c.strokes.length} updatedAt=${c.updatedAt}` : `SERVER_SAVE_DISABLED key=book:${r} cleared`);
1580  }, []), er = a.useMemo(() => {
1581    var r, c;
1582    return In("vocab-book", (r = x == null ? void 0 : x.academy_id) != null ? r : 0, (c = x == null ? void 0 : x.id) != null ? c : 0, String(n));
1583  }, [n, x == null ? void 0 : x.academy_id, x == null ? void 0 : x.id]), { isNativeActive: it, undo: Rt, clear: At }
1583 = An({ entityId: String(n), enabled: F, containerRef: pe, tool: R, color: K, scopeName: "vocab-book", nativeDrawingStorageKey: er, buildStorageScope: ze, recordDraft: Mt, setActiveEntryId: z, setPersistenceStatus: me });
1584  a.useEffect(() => {
1585    le.current = it, L.current = Rt, Ee.current = At;
1586  }, [it, Rt, At, le, L, Ee]);
1587  const tr = a.useCallback(() => {
1588    Object.entries(Le).forEach(([r, c]) => {
1589      var N, w;
1590      const B = Number(r), $ = (N = Be.current[B]) != null ? N : null;
1591      ((w = c.local) == null ? void 0 : w.phase) === "error" && (me(r, { target: "local", phase: "saving", retryable: false, updatedAt: $ == null ? void 0 : $.updatedAt }), ($ ? pr(ze(B), $) : br(ze(B))).then(() => {
1592        me(r, { target: "local", phase: "saved", retryable: false, updatedAt: $ == null ? void 0 : $.updatedAt });
1593      }).catch((Q) => {
1594        const lt = Q instanceof jt ? Q : new jt("unknown_local_error");
1595        me(r, { target: "local", phase: "error", reasonCode: lt.reasonCode, message: yr(lt.reasonCode, "vocab-book"), retryable: true, updatedAt: $ == null ? void 0 : $.updatedAt });
1596      }));
1597    });
1598  }, [ze, me, Le]), Ue = I.size, pt = re.length > 0 && re.every((r) => I.has(r.id)), Te = re.filter((r) => I.has(r.id)).filter((r) => Pe(r) !== "saved").map((r) => r.id), t = En({ entries: se, activeStatus: m, onStatusChange: ne, onMoveEntries: ke, onBeforeOpen: q, disabled: Ve.isPending, pronunciationSource: "book" });
1599  return e.jsxs("div", { className: `px-2 pt-2 pb-20 md:p-6 md:pb-6 max-w-5xl mx-auto ${Ue > 0 ? "pb-56 sm:pb-36 md:pb-28" : ""}`, children: [e.jsx(xn, { message: (u = Ie == null ? void 0 : Ie.message) != null ? u : null, onRetry: tr, className: "mb-4" }), e.jsxs("div", { className: "mb-2 md:mb-4", children: [e.jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2", children: [e.jsx(J, { avoidNativeButton: F, onClick: s, className: "p-2 hover:bg-gray-100 rounded-lg transition-colors flex-shrink-0", children: e.jsx(wr, { className: "w-5 h-5 text-gray-600" }) }), e.jsx("h1", { className: "text-lg md:text-xl font-bold text-gray-900 flex flex-1 min-w-[12rem]", children: e.jsx("span", { className: "truncate", children: (h = o == null ? void 0 : o.title) != null ? h : "..." }) }), e.jsxs("div", { className: "hidden md:flex md:flex-wrap items-center justify-end gap-1.5 min-w-0 ml-auto", children: [tt && e.jsxs(e.Fragment, { children: [e.jsxs(J, { avoidNativeButton: F, onClick: Fe, disabled: re.length === 0, className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${be ? "bg-red-500 text-white border-red-500" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"} disabled:opacity-40`, children: [be ? e.jsx(Ot, { className: "w-3.5 h-3.5" }) : e.jsx(Nt, { className: "w-3.5 h-3.5" }), be ? "\uC911\uC9C0" : "\uC7AC\uC0DD"] }), e.jsx(J, { avoidNativeButton: F, onClick: () => ft((r) => !r), className: `flex items-center justify-center w-7 h-7 rounded-lg border transition-colors ${Qe ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-400 hover:text-gray-600 hover:bg-gray-50"}`, title: "\uC74C\uC131 \uC124\uC815", children: e.jsx(cn, { className: "w-3.5 h-3.5" }) })] }), e.jsxs(J, { avoidNativeButton: F, onClick: et, className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${T ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [e.jsx(Pt, { className: "w-3.5 h-3.5" }), T ? "\uC6D0\uB798\uC21C\uC11C" : "\uB79C\uB364"] }), e.jsxs(J, { avoidNativeButton: F, onClick: () => Y((r) => !r), className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${O ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [O ? e.jsx(Kt, { className: "w-3.5 h-3.5" }) : e.jsx(qt, { className: "w-3.5 h-3.5" }), O ? "\uB73B \uBCF4\uAE30" : "\uB73B \uAC00\uB9AC\uAE30"] }), e.jsxs(J, { avoidNativeButton: F, onClick: () => E((r) => !r), className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${_ ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [e.jsx(yn, { className: "w-3.5 h-3.5" }), _ ? "1\uC5F4" : "2\uC5F4"] }), F && e.jsxs(J, { avoidNativeButton: F, onClick: () => we((r) => !r), className: "flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-all bg-white border-gray-200 text-gray-600 hover:bg-gray-50", children: [oe ? e.jsx(Ut, { className: "w-3.5 h-3.5" }) : e.jsx(Wt, { className: "w-3.5 h-3.5" }), oe ? "\uCE74\uB4DC \uC791\uAC8C" : "\uCE74\uB4DC \uD06C\uAC8C"] }), e.jsxs(J, { avoidNativeButton: F, onClick: () => {
1600    be && ae(), Ne((r) => !r);
1601  }, className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-all ${F ? "bg-primary text-white border-primary shadow-sm" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [e.jsx(dn, { className: "w-3.5 h-3.5" }), F ? "\uD544\uAE30 ON" : "\uD544\uAE30"] })] })] }), e.jsx("div", { className: "flex items-center justify-end gap-2 mt-1", children: e.jsxs("div", { className: "flex md:hidden items-center gap-1.5 ml-auto flex-shrink-0", children: [tt && e.jsx(J, { avoidNativeButton: F, onClick: Fe, disabled: re.length === 0, className: `flex items-center justify-center w-8 h-8 rounded-lg border transition-colors ${be ? "bg-red-500 text-white border-red-500" : "bg-white border-gray-200 text-gray-600"} disabled:opacity-40`, title: be ? "\uC7AC\uC0DD \uC911\uC9C0" : "\uB2E8\uC5B4 \uC7AC\uC0DD", children: be ? e.jsx(Ot, { className: "w-3.5 h-3.5" }) : e.jsx(Nt, { className: "w-3.5 h-3.5" }) }), e.jsxs(J, { avoidNativeButton: F, onClick: et, className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${T ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [e.jsx(Pt, { className: "w-3.5 h-3.5" }), T ? "\uC6D0\uB798\uC21C\uC11C" : "\uB79C\uB364"] }), e.jsxs(J, { avoidNativeButton: F, onClick: () => Y((r) => !r), className: `flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-lg border transition-colors ${O ? "bg-primary/10 border-primary/30 text-primary" : "bg-white border-gray-200 text-gray-600 hover:bg-gray-50"}`, children: [O ? e.jsx(Kt, { className: "w-3.5 h-3.5" }) : e.jsx(qt, { className: "w-3.5 h-3.5" }), O ? "\uB73B \uBCF4\uAE30" : "\uB73B \uAC00\uB9AC\uAE30"] }), F && e.jsx(J, { avoidNativeButton: F, onClick: () => we((r) => !r), className: "flex items-center justify-center w-8 h-8 rounded-lg border transition-all bg-white border-gray-200 text-gray-600", title: oe ? "\uCE74\uB4DC \uC791\uAC8C" : "\uCE74\uB4DC \uD06C\uAC8C", children: oe ? e.jsx(Ut, { className: "w-3.5 h-3.5" }) : e.jsx(Wt, { className: "w-3.5 h-3.5" }) })] }) })] }), t.folderTabs, t.overlays, Qe && Re.length > 0 && e.jsx(Mn, { enVoices: Re, koVoices: rt, selectedEnVoice: Ae, selectedKoVoice: mt, onEnVoiceChange: nt, onKoVoiceChange: at, onClose: () => ft(false), avoidNativeButtons: F }), F && e.jsx(gn, { tool: R, onToolChange: D, penColor: K, onPenColorChange: ee, onUndo: H, onClear: U, canUndo: te != null, canClear: true }), Se && Se.queue.length > 0 && e.jsx(wn, { prompt: Se.queue[0], remainingCount: Se.queue.length - 1, onMerge: () => Ge({ action: "merge", targetEntryId: Se.queue[0].mergeTargetEntryId }), onSeparate: () => Ge({ action: "separate" }), onDismiss: () => Ge(null) }), Ue > 0 && e.jsxs("div", { className: "fixed bottom-0 left-0 right-0 z-50 flex flex-nowrap items-center justify-center gap-1 border-t border-gray-200 bg-white pb-[max(0.75rem,env(safe-area-inset-bottom))] pl-[max(0.5rem,env(safe-area-inset-left))] pr-[max(0.5rem,env(safe-area-inset-right))] pt-3 shadow-[0_-4px_12px_rgba(0,0,0,0.08)] sm:gap-2 sm:pl-[max(1rem,env(safe-area-inset-left))] sm:pr-[max(1rem,env(safe-area-inset-right))]", children: [e.jsxs("span", { className: "shrink-0 whitespace-nowrap text-sm font-semibold text-primary", children: [e.jsxs("span", { className: "sm:hidden", children: [Ue, "\uAC1C"] }), e.jsxs("span", { className: "hidden sm:inline", children: [Ue, "\uAC1C \uC120\uD0DD\uB428"] })] }), m === "known" && e.jsxs(e.Fragment, { children: [e.jsxs("button", { onClick: () => {
1602    ve("default");
1603  }, disabled: Ve.isPending, "aria-label": "\uAE30\uBCF8\uC73C\uB85C", className: "flex shrink-0 items-center gap-1 whitespace-nowrap rounded-lg border border-gray-300 px-2 py-1.5 text-sm text-gray-700 transition-colors hover:bg-gray-50 disabled:opacity-50 sm:gap-1.5 sm:px-3", children: [e.jsx("span", { className: "sm:hidden", children: "\uAE30\uBCF8" }), e.jsx("span", { className: "hidden sm:inline", children: "\uAE30\uBCF8\uC73C\uB85C" })] }), e.jsxs("button", { onClick: () => {
1604    ve("memorized");
1605  }, disabled: Ve.isPending, "aria-label": "\uC554\uAE30\uB428\uC73C\uB85C", className: "flex shrink-0 items-center gap-1 whitespace-nowrap rounded-lg border border-primary/30 bg-primary/5 px-2 py-1.5 text-sm text-primary transition-colors hover:bg-primary/10 disabled:opacity-50 sm:gap-1.5 sm:px-3", children: [e.jsx("span", { className: "sm:hidden", children: "\uC554\uAE30\uB428" }), e.jsx("span", { className: "hidden sm:inline", children: "\uC554\uAE30\uB428\uC73C\uB85C" })] })] }), e.jsxs("button", { onClick: () => Et(Te), disabled: ot.isPending || Te.length === 0, "aria-label": "\uB098\uC758 \uB2E8\uC5B4\uC7A5\uC5D0 \uCD94\uAC00", className: "flex shrink-0 items-center gap-1 whitespace-nowrap rounded-lg bg-primary px-2 py-1.5 text-sm text-white transition-colors hover:bg-primary/90 disabled:opacity-50 sm:gap-1.5 sm:px-3", children: [ot.isPending ? e.jsx(We, { className: "w-3.5 h-3.5 animate-spin" }) : e.jsx(na, { className: "w-3.5 h-3.5" }), e.jsx("span", { className: "sm:hidden", children: "\uB2E8\uC5B4\uC7A5 \uCD94\uAC00" }), e.jsx("span", { className: "hidden sm:inline", children: "\uB098\uC758 \uB2E8\uC5B4\uC7A5\uC5D0 \uCD94\uAC00" })] }), m !== "known" && e.jsxs("button", { onClick: () => {
1606    Xe();
1607  }, disabled: Ve.isPending, "aria-label": "\uC544\uB294 \uB2E8\uC5B4\uB85C \uC774\uB3D9", className: "flex shrink-0 items-center gap-1 whitespace-nowrap rounded-lg border border-primary/30 bg-primary/5 px-2 py-1.5 text-sm text-primary transition-colors hover:bg-primary/10 disabled:opacity-50 sm:gap-1.5 sm:px-3", children: [e.jsx(or, { className: "h-3.5 w-3.5" }), e.jsx("span", { className: "sm:hidden", children: "\uC544\uB294 \uB2E8\uC5B4" }), e.jsx("span", { className: "hidden sm:inline", children: "\uC544\uB294 \uB2E8\uC5B4\uB85C \uC774\uB3D9" })] }), e.jsxs("button", { onClick: () => {
1608    ce(), vt(m);
1609  }, className: "flex shrink-0 items-center gap-1 whitespace-nowrap text-sm text-gray-500 transition-colors hover:text-gray-700", children: [e.jsx(_t, { className: "w-4 h-4" }), "\uC120\uD0DD \uD574\uC81C"] })] }), y ? e.jsx(vr, { message: "\uC624\uD504\uB77C\uC778 \uC0C1\uD0DC\uC774\uBA70 \uC774 \uB2E8\uC5B4\uC7A5\uC744 \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." }) : v ? e.jsx("div", { className: "flex items-center justify-center h-48", children: e.jsx(We, { className: "w-8 h-8 animate-spin text-primary" }) }) : S ? e.jsxs("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [e.jsx(Ke, { className: "mb-4 h-12 w-12 text-amber-500" }), e.jsx("h2", { className: "mb-2 text-lg font-semibold text-gray-700", children: "\uB2E8\uC5B4\uC7A5\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4" }), e.jsx("p", { className: "mb-5 text-sm text-gray-500", children: "\uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694." }), e.jsx("button", { type: "button", onClick: () => {
1610    C();
1611  }, className: "rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm text-gray-700 hover:bg-gray-50", children: "\uB2E4\uC2DC \uC2DC\uB3C4" })] }) : p.length === 0 ? e.jsxs("div", { className: "text-center py-16", children: [e.jsx(ir, { className: "w-16 h-16 mx-auto text-gray-300 mb-4" }), e.jsx("h2", { className: "text-lg font-semibold text-gray-700 mb-2", children: "\uB2E8\uC5B4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" })] }) : re.length === 0 ? e.jsxs("div", { className: "text-center py-14 roun
1611ded-xl border border-dashed border-gray-200 bg-gray-50/60", children: [e.jsx(ir, { className: "w-12 h-12 mx-auto text-gray-300 mb-3" }), e.jsxs("h2", { className: "text-base font-semibold text-gray-700", children: [ut[m], " \uD3F4\uB354\uC5D0 \uB2E8\uC5B4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4"] }), e.jsx("p", { className: "mt-1 text-sm text-gray-500", children: "\uB2E4\uB978 \uD3F4\uB354\uC5D0\uC11C \uB2E8\uC5B4\uB97C \uC774\uB3D9\uD574 \uBCF4\uC138\uC694." })] }) : F ? e.jsxs(e.Fragment, { children: [t.folderActions && e.jsx("div", { className: "py-1.5", children: t.folderActions }), e.jsx("div", { ref: pe, className: _ ? "flex flex-col gap-0.5 md:grid md:grid-cols-2 md:grid-flow-col" : "space-y-0.5", style: _ ? { gridTemplateRows: `repeat(${Math.ceil(re.length / 2)}, auto)` } : void 0, children: re.map((r, c) => {
1612    const N = te === r.id;
1613    return e.jsx(Tn, { entryId: r.id, index: c, active: N, largeCards: oe, isNativeActive: it, onActivate: () => z(r.id), renderOverlay: () => e.jsx(hn, { ref: (w) => {
1614      w ? he.current.set(r.id, w) : he.current.delete(r.id);
1615    }, questionId: r.id, sheetId: n, enabled: F, disableNative: true, deviceId: ue, serverDraft: Zt[String(r.id)], onDraftChange: Mt, syncHydratedDraft: false, touchActionMode: "pan-y", debugPanelActive: N, storageKeyPrefix: "vocab-b-", storageScope: ze(r.id), onPersistenceStatusChange: (w) => Jt(r.id, w), tool: R, onToolChange: D, penColor: K, onPenColorChange: ee, hideToolbar: true, onActivate: () =>
1615 z(r.id), entityType: "vocabulary", entityId: String(n), subEntityId: String(r.id), tapZoneSelector: "button[data-handwriting-tap-through]" }), children: e.jsxs("div", { className: "absolute inset-0 z-[11] pointer-events-none flex items-center gap-3 px-4", children: [e.jsx("input", { type: "checkbox", checked: I.has(r.id), onChange: (w) => Z(c, w.nativeEvent.shiftKey), className: "w-5 h-5 md:w-4 md:h-4 rounded border-gray-300 text-primary focus:ring-primary/30 pointer-events-auto" }), e.jsx("span", { className: "text-sm text-gray-400 w-6 text-right", children: c + 1 }), e.jsx(Lt, { word: r.word, active: be && fe === c, onPlay: () => He(c), handwriting: true }), e.jsx("span", { className: "font-semibold text-gray-900 text-base", children: r.word }), e.jsx("button", { type: "button", "data-handwriting-tap-through": true, onClick: O ? (w) => {
1616      w.stopPropagation(), qe(r.id);
1617    } : void 0, className: `text-base ml-auto bg-transparent border-0 p-0 ${O ? "pointer-events-auto cursor-pointer select-none active:bg-gray-100 rounded px-1" : "pointer-events-none"} ${O && !A.has(r.id) ? "text-gray-400" : "text-gray-600"}`, children: !O || A.has(r.id) ? r.meaning : "\u2022\u2022\u2022\u2022" })] }) }, r.id);
1618  }) })] }) : e.jsxs(e.Fragment, { children: [_ ? e.jsxs("div", { className: "hidden md:block bg-white rounded-xl border border-gray-200 overflow-hidden", children: [t.folderActions && e.jsx("div", { className: "flex items-center border-b border-gray-100 bg-gray-50/60 px-2 py-2.5", children: t.folderActions }), e.jsx("div", { ...X, className: "grid grid-cols-2 grid-flow-col py-2", style: { ...X.style, gridTemplateRows: `repeat(${Math.ceil(re.length / 2)}, auto)` }, children: re.map((r, c) => e.jsxs("div", { "data-vocab-select-index": c, ref: fe === c ? (N) => {
1619    st.current = N;
1620  } : void 0, onClick: () => Z(c, false), className: `flex items-center gap-2 px-4 py-1.5 cursor-pointer transition-colors ${c < Math.ceil(re.length / 2) ? "border-r border-gray-100" : ""} ${fe === c ? "bg-yellow-50" : I.has(r.id) ? "bg-primary/5" : "hover:bg-gray-50/50"}`, children: [e.jsx("span", { "data-vocab-drag-handle": true, onClick: (N) => {
1621    N.stopPropagation(), Z(c, false);
1622  }, className: "-m-3 flex flex-shrink-0 items-center justify-center p-3", style: { touchAction: "none" }, children: e.jsx("input", { type: "checkbox", checked: I.has(r.id), onChange: (N) => {
1623    N.stopPropagation(), Z(c, N.nativeEvent.shiftKey);
1624  }, onClick: (N) => N.stopPropagation(), className: "rounded border-gray-300 text-primary focus:ring-primary/30" }) }), e.jsxs("span", { className: "text-xs text-gray-400 w-6 text-right flex-shrink-0", children: [c + 1, "."] }), e.jsx(Lt, { word: r.word, active: be && fe === c, onPlay: () => He(c) }), e.jsx("span", { className: "font-medium text-gray-900 truncate", children: r.word }), e.jsx("span", { onClick: O ? (N) => {
1625    N.stopPropagation(), qe(r.id);
1626  } : void 0, className: `text-sm ml-auto truncate ${O ? "cursor-pointer select-none" : ""} ${O && !A.has(r.id) ? "text-gray-400" : "text-gray-600"}`, children: !O || A.has(r.id) ? r.meaning : "\u2022\u2022\u2022\u2022" })] }, r.id)) })] }) : e.jsxs("div", { className: "hidden md:block bg-white rounded-xl border border-gray-200 overflow-hidden", children: [t.folderActions && e.jsx("div", { className: "flex items-center border-b border-gray-100 bg-gray-50/60 px-2 py-2.5", children: t.folderActions }), e.jsxs("table", { className: "w-full", children: [e.jsx("thead", { children: e.jsxs("tr", { className: "border-b border-gray-100 bg-gray-50/60", children: [e.jsx("th", { className: "w-10 px-4 py-3", children: e.jsx("input", { type: "checkbox", checked: pt, onChange: (r) => ye(r.target.checked), disabled: re.length === 0, className: "rounded border-gray-300 text-primary focus:ring-primary/30 disabled:opacity-30" }) }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-16", children: "\uBC88\uD638" }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-48", children: "\uB2E8\uC5B4" }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-48", children: "\uB73B" }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider", children: "\uC608\uBB38" }), e.jsx("th", { className: "px-4 py-3 text-left text-xs font-semibold text-gray-500 uppercase tracking-wider w-24", children: "\uC0C1\uD0DC" })] }) }), e.jsx("tbody", { ...X, children: re.map((r, c) => {
1627    var N;
1628    return e.jsxs("tr", { "data-vocab-select-index": c, ref: fe === c ? (w) => {
1629      st.current = w;
1630    } : void 0, className: `border-b border-gray-50 last:border-b-0 hover:bg-gray-50/50 transition-colors ${fe === c ? "bg-yellow-50 ring-1 ring-inset ring-yellow-300" : I.has(r.id) ? "bg-primary/5" : ""}`, children: [e.jsx("td", { className: "px-4 py-3", children: e.jsx("span", { "data-vocab-drag-handle": true, onClick: (w) => {
1631      w.stopPropagation(), Z(c, false);
1632    }, className: "-m-3 inline-flex items-center justify-center p-3", style: { touchAction: "
1632none" }, children: e.jsx("input", { type: "checkbox", checked: I.has(r.id), onChange: (w) => Z(c, w.nativeEvent.shiftKey), onClick: (w) => w.stopPropagation(), className: "rounded border-gray-300 text-primary focus:ring-primary/30" }) }) }), e.jsx("td", { className: "px-4 py-3 text-sm text-gray-400", children: c + 1 }), e.jsx("td", { onClick: () => Z(c, false), className: "px-4 py-3 font-medium text-gray-900 whitespace-pre-line cursor-pointer", children: e.jsxs("div", { className: "flex items-center gap-2", children: [e.jsx(Lt, { word: r.word, active: be && fe === c, onPlay: () => He(c) }), e.jsx("span", { children: r.word })] }) }), e.jsx("td", { onClick: O ? () => qe(r.id) : void 0, className: `px-4 py-3 text-sm whitespace-pre-line ${O ? "cursor-pointer select-none" : ""} ${O && !A.has(r.id) ? "text-gray-400" : "text-gray-700"}`, children: !O || A.has(r.id) ? r.meaning : "\u2022\u2022\u2022\u2022" }), e.jsx("td", { className: "px-4 py-3 text-sm text-gray-500 whitespace-pre-line", children: (N = r.example_sentence) != null ? N : "-" }), e.jsx("td", { className: "px-4 py-3", children: Pe(r) === "saved" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-green-600 bg-green-50 px-2 py-0.5 rounded-full", children: [e.jsx(or, { className: "w-3 h-3" }), "\uCD94\uAC00\uB428"] }) : Pe(r) === "conflict" ? e.jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-amber-600 bg-amber-50 px-2 py-0.5 rounded-full", children: [e.jsx(Ke, { className: "w-3 h-3" }), "\uB2E4\uB978 \uB73B \uC800\uC7A5\uB428"] }) : e.jsx("span", { className: "text-xs text-gray-400", children: "\uBBF8\uCD94\uAC00" }) })] }, r.id);
1633  }) })] })] }), e.jsxs("div", { ...X, "data-testid": "book-vocabulary-selection-surface-mobile", className: "md:hidden bg-white rounded-xl border border-gray-200 overflow-hidden", children: [e.jsxs("div", { className: "flex items-center gap-1 px-2 py-2.5 border-b border-gray-100 bg-gray-50/60", children: [e.jsx("input", { type: "checkbox", checked: pt, onChange: (r) => ye(r.target.checked), disabled: re.length === 0, className: "w-5 h-5 rounded border-gray-300 text-primary focus:ring-primary/30 disabled:opacity-30" }), e.jsx("span", { className: "text-sm text-gray-500", children: "\uC804\uCCB4 \uC120\uD0DD" }), t.folderActions] }), re.map((r, c) => e.jsxs("div", { "data-vocab-select-index": c, ref: fe === c ? (N) => {
1634    xt.current = N;
1635  } : void 0, onClick: () => Z(c, false), className: `flex items-center gap-0.5 px-2 py-2.5 border-b border-gray-50 last:border-b-0 transition-colors cursor-pointer active:bg-gray-100 ${fe === c ? "bg-yellow-50 ring-1 ring-inset ring-yellow-300" : I.has(r.id) ? "bg-primary/5" : Pe(r) === "saved" ? "bg-green-50/40" : Pe(r) === "conflict" ? "bg-amber-50/40" : ""}`, children: [e.jsx("span", { "data-vocab-drag-handle": true, className: "-m-2.5 flex flex-shrink-0 items-center justify-center p-2.5", style: { touchAction: "none" }, children: e.jsx("input", { type: "checkbox", checked: I.has(r.id), readOnly: true, className: "w-5 h-5 rounded border-gray-300 text-primary focus:ring-primary/30 pointer-events-none" }) }), e.jsx("span", { className: "text-xs text-gray-400 w-4 text-center flex-shrink-0", children: c + 1 }), e.jsx(Lt, { word: r.word, active: be && fe === c, onPlay: () => He(c) }), e.jsx("span", { className: "font-medium text-gray-900 flex-1 min-w-0 line-clamp-2 ml-0.5", children: r.word }), e.jsx("span", { onClick: O ? (N) => {
1636    N.stopPropagation(), qe(r.id);
1637  } : void 0, className: `text-sm flex-shrink-0 line-clamp-2 text-right ${O ? "w-[42%] py-3 -my-2.5 pl-2 -mr-1 pr-1 cursor-pointer select-none active:bg-gray-100 rounded-md" : "max-w-[40%]"} ${O && !A.has(r.id) ? "text-gray-400" : "text-gray-600"}`, children: !O || A.has(r.id) ? r.meaning : "\u2022\u2022\u2022\u2022" })] }, r.id))] })] })] });
1638}
1639export {
1640  ks as VocabularyPage
1641};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.