VOCABULARY DATA
===============
Load order (first file that exists wins, see 04_vocab.rpy):
  1. game/data/vocab_user.csv    optional hand-made override
  2. game/data/vocab.csv         GENERATED from source/vocab_source.xlsx
  3. game/data/vocab_sample.csv  30-word fallback sample

Regenerate vocab.csv after editing the spreadsheet (from project root):
    python3 tools/import_vocab.py [source/vocab_source.xlsx] [game/data/vocab.csv]
The importer uses only the Python standard library (reads the xlsx XML
directly). Safe to re-run; it overwrites vocab.csv.

Spreadsheet expected: one sheet with columns Section, Lesson, Russian, English.
  - Section "Frequency" (shown in game as "Supplemental") -> priority=low (general list, lowest priority)
  - every other section (Mod 1..7, Thematics, News & Media) -> priority=high; these
    set curriculum order by lesson.
  - "/" aspect pairs, stress marks, non-breaking spaces and [ ] / { } notes
    are normalised ([ ] { } become ( ) so Ren'Py text tags don't break).

vocab.csv columns (UTF-8, '#' lines are comments, column order free)
  ru        Russian (stress marks kept for display; ignored when grading)
  en        main English meaning
  section   spreadsheet section (Unit 1 Part 1 ... Unit 4 Part 2, Supplemental)
  lesson    spreadsheet lesson / unit
  priority  high | low
  week      course week the word unlocks; high-priority words spread by
            lesson order, Supplemental words fill in behind them
  order     global curriculum order
  pos, gender, tags, alt_en   optional; alt_en = other accepted answers (;)

Minimal hand-made file:   ru,en      (week auto-assigned in file order)

Who uses it
  * Quizzes/exams (05_exams.rpy): only words with week <= current week;
    high priority first, recent lessons weighted up.
  * Minigames (13_minigames.rpy): same weighting, Supplemental capped at 1/5
    of a round, plus words due in spaced repetition.
  * Spaced repetition: every graded answer (exams, drills, minigames)
    updates a Leitner box per word (intervals 1,2,4,8,16,32,64 in-game
    days; a miss resets to box 0, due tomorrow). Due words are boosted in
    every picker and can be drilled from Phone > Review deck.

Wiktionary definitions (Inspect tool)
  wiktionary_cache.json  English-Wiktionary entries (Russian section) for
                         every Russian word in the game text and the
                         vocab list: all senses grouped by part of speech,
                         "inflection of" links to the lemma, headword with
                         stress, gender/animacy, aspect pair. Multiple
                         senses per lemma; versioned JSON.
  wiktionary_cache.csv   flat summary (word, lemma, pos, gloss, source).
  Rebuild / extend:      python3 tools/fetch_wiktionary.py --scope all
                         (resumable; --scope game|high|all, --rate,
                         --max-minutes, --stats for coverage only)
  At run time a word missing from the cache is looked up live in a
  background thread and saved to <savedir>/wiktionary_user_cache.json
  (Preferences > Dictionary > Online lookups switches this off).
  Content: Wiktionary contributors, CC BY-SA 4.0
  (https://creativecommons.org/licenses/by-sa/4.0/); see the About screen.
