// КЕЙС №2 — "Тихий аукціон". Сучасний нуар, два акти. Все детерміновано, без AI. const CASE = { title: 'Тихий аукціон', intro: 'Місто. Листопад. Третя доба дощу. Віктор Гайдук, 58, власник аукціонного дому «Гайдук і Спадок», знайдений мертвим у кріслі свого кабінету над аукціонною залою — напередодні найбільших торгів року. Лікар швидкої написав «серцевий напад». Страхова компанія вимагає незалежної перевірки. У вас одна ніч і жодного ордера.', actNote: 'АКТ I: доведіть, що це вбивство — тоді прокурор підпише ордери. АКТ II: доведіть, хто вбивця.', act2title: 'АКТ II — ОРДЕРИ ПІДПИСАНО', act2text: 'Токсикологія підтвердила: це вбивство. Прокурор підписав ордери — відкрито доступ до банків, реєстрів і приватних приміщень. Тепер знайдіть того, хто налив отруту.', roles: { field: { name: 'Польовий детектив', desc: 'Ти працюєш ногами: місце злочину, обшуки, допити віч-на-віч. Обшук вимагає твердої руки — зафіксуй сканер у зоні сигналу. Цифрові системи для тебе закриті.' }, analyst: { name: 'Детектив-аналітик', desc: 'Ти працюєш з терміналу: камери, дзвінки, банки, біометрія. Кожен запит захищений — перехопи й повтори код доступу. На місце злочину тебе не пускають.' } }, howto: 'Знайдені докази закріплюйте на спільній дошці (📌) — лише закріплене бачить напарник, і лише воно розблоковує нові питання й запити. Відкидайте підозрюваних, зірочте ключові докази, лишайте нотатки — все синхронізується. Говоріть уголос.', suspects: [ { id: 'stryzh', name: 'Богдан Стриж', role: 'Партнер, головний аукціоніст', desc: 'Друга особа дому «Гайдук і Спадок». Бігає марафони, курить дорогі сигарили — «одна на день, для нервів».' }, { id: 'iryna', name: 'Ірина Гайдук', role: 'Дружина', desc: 'Молодша за чоловіка на двадцять років. Шлюбний контракт, велика страховка — місто вже все порахувало.' }, { id: 'dana', name: 'Дана Гайдук', role: 'Дочка від першого шлюбу', desc: 'Не розмовляла з батьком два роки. Борги, зйомна квартира, гострий язик.' }, { id: 'mazur', name: 'Лесь Мазур', role: 'Реставратор', desc: 'П\'ять років тому Гайдук публічно знищив його репутацію. Тепер веде стріми з реставрації — на життя вистачає.' }, { id: 'pliuta', name: 'Артем Плюта', role: 'Колекціонер', desc: 'Купив у Гайдука «Екстер» за триста тисяч. Експертиза сказала: підробка. Судиться.' } ], methods: [ { id: 'digoxin', label: 'Передозування дигоксином, розчиненим у коньяку в графині' }, { id: 'placebo', label: 'Підміна серцевих ліків на плацебо' }, { id: 'smother', label: 'Задушення з інсценуванням серцевого нападу' }, { id: 'insulin', label: 'Ін\'єкція інсуліну' }, { id: 'natural', label: 'Природна смерть — серцевий напад' } ], evidence: { // ---- АКТ I, фізичні ---- decanter: { role: 'field', title: 'Осад у графині', tag: 'засіб', detail: 'На дні графина з коньяком — білуватий кристалічний осад. Коньяк такого не лишає. Графин стоїть на звичному місці, біля крісла.' }, wiped_glass: { role: 'field', title: 'Вимитий келих', tag: 'інсценування', detail: 'Єдиний келих — ретельно вимитий і поставлений догори дном біля мийки. Мертві не миють посуд. Хтось прибирав за ним.' }, diary: { role: 'field', title: 'Щоденник Гайдука', tag: 'мотив', detail: 'Останній запис, зроблений вчора: «Скасувати торги. Дзвонити К. Нікому в домі не вірити.» Слово «домі» підкреслено двічі.' }, pills_missing:{ role: 'field', title: 'Зниклі ліки', tag: 'засіб', detail: 'В аптечці — свіжий рецепт на дигоксин (серцевий препарат), виписаний тиждень тому. Самої пляшечки ніде немає. Ні в кабінеті, ні в смітті.' }, cigarillo: { role: 'field', title: 'Недопалок сигарили', tag: 'доступ', detail: 'Свіжий недопалок дорогої сигарили під дверима службового входу. Двері — на защіпці, камери там немає. Потрібен аналіз ДНК — закріпи на дошці для аналітика.' }, guard2: { role: 'field', title: 'Свідчення охоронця', tag: 'алібі', detail: 'Охоронець Семен: «Пан Стриж вийшов о 21:03 головним входом, я записав. Службовий вхід на защіпці, камери там нема — економія. На паркінгу камери два тижні як мертві, тільки шлагбаум лог пише».' }, cleaner_st: { role: 'field', title: 'Свідчення прибиральниці', tag: 'таймлайн', detail: 'Пані Ольга: «Графин я мила о сьомій вечора, як завжди. Пан Віктор наливав перший келих о пів на десяту — ритуал, свята справа. Келих я не мила і догори дном не ставила».' }, // ---- АКТ II, фізичні ---- coatcheck: { role: 'field', title: 'Свідчення гардеробниці', tag: 'алібі', act: 2, detail: 'Пані Зоя з фонду «Меценат»: «Пан Стриж? Здав пальто десь після пів на одинадцяту — точно після початку дощу, мокрий був наскрізь. А дощ того вечора почався о десятій». Людська пам\'ять — не документ, але вона впевнена щодо дощу.' }, blister: { role: 'field', title: 'Блістер у смітті Стрижа', tag: 'засіб', act: 2, detail: 'На дні сміттєвого пакета в офісі Стрижа на складі — порожній блістер дигоксину. У марафонця Стрижа здорове серце. Партію можна простежити — закріпи для аналітика.' }, fake_canvases:{ role: 'field', title: 'Підробки на складі', tag: 'мотив', act: 2, detail: 'Склад №3: шість полотен «з провенансом» — і поруч шість свіжих копій, ще зі скипидарним запахом. Це лоти 12–18 завтрашніх торгів. Хтось продає фальшаки через дім Гайдука.' }, dana_confess:{ role: 'field', title: 'Зізнання Дани', tag: 'зняття підозри', detail: 'Дана визнала: заходила о 20:30 забрати картину Марчука з малої зали — «батько мені її обіцяв». Вийшла о 21:12, до кабінету не піднімалась. Камера це підтверджує.' }, stryzh_lie: { role: 'field', title: 'Злам алібі Стрижа', tag: 'алібі', act: 2, detail: 'Під тиском фактів Стриж визнав: повертався в дім службовим входом «за каталогами», виїхав з паркінгу о 22:14. Стверджує, що Гайдук був живий і «пив свій коньяк».' }, // ---- АКТ I, цифрові ---- watch_log: { role: 'analyst', title: 'Лог смарт-годинника', tag: 'спосіб смерті', detail: 'Годинник жертви: 21:52 — аритмія за патерном глікозидної інтоксикації (передозування серцевим препаратом). 22:03 — зупинка серця. Це не «просто напад» — це отруєння.' }, lobby_cam: { role: 'analyst', title: 'Камера головного входу', tag: 'таймлайн', detail: 'Стриж: вихід 21:03. Дана Гайдук: вхід 20:30, вихід 21:12 — на поверх кабінету не піднімалась, була лише в малій залі. Після 21:12 головним входом ніхто не заходив і не виходив до ранку.' }, call_log: { role: 'analyst', title: 'Відеодзвінок Ірини', tag: 'зняття підозри', detail: 'Ірина Гайдук: відеодзвінок сестрі в Торонто 21:28–22:36 з домашнього wifi, камера активна, обличчя в кадрі підтверджено. На момент отруєння була вдома.' }, stream_log: { role: 'analyst', title: 'Стрім Мазура', tag: 'зняття підозри', detail: 'Лесь Мазур: безперервна пряма трансляція реставрації 20:00–23:05, п\'ятсот глядачів, обличчя й руки в кадрі весь час. Залізне алібі.' }, expert_email:{ role: 'analyst', title: 'Лист експертці', tag: 'мотив', detail: 'Гайдук — експертці Катерині Резник, учора 18:44: «Катерино, перевірте лоти 12–18 до торгів. Особисто. Нікому ні слова».' }, geo_toll: { role: 'analyst', title: 'Геолокація Плюти', tag: 'зняття підозри', detail: 'Плюта: транзакції на платних дорогах і АЗС — о 21:50 був за 170 км від міста, повертався з Одеси. Фізично не міг бути в кабінеті.' }, // ---- АКТ II, цифрові ---- parking: { role: 'analyst', title: 'Лог шлагбаума паркінгу', tag: 'алібі', act: 2, detail: 'Паркінг аукціонного дому: авто Стрижа — виїзд о 22:14. Він каже, що «поїхав о 21:00 і о 21:30 був на вечері фонду». Авто каже інше.' }, tox_report: { role: 'analyst', title: 'Токсикологія (ордер)', tag: 'спосіб смерті', act: 2, detail: 'Офіційний висновок: дигоксин, семикратна терапевтична доза. У крові жертви — і в залишках коньяку з графина. Отруту розчинили саме там.' }, dna_match: { role: 'analyst', title: 'ДНК з недопалка', tag: 'доступ', act: 2, requires: ['cigarillo'], detail: 'ДНК зі слини на недопалку сигарили біля службового входу: збіг — Богдан Стриж. Він стояв під дверима без камер того вечора.' }, bank_shell: { role: 'analyst', title: 'Рахунки-прокладки', tag: 'мотив', act: 2, detail: 'Ордер на банки: ТОВ «Артконсалт-Гарант» отримало 2,3 млн за «атрибуцію» лотів 12–18. Кінцевий бенефіціар прокладки — Богдан Стриж. Гайдук збирався скасувати торги і поховати схему.' }, pharma_log: { role: 'analyst', title: 'Слід партії дигоксину', tag: 'засіб', act: 2, requires: ['blister'], detail: 'Партія з блістера: онлайн-аптека, замовлення на неіснуючу «О. Кравець», доставка в поштомат за квартал від дому Стрижа, оплата карткою, поповненою готівкою. Ланцюжок веде до нього.' } }, // Умова переходу в Акт II: обидва докази вбивства на дошці. actGate: ['decanter', 'watch_log'], locations: [ { id: 'office', name: 'Кабінет Гайдука', desc: 'Кабінет над аукціонною залою. Крісло, графин, дощ по склу. Тіло вже забрали.', spots: [ { id: 's1', label: 'Оглянути графин', ev: 'decanter' }, { id: 's2', label: 'Оглянути мийку та келих', ev: 'wiped_glass' }, { id: 's3', label: 'Обшукати стіл', ev: 'diary' }, { id: 's4', label: 'Оглянути аптечку', ev: 'pills_missing' }, { id: 's5', label: 'Службові сходи', ev: 'cigarillo' }, { id: 's6', label: 'Оглянути крісло', flavor: 'Жодних слідів боротьби. Він просто сів у крісло з келихом — і не встав. Хтось дуже хотів, щоб це виглядало саме так.' } ], people: ['olga'] }, { id: 'hall', name: 'Аукціонна зала', desc: 'Порожня зала, накриті лоти, завтра тут мали бути торги року.', spots: [], people: ['stryzh', 'dana', 'semen'] }, { id: 'house', name: 'Дім Гайдуків', desc: 'Особняк за містом. Тихо, дорого, самотньо.', spots: [], people: ['iryna'] }, { id: 'studio', name: 'Студія Мазура', desc: 'Підвал, лампи, запах лаку. У кутку — кільцева лампа для стрімів.', spots: [], people: ['mazur'] }, { id: 'hotel', name: 'Готель «Централь»', desc: 'Плюта зупинився тут «до кінця судового процесу».', spots: [], people: ['pliuta'] }, { id: 'fund', name: 'Фонд «Меценат»', desc: 'Зала благодійної вечері, де Стриж «був з 21:30». Гардероб працює до останнього гостя.', act: 2, spots: [ { id: 's7', label: 'Розпитати розпорядника', flavor: '«Пан Стриж? Був, звісно. Коли саме прийшов? У нас не клуб, детективе, ми квитки не штампуємо. Спитайте в гардеробі — Зоя все пам\'ятає».' } ], people: ['zoya'] }, { id: 'depot', name: 'Склад «Гайдук і Спадок» №3', desc: 'Ордер відкрив двері, які Стриж тримав замкненими. Його офіс — у кутку складу.', act: 2, spots: [ { id: 's8', label: 'Оглянути ящики з лотами', ev: 'fake_canvases' }, { id: 's9', label: 'Обшукати сміття в офісі Стрижа', ev: 'blister' }, { id: 's10', label: 'Сейф Стрижа', flavor: 'Замкнено. Злам сейфа ордер не покриває — та й те, що лежить у смітті, часом говорить голосніше.' } ], people: [] } ], systems: [ { id: 'video', name: 'Камери й трансляції', queries: [ { id: 'q1', label: 'Камера головного входу аукціонного дому', ev: 'lobby_cam' }, { id: 'q2', label: 'Стрім-платформа: канал Мазура', ev: 'stream_log' }, { id: 'q3', label: 'Камери паркінгу', flavor: 'Камери паркінгу не працюють два тижні — «на технічному обслуговуванні». Пише лише лог шлагбаума, а він видається тільки з ордером.' }, { id: 'q4', label: 'Лог шлагбаума паркінгу (ордер)', ev: 'parking', act: 2 } ]}, { id: 'comms', name: 'Зв\'язок', queries: [ { id: 'q5', label: 'Дзвінки та відеозв\'язок Ірини Гайдук', ev: 'call_log' }, { id: 'q6', label: 'Пошта жертви', ev: 'expert_email' } ]}, { id: 'bio', name: 'Біометрія і криміналістика', queries: [ { id: 'q7', label: 'Смарт-годинник жертви', ev: 'watch_log' }, { id: 'q8', label: 'Повна токсикологія (ордер)', ev: 'tox_report', act: 2 }, { id: 'q9', label: 'Аналіз ДНК недопалка', ev: 'dna_match', act: 2 } ]}, { id: 'money', name: 'Фінанси і реєстри', queries: [ { id: 'q10', label: 'Транзакції Плюти: дороги та АЗС', ev: 'geo_toll' }, { id: 'q11', label: 'Заповіт і страховка', flavor: 'Нотаріус і страхова вимагають ордер. Ордер буде, коли доведете, що це вбивство: потрібні докази отруєння на дошці.' }, { id: 'q12', label: 'Банківські рахунки, пов\'язані з домом (ордер)', ev: 'bank_shell', act: 2 }, { id: 'q13', label: 'Простежити партію препарату', ev: 'pharma_log', act: 2 } ]} ], people: { stryzh: { name: 'Богдан Стриж', suspect: true, topics: [ { id: 't1', q: 'Де ви були вчора ввечері?', a: '«Пішов о 21:00 — камера підтвердить. О 21:30 вже був на вечері фонду „Меценат". Сотня свідків, детективе.» Відповідає гладко, як з каталогу.' }, { id: 't2', q: 'Що тепер буде з торгами?', a: '«Найбільші торги року. Віктор був знервований останній тиждень... Тепер усе на мені.» Скорботи в голосі — рівно нуль.' }, { id: 't3', q: 'У щоденнику: «Скасувати торги».', requires: ['diary'], a: '«Скасувати?! Вперше чую. У нас зобов\'язання перед клієнтами.» Різкий, як удар молотка. Занадто різкий.' }, { id: 't4', q: 'Гайдук просив експертку перевірити лоти 12–18.', requires: ['expert_email'], a: '«Рутинна перевірка провенансу. Ці лоти, до речі, готував я.» Поправляє годинник. Пальці не слухаються.' }, { id: 't5', q: 'Авто виїхало о 22:14. Пальто ви здали о 22:40.', requires: ['coatcheck', 'parking'], gives: 'stryzh_lie', a: 'Довга пауза. «...Гаразд. Я повертався за каталогами. Службовим входом, щоб охорона не бачила — не хотів розмов. Віктор був живий, сидів з коньяком. Це все, що я скажу без адвоката.»' } ]}, iryna: { name: 'Ірина Гайдук', suspect: true, topics: [ { id: 't6', q: 'Де ви були вчора ввечері?', a: '«Вдома. Дзвонила сестрі в Торонто, ми говорили години зо дві.» Дивиться у вікно, на дощ.' }, { id: 't7', q: 'Ваш шлюб. Страховка. Контракт.', a: '«Місто вже все порахувало, так? Ми десять років разом. Він був складний. Але мій.» Вперше за розмову — живий голос.' }, { id: 't8', q: 'Дзвінок підтверджено. Що ви не договорюєте?', requires: ['call_log'], a: 'Видихає. «Останній тиждень Віктор замикався з паперами. Одного вечора сказав: „Богдан думає, що я сліпий". Я тоді не зрозуміла. Тепер, здається, розумію.»' } ]}, dana: { name: 'Дана Гайдук', suspect: true, topics: [ { id: 't9', q: 'Що ви робите в залі?', a: '«Забираю речі батька. Маю право.» Тримає порожню теку так, наче там щось є.' }, { id: 't10', q: 'Ви не розмовляли два роки. Чому?', a: '«Він обрав дім. Аукціонний. Я не вписалась у каталог.» Сухо. Але руки тремтять.' }, { id: 't11', q: 'Камера: ви зайшли о 20:30 і вийшли о 21:12.', requires: ['lobby_cam'], gives: 'dana_confess', a: 'Мовчить. Потім: «Я взяла картину. Марчука, з малої зали. Батько обіцяв її мені ще до всього. Нагору я не піднімалась. Не змогла. Тепер уже й не зможу.»' } ]}, mazur: { name: 'Лесь Мазур', suspect: true, topics: [ { id: 't12', q: 'Де ви були вчора ввечері?', a: '«Стрім. Три години, п\'ятсот глядачів, реставрація наживо. Таке не змонтуєш, детективе — перевірте платформу.»' }, { id: 't13', q: 'Гайдук знищив вашу репутацію.', a: '«Назвав мою атрибуцію шахрайством. Публічно. І знаєте що? Він мав рацію — я тоді помилився. Його прокляттям було бачити підробки скрізь. Схоже, одного разу він подивився надто близько до дому.»' } ]}, pliuta: { name: 'Артем Плюта', suspect: true, topics: [ { id: 't14', q: 'Де ви були вчора ввечері?', a: '«Повертався з Одеси. Траса, чеки, платні дороги — усе в банківській виписці. Перевіряйте, я нікуди не поспішаю.»' }, { id: 't15', q: 'Гайдук продав вам підробку.', a: '«„Екстер" за триста тисяч, який малювали позавчора. Я подав до суду, детективе, а не в морг. Мертвий Гайдук мені суд не виграє.»' } ]}, semen: { name: 'Охоронець Семен', suspect: false, topics: [ { id: 't16', q: 'Хто заходив і виходив увечері?', gives: 'guard2', a: '«Пан Стриж вийшов о 21:03 головним, я записав. Дочка господаря ще була... Службовий вхід? Він на защіпці постійно, камери там нема — економлять. На паркінгу камери два тижні мертві, тільки шлагбаум лог пише.»' } ]}, olga: { name: 'Прибиральниця пані Ольга', suspect: false, topics: [ { id: 't17', q: 'Розкажіть про вчорашній вечір.', gives: 'cleaner_st', a: '«Графин я мила о сьомій, як завжди. Пан Віктор наливав перший келих о пів на десяту — ритуал, свята справа, хоч годинник звіряй. Келих біля мийки? Я його не мила і догори дном не ставила. Не мій почерк.»' } ]}, zoya: { name: 'Гардеробниця пані Зоя', suspect: false, topics: [ { id: 't18', q: 'Коли Стриж здав пальто?', gives: 'coatcheck', a: '«Десь після пів на одинадцяту. Точно після початку дощу — мокрий був наскрізь, аж з рукавів текло. А дощ учора почався рівно о десятій, я ще парасолю з дому не взяла.»' } ]} }, finale: { suspect: 'stryzh', method: 'digoxin', maxEvidence: 4, recap: 'Богдан Стриж роками продавав підробки через дім «Гайдук і Спадок», отримуючи мільйони через прокладку «Артконсалт-Гарант». Гайдук помітив, замовив таємну експертизу лотів 12–18 і зібрався скасувати торги. О 21:03 Стриж демонстративно вийшов головним входом — для камери. Повернувся службовими сходами, де немає камер, викуривши сигарилу під дверима. Розчинив дигоксин у графині, знаючи ритуал партнера: перший келих о пів на десяту. Вимив свій келих, забрав пляшечку ліків — хай виглядає як хворе серце. О 22:14 виїхав з паркінгу, о 22:40, мокрий від дощу, здав пальто на вечері, де «був з 21:30». Годинник на зап\'ясті жертви виявився чеснішим за некролог. Справу закрито.' } }; // Перевірка звинувачення. Повертає {ok, hint}. function checkAccusation(suspect, method, evs) { const has = id => evs.includes(id); if (suspect !== CASE.finale.suspect) return { ok: false, hint: 'Не сходиться сам підозрюваний: його місцеперебування на вечір смерті підтверджене доказами, які у вас є або які можна знайти. Кого докази виключають — той не вбивця.' }; if (method !== CASE.finale.method) return { ok: false, hint: 'Підозрюваний правильний, але спосіб суперечить біометрії та токсикології. ЩО саме вбило жертву і ДЕ це було розчинено?' }; if (!(has('blister') || has('pharma_log'))) return { ok: false, hint: 'Ланка «засіб» не доведена: потрібен доказ, що пов\'язує вбивцю з отрутою, а не лише отруту з жертвою.' }; if (!(has('stryzh_lie') || (has('coatcheck') && has('parking')))) return { ok: false, hint: 'Ланка «алібі» не зламана: потрібна суперечність із двох незалежних джерел — або зізнання. Один доказ тут завжди можна відбрехати.' }; if (!has('dna_match')) return { ok: false, hint: 'Ланка «доступ» не доведена: як вбивця потрапив у кабінет повз камери? Потрібен доказ його присутності на шляху без камер.' }; return { ok: true }; } if (typeof module !== 'undefined') module.exports = { CASE, checkAccusation };