'use strict'; /* ════════════════════════════════════════════════════════════════════ QualAnalysisSim — Качественный анализ катионов и анионов Режим 1: «Определить ион» (guided identification) Режим 2: «Неизвестное вещество» (drag-drop free experiment) ════════════════════════════════════════════════════════════════════ */ class QualAnalysisSim { /* ── Ion database ─────────────────────────────────────────────── */ static IONS = [ /* КАТИОНЫ */ { id: 'Na+', label: 'Na⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Пламя жёлтое', color: '#FFD700', type: 'flame', positive: true }, NaOH: { obs: 'Нет заметного осадка', color: null, type: 'none', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'K+', label: 'K⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Пламя фиолетовое (через синее стекло)', color: '#CC00FF', type: 'flame', positive: true }, NaOH: { obs: 'Нет осадка', color: null, type: 'none', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'NH4+', label: 'NH₄⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'При нагреве — газ NH₃↑ (запах, влажная лакмусовая бумага синеет)', color: '#CCFFCC', type: 'gas', gasLabel: 'NH₃↑', positive: true }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'Mg2+', label: 'Mg²⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Белый осадок Mg(OH)₂, не растворим в избытке NaOH', color: '#FFFFFF', type: 'precip', precipLabel: 'Mg(OH)₂↓', positive: true }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'Ca2+', label: 'Ca²⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Пламя кирпично-красное', color: '#CC4400', type: 'flame', positive: true }, NaOH: { obs: 'Слабый белый осадок Ca(OH)₂ (малорастворим)', color: '#EEEEEE', type: 'precip', precipLabel: 'Ca(OH)₂↓', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Белый осадок CaSO₄↓ (малорастворим)', color: '#FFFFFF', type: 'precip', precipLabel: 'CaSO₄↓', positive: true }, } }, { id: 'Ba2+', label: 'Ba²⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Пламя зелёное', color: '#00DD00', type: 'flame', positive: true }, NaOH: { obs: 'Белый осадок Ba(OH)₂', color: '#EEEEEE', type: 'precip', precipLabel: 'Ba(OH)₂↓', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Белый осадок BaSO₄↓, нерастворим в HNO₃', color: '#FFFFFF', type: 'precip', precipLabel: 'BaSO₄↓', positive: true }, } }, { id: 'Al3+', label: 'Al³⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Белый осадок Al(OH)₃↓, растворяется в избытке NaOH (амфотерность)', color: '#DDDDDD', type: 'precip', precipLabel: 'Al(OH)₃↓', positive: true, excess: 'Растворяется в избытке NaOH — амфотерность' }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'Fe2+', label: 'Fe²⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(100,160,80,0.25)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Зеленоватый осадок Fe(OH)₂↓', color: '#88BB66', type: 'precip', precipLabel: 'Fe(OH)₂↓', positive: true }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Слабое розовое окрашивание (следы Fe³⁺), не яркое', color: 'rgba(255,100,80,0.3)', type: 'solution', positive: false }, K3FeCN6: { obs: 'Синий осадок — Турнбулева синь (Fe₃[Fe(CN)₆]₂)', color: '#1144CC', type: 'precip', precipLabel: 'Турн. синь↓', positive: true }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'Fe3+', label: 'Fe³⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(200,100,30,0.3)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Бурый осадок Fe(OH)₃↓', color: '#884422', type: 'precip', precipLabel: 'Fe(OH)₃↓', positive: true }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Ярко-красный раствор — роданид железа(III)', color: '#DD1100', type: 'solution', positive: true }, K3FeCN6: { obs: 'Нет характерной реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции (осаждается NaOH)', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'Cu2+', label: 'Cu²⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(30,120,200,0.35)', reactions: { flame: { obs: 'Пламя зелёное (галогениды — синий)', color: '#00BB44', type: 'flame', positive: false }, NaOH: { obs: 'Голубой осадок Cu(OH)₂↓', color: '#5599FF', type: 'precip', precipLabel: 'Cu(OH)₂↓', positive: true }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет характерной реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Ярко-синий раствор комплекса [Cu(NH₃)₄]²⁺', color: '#0044EE', type: 'solution', positive: true }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'Ag+', label: 'Ag⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,255,0.1)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Коричневый осадок Ag₂O↓', color: '#886622', type: 'precip', precipLabel: 'Ag₂O↓', positive: false }, HCl: { obs: 'Белый творожистый осадок AgCl↓, темнеет на свету', color: '#DDDDDD', type: 'precip', precipLabel: 'AgCl↓', positive: true }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Белый осадок AgSCN↓', color: '#FFFFFF', type: 'precip', precipLabel: 'AgSCN↓', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Растворяется — комплекс [Ag(NH₃)₂]⁺', color: 'rgba(255,255,255,0.05)', type: 'solution', positive: true }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'Pb2+', label: 'Pb²⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(200,200,200,0.12)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Белый осадок Pb(OH)₂↓, растворим в избытке', color: '#EEEEEE', type: 'precip', precipLabel: 'Pb(OH)₂↓', positive: false }, HCl: { obs: 'Белый осадок PbCl₂↓', color: '#FFFFFF', type: 'precip', precipLabel: 'PbCl₂↓', positive: true }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Белый осадок PbSO₄↓', color: '#FFFFFF', type: 'precip', precipLabel: 'PbSO₄↓', positive: true }, } }, { id: 'Zn2+', label: 'Zn²⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Белый осадок Zn(OH)₂↓, растворяется в избытке NaOH (амфотерность)', color: '#EEEEEE', type: 'precip', precipLabel: 'Zn(OH)₂↓', positive: true, excess: 'Растворяется в избытке NaOH — амфотерность' }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Белый осадок Zn(OH)₂↓, растворяется в избытке — [Zn(NH₃)₄]²⁺', color: '#EEEEEE', type: 'precip', precipLabel: 'Zn(OH)₂↓', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'H+', label: 'H⁺', type: 'cat', group: 'Катионы', solColor: 'rgba(255,255,200,0.1)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нейтрализация. Лакмус синеет при добавлении щёлочи', color: 'rgba(255,255,255,0.08)', type: 'solution', positive: true }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нейтрализация: H⁺ + NH₃ → NH₄⁺', color: 'rgba(255,255,255,0.08)', type: 'solution', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, }, indicators: { litmus: 'красный', methylorange: 'красный', phenolphthalein: 'бесцветный' } }, { id: 'OH-', label: 'OH⁻', type: 'an', group: 'Анионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Нейтрализация, нет видимой реакции', color: 'rgba(255,255,255,0.08)', type: 'solution', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нейтрализация', color: 'rgba(255,255,255,0.08)', type: 'solution', positive: false }, }, indicators: { litmus: 'синий', methylorange: 'жёлтый', phenolphthalein: 'малиновый' } }, /* АНИОНЫ */ { id: 'Cl-', label: 'Cl⁻', type: 'an', group: 'Анионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Белый творожистый осадок AgCl↓, нерастворим в HNO₃', color: '#DDDDDD', type: 'precip', precipLabel: 'AgCl↓', positive: true }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'Br-', label: 'Br⁻', type: 'an', group: 'Анионы', solColor: 'rgba(180,80,0,0.15)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Желтоватый осадок AgBr↓', color: '#EEEE88', type: 'precip', precipLabel: 'AgBr↓', positive: true }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'I-', label: 'I⁻', type: 'an', group: 'Анионы', solColor: 'rgba(100,0,120,0.2)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Жёлтый осадок AgI↓, практически нерастворим в NH₃', color: '#FFEE44', type: 'precip', precipLabel: 'AgI↓', positive: true }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'SO42-', label: 'SO₄²⁻', type: 'an', group: 'Анионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Белый осадок BaSO₄↓, нерастворим в кислотах', color: '#FFFFFF', type: 'precip', precipLabel: 'BaSO₄↓', positive: true }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'SO32-', label: 'SO₃²⁻', type: 'an', group: 'Анионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Газ SO₂↑ — запах жжёной серы', color: '#FFFFAA', type: 'gas', gasLabel: 'SO₂↑', positive: true }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Белый осадок BaSO₃↓, растворяется в кислоте', color: '#FFFFFF', type: 'precip', precipLabel: 'BaSO₃↓', positive: true }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Газ SO₂↑ — запах жжёной серы', color: '#FFFFAA', type: 'gas', gasLabel: 'SO₂↑', positive: true }, } }, { id: 'CO32-', label: 'CO₃²⁻', type: 'an', group: 'Анионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Бурное выделение CO₂↑ (пузыри), мутит известковую воду Ca(OH)₂', color: '#FFFFFF', type: 'gas', gasLabel: 'CO₂↑', positive: true }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Белый осадок BaCO₃↓, растворяется в кислоте', color: '#FFFFFF', type: 'precip', precipLabel: 'BaCO₃↓', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Бурное выделение CO₂↑ (пузыри)', color: '#FFFFFF', type: 'gas', gasLabel: 'CO₂↑', positive: true }, } }, { id: 'NO3-', label: 'NO₃⁻', type: 'an', group: 'Анионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'При нагреве с Cu: бурый газ NO₂↑ («бурое кольцо» с FeSO₄)', color: '#DD8800', type: 'gas', gasLabel: 'NO₂↑', positive: true }, } }, { id: 'PO43-', label: 'PO₄³⁻', type: 'an', group: 'Анионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Жёлтый осадок Ag₃PO₄↓', color: '#EECC44', type: 'precip', precipLabel: 'Ag₃PO₄↓', positive: true }, BaCl2: { obs: 'Белый осадок Ba₃(PO₄)₂↓', color: '#FFFFFF', type: 'precip', precipLabel: 'Ba₃(PO₄)₂↓', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, } }, { id: 'S2-', label: 'S²⁻', type: 'an', group: 'Анионы', solColor: 'rgba(200,200,100,0.1)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Газ H₂S↑ — запах тухлых яиц', color: '#FFFF88', type: 'gas', gasLabel: 'H₂S↑', positive: true }, AgNO3: { obs: 'Чёрный осадок Ag₂S↓', color: '#111111', type: 'precip', precipLabel: 'Ag₂S↓', positive: true }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Газ H₂S↑ — запах тухлых яиц', color: '#FFFF88', type: 'gas', gasLabel: 'H₂S↑', positive: true }, } }, { id: 'CH3COO-', label: 'CH₃COO⁻', type: 'an', group: 'Анионы', solColor: 'rgba(255,255,255,0.08)', reactions: { flame: { obs: 'Нет характерного окрашивания', color: null, type: 'none', positive: false }, NaOH: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, HCl: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, AgNO3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, BaCl2: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, KSCN: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, K3FeCN6: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, NH3: { obs: 'Нет реакции', color: null, type: 'none', positive: false }, H2SO4: { obs: 'Запах уксуса; с FeCl₃ при нагреве — бурый осадок', color: '#AA6622', type: 'solution', positive: true }, } }, ]; static REAGENTS = [ { id: 'NaOH', label: 'NaOH', color: '#8866FF' }, { id: 'HCl', label: 'HCl', color: '#FF6644' }, { id: 'AgNO3', label: 'AgNO₃', color: '#CCCCCC' }, { id: 'BaCl2', label: 'BaCl₂', color: '#44BBFF' }, { id: 'KSCN', label: 'KSCN', color: '#FF4444' }, { id: 'K3FeCN6', label: 'K₃[Fe(CN)₆]', color: '#FFAA00' }, { id: 'NH3', label: 'NH₃', color: '#AAFFAA' }, { id: 'H2SO4', label: 'H₂SO₄', color: '#FFFF44' }, { id: 'flame', label: 'Пламя', color: '#FF8800' }, ]; /* ── constructor ─────────────────────────────────────────────── */ constructor(container) { this._container = container; this._mode = 'identify'; // 'identify' | 'unknown' this._targetIon = null; this._log = []; this._answered = false; this._dropAnim = []; this._precipParticles = []; this._gasParticles = []; this._raf = null; this._tubeState = { color: null, precipColor: null, precipH: 0, gasLabel: null, flameColor: null, solColor: 'rgba(100,180,255,0.18)' }; this._dragReagent = null; this._dragX = 0; this._dragY = 0; this._score = 0; this._lastT = 0; this._build(); this._bindEvents(); this._startMode('identify'); } /* ── DOM build ───────────────────────────────────────────────── */ _build() { this._container.innerHTML = ''; this._container.style.cssText = 'display:flex;flex-direction:column;height:100%;background:#0D0D1A;color:#E0E0FF;font-family:Manrope,sans-serif;overflow:hidden;user-select:none'; /* top toolbar */ const tb = document.createElement('div'); tb.style.cssText = 'display:flex;align-items:center;gap:8px;padding:8px 14px;border-bottom:1px solid rgba(255,255,255,0.08);flex-shrink:0;flex-wrap:wrap'; tb.innerHTML = `
Счёт: 0 `; this._container.appendChild(tb); /* main area */ const main = document.createElement('div'); main.style.cssText = 'display:flex;flex:1;min-height:0;overflow:hidden'; this._container.appendChild(main); /* left panel: log + reagents */ const left = document.createElement('div'); left.id = 'qa-left'; left.style.cssText = 'width:230px;display:flex;flex-direction:column;border-right:1px solid rgba(255,255,255,0.07);flex-shrink:0;overflow:hidden'; main.appendChild(left); /* reagent shelf */ const shelf = document.createElement('div'); shelf.id = 'qa-shelf'; shelf.style.cssText = 'padding:10px 8px 6px;border-bottom:1px solid rgba(255,255,255,0.07);flex-shrink:0'; shelf.innerHTML = '