speakid-build-a-sentence 1.0.22 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"speakid-build-a-sentence.es.js","sources":["../src/Game.styles.ts","../src/hooks/useValidation.ts","../src/utils/accessibility.ts","../src/Game.tsx","../src/components/ErrorBoundary.tsx"],"sourcesContent":["import { CSSProperties } from \"react\";\n\n// ===== Добавляем анимации в <head> =====\nconst keyframes = `\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n \n @keyframes pulse {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.05); }\n }\n \n @keyframes shake {\n 0%, 100% { transform: translateX(0); }\n 25% { transform: translateX(-5px); }\n 75% { transform: translateX(5px); }\n }\n \n @keyframes slideIn {\n from { transform: translateY(-20px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes bounce {\n 0%, 20%, 53%, 80%, 100% { transform: translate3d(0,0,0); }\n 40%, 43% { transform: translate3d(0, -8px, 0); }\n 70% { transform: translate3d(0, -4px, 0); }\n 90% { transform: translate3d(0, -2px, 0); }\n }\n \n @keyframes glow {\n 0%, 100% { box-shadow: 0 0 5px rgba(76, 175, 80, 0.5); }\n 50% { box-shadow: 0 0 20px rgba(76, 175, 80, 0.8), 0 0 30px rgba(76, 175, 80, 0.6); }\n }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"game-keyframes\")) {\n const styleTag = document.createElement(\"style\");\n styleTag.id = \"game-keyframes\";\n styleTag.innerHTML = keyframes;\n document.head.appendChild(styleTag);\n}\n\n// ===== Анимации =====\nconst animations = {\n spin: {\n animation: \"spin 1.4s linear infinite\",\n },\n pulse: {\n animation: \"pulse 0.6s ease-in-out\",\n },\n shake: {\n animation: \"shake 0.4s ease-in-out\",\n },\n slideIn: {\n animation: \"slideIn 0.3s ease-out\",\n },\n bounce: {\n animation: \"bounce 0.6s ease-in-out\",\n },\n glow: {\n animation: \"glow 1s ease-in-out infinite\",\n },\n};\n\n// ===== Основные стили =====\nexport const styles: Record<string, CSSProperties> = {\n gmCenterScreen: {\n position: \"relative\",\n zIndex: 1,\n // use percent so the component fits inside the centered square container\n // (100vh caused overflow on tablets because it measured the viewport, not the container)\n minHeight: \"100%\",\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n textAlign: \"center\",\n color: \"#1f2937\",\n padding: \"24px 16px\",\n boxSizing: \"border-box\",\n transform: \"translateY(20px)\", // чуть вниз, чтобы компенсировать логотип\n },\n\n gmHeadline1: {\n fontWeight: 700,\n fontSize: \"clamp(28px, 4vw, 40px)\",\n lineHeight: \"110%\",\n },\n\n gmHeadline2: {\n fontWeight: 600,\n fontSize: \"24px\",\n lineHeight: \"120%\",\n },\n\n gmHeadline3: {\n fontWeight: 600,\n fontSize: \"18px\",\n lineHeight: \"130%\",\n },\n\n gmBodyL: {\n fontWeight: 400,\n fontSize: \"18px\",\n lineHeight: \"140%\",\n },\n\n gmBodyM: {\n fontWeight: 400,\n fontSize: \"16px\",\n lineHeight: \"140%\",\n },\n\n gmBodyS: {\n fontWeight: 400,\n fontSize: \"14px\",\n lineHeight: \"140%\",\n color: \"#6b7280\",\n },\n\n gmButton: {\n fontFamily:\n '\"Geist\", system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, \"Noto Sans\"',\n fontWeight: 600,\n fontSize: \"16px\",\n padding: \"10px 16px\",\n borderRadius: \"12px\",\n border: \"1px solid #e5e7eb\",\n background: \"#ec4c44\",\n color: \"#ffffff\",\n cursor: \"pointer\",\n boxShadow: \"0 6px 18px rgba(236, 76, 68, .18)\",\n transition:\n \"transform .06s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease\",\n },\n\n gmButtonActive: {\n background: \"#333\",\n color: \"#fff\",\n },\n\n gmGameLayout: {\n position: \"relative\",\n width: \"100%\",\n // allow the layout to expand within the square container for tablets/laptops\n maxWidth: \"none\",\n // should fill the parent square, not the full viewport\n minHeight: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n textAlign: \"center\",\n color: \"#1f2937\",\n padding: \"16px 8px\",\n margin: \"0 auto\",\n },\n\n gmGrid: {\n width: \"100%\",\n // let the grid use all available space; sizing is controlled in Game.tsx\n maxWidth: \"none\",\n margin: \"0 auto\",\n display: \"grid\",\n // defaults; overridden responsively in Game.tsx\n gridTemplateColumns: \"repeat(3, 210px)\",\n gridAutoRows: \"210px\",\n gap: \"20px\",\n justifyContent: \"center\",\n },\n\n gmCard: {\n border: \"1px solid #e5e7eb\",\n borderRadius: \"16px\",\n background: \"#f9f9f9\",\n aspectRatio: \"1 / 1\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n overflow: \"hidden\",\n transition:\n \"transform .2s ease, box-shadow .2s ease, border-color .2s ease\",\n },\n\n gmCorrect: {\n border: \"2px solid #10b981\",\n boxShadow: \"0 0 18px rgba(16,185,129,.45)\",\n background: \"#ecfdf5\",\n },\n\n gmWrong: {\n border: \"2px solid #ec4c44\",\n boxShadow: \"0 0 18px rgba(236,76,68,.35)\",\n background: \"#fef2f2\",\n },\n\n gmInput: {\n padding: \"6px 10px\",\n borderRadius: \"6px\",\n border: \"1px solid #ccc\",\n fontSize: \"16px\",\n fontFamily: '\"Geist\", system-ui',\n width: \"160px\",\n },\n\n gmTable: {\n marginTop: \"20px\",\n marginBottom: \"32px\",\n borderCollapse: \"collapse\",\n width: \"100%\",\n maxWidth: \"520px\",\n tableLayout: \"fixed\",\n textAlign: \"center\",\n },\n\n gmTableCell: {\n padding: \"8px 12px\",\n borderBottom: \"1px solid #e5e7eb\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n },\n\n // ✅ Обновлено только для качества логотипа (размер как в whats-missing)\n gmLogoFixed: {\n position: \"absolute\",\n top: \"16px\",\n left: \"16px\",\n width: \"auto\",\n zIndex: 10,\n pointerEvents: \"none\",\n background: \"transparent\",\n transform: \"none\",\n willChange: \"auto\",\n },\n\n gmLogoImg: {\n height: \"28px\",\n width: \"auto\",\n background: \"transparent\",\n objectFit: \"contain\",\n imageRendering: \"auto\",\n transform: \"translateZ(0)\",\n backfaceVisibility: \"hidden\",\n WebkitFontSmoothing: \"antialiased\",\n display: \"block\",\n },\n\n gmLogoFallback: {\n height: \"28px\",\n width: \"auto\",\n background: \"transparent\",\n color: \"#ec4c44\",\n fontSize: \"16px\",\n fontWeight: 700,\n display: \"block\",\n },\n\n gmReadyWrapper: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n // use percent so the wrapper scales with the container square\n height: \"60%\",\n gap: \"16px\",\n },\n\n gmHourglass: {\n fontSize: \"42px\",\n ...animations.spin,\n },\n\n // ===== Анимационные стили =====\n ...animations,\n};\n","import { useState, useCallback } from 'react';\n\nexport interface ValidationError {\n type: 'length' | 'characters' | 'empty' | 'duplicate';\n message: string;\n}\n\nexport interface ValidationResult {\n isValid: boolean;\n errors: ValidationError[];\n}\n\nexport const useValidation = () => {\n const [errors, setErrors] = useState<ValidationError[]>([]);\n\n const validateSentence = useCallback((sentence: string, index: number, allSentences: string[]): ValidationResult => {\n const newErrors: ValidationError[] = [];\n\n // Проверка на пустоту\n if (!sentence.trim()) {\n newErrors.push({\n type: 'empty',\n message: 'Sentence cannot be empty'\n });\n }\n\n // Проверка длины\n if (sentence.length > 41) {\n newErrors.push({\n type: 'length',\n message: `Sentence is too long (${sentence.length}/41 characters)`\n });\n }\n\n // Проверка символов (только латиница)\n const latinRegex = /^[a-zA-Z0-9\\s.,!?;:'\"-]*$/;\n if (sentence && !latinRegex.test(sentence)) {\n newErrors.push({\n type: 'characters',\n message: 'Only Latin characters, numbers, spaces and punctuation are allowed'\n });\n }\n\n // Проверка на дубликаты\n const duplicateIndex = allSentences.findIndex((s, i) => i !== index && s.toLowerCase().trim() === sentence.toLowerCase().trim());\n if (duplicateIndex !== -1) {\n newErrors.push({\n type: 'duplicate',\n message: `Duplicate sentence (same as sentence ${duplicateIndex + 1})`\n });\n }\n\n setErrors(newErrors);\n return {\n isValid: newErrors.length === 0,\n errors: newErrors\n };\n }, []);\n\n const validateAllSentences = useCallback((sentences: string[]): ValidationResult => {\n const allErrors: ValidationError[] = [];\n \n sentences.forEach((sentence, index) => {\n const result = validateSentence(sentence, index, sentences);\n allErrors.push(...result.errors.map(error => ({\n ...error,\n message: `Sentence ${index + 1}: ${error.message}`\n })));\n });\n\n return {\n isValid: allErrors.length === 0,\n errors: allErrors\n };\n }, [validateSentence]);\n\n const clearErrors = useCallback(() => {\n setErrors([]);\n }, []);\n\n return {\n errors,\n validateSentence,\n validateAllSentences,\n clearErrors,\n };\n};\n\n","// Утилиты для улучшения доступности\n\nexport const createAriaLabel = (action: string, word?: string, context?: string): string => {\n if (word && context) {\n return `${action} word \"${word}\" ${context}`;\n }\n if (word) {\n return `${action} word \"${word}\"`;\n }\n return action;\n};\n\nexport const getRoleForElement = (type: 'button' | 'draggable' | 'droppable' | 'input'): string => {\n const roles = {\n button: 'button',\n draggable: 'button',\n droppable: 'region',\n input: 'textbox'\n };\n return roles[type];\n};\n\nexport const handleKeyDown = (\n event: React.KeyboardEvent,\n action: () => void,\n allowedKeys: string[] = ['Enter', ' ']\n) => {\n if (allowedKeys.includes(event.key)) {\n event.preventDefault();\n action();\n }\n};\n\nexport const announceToScreenReader = (message: string) => {\n // Создаем временный элемент для объявления\n const announcement = document.createElement('div');\n announcement.setAttribute('aria-live', 'polite');\n announcement.setAttribute('aria-atomic', 'true');\n announcement.style.position = 'absolute';\n announcement.style.left = '-10000px';\n announcement.style.width = '1px';\n announcement.style.height = '1px';\n announcement.style.overflow = 'hidden';\n \n document.body.appendChild(announcement);\n announcement.textContent = message;\n \n // Удаляем элемент после объявления\n setTimeout(() => {\n document.body.removeChild(announcement);\n }, 1000);\n};\n\nexport const getFocusableElements = (container: HTMLElement): HTMLElement[] => {\n const focusableSelectors = [\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[role=\"button\"]:not([disabled])'\n ].join(', ');\n \n return Array.from(container.querySelectorAll(focusableSelectors));\n};\n\nexport const trapFocus = (container: HTMLElement) => {\n const focusableElements = getFocusableElements(container);\n \n if (focusableElements.length === 0) return;\n \n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n \n const handleTabKey = (e: KeyboardEvent) => {\n if (e.key === 'Tab') {\n if (e.shiftKey) {\n if (document.activeElement === firstElement) {\n lastElement.focus();\n e.preventDefault();\n }\n } else {\n if (document.activeElement === lastElement) {\n firstElement.focus();\n e.preventDefault();\n }\n }\n }\n };\n \n container.addEventListener('keydown', handleTabKey);\n \n // Фокусируем первый элемент\n firstElement.focus();\n \n // Возвращаем функцию для очистки\n return () => {\n container.removeEventListener('keydown', handleTabKey);\n };\n};\n\n","// ======================\n// MAGIC SENTENCE GAME (SPEAKID)\n// React 18 + TypeScript + Vite\n// Адаптивная верстка для всех устройств\n// ======================\n\nimport * as React from \"react\";\nimport { useState, useEffect, useRef, useMemo } from \"react\";\nimport { styles } from \"./Game.styles\";\nimport { ErrorBoundary } from \"./components/ErrorBoundary\";\nimport { useValidation } from \"./hooks/useValidation\";\nimport { createAriaLabel, handleKeyDown, announceToScreenReader } from \"./utils/accessibility\";\n\ntype Stage = \"select\" | \"time\" | \"type\" | \"getready\" | \"play\" | \"results\";\ntype Token = { id: string; text: string };\n\n// ✅ базовый reset\nconst globalReset = () => {\n const style = document.createElement(\"style\");\n style.id = \"magic-sentence-reset\"; // ✅ Добавляем ID для удаления\n \n style.textContent = `\n #magic-sentence-root, #magic-sentence-root * {\n box-sizing: border-box;\n font-family: \"Geist\", system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, sans-serif;\n }\n #magic-sentence-root img {\n max-width: 100%;\n height: auto;\n display: block;\n user-select: none;\n }\n html, body {\n margin: 0 !important;\n padding: 0 !important;\n width: 100% !important;\n height: 100% !important;\n overflow: hidden !important;\n zoom: 1 !important; /* ✅ защита от подзума */\n }\n #root {\n margin: 0 !important;\n padding: 0 !important;\n width: 100% !important;\n height: 100% !important;\n overflow: hidden !important;\n }\n `;\n \n // ✅ Удаляем старый стиль, если он есть\n const existingStyle = document.getElementById(\"magic-sentence-reset\");\n if (existingStyle) {\n existingStyle.remove();\n }\n \n document.head.appendChild(style);\n};\n\nconst shuffle = (arr: string[]) => [...arr].sort(() => Math.random() - 0.5);\n\nexport interface GameProps {\n logoUrl?: string;\n showLogo?: boolean;\n}\n\nfunction GameComponent(props: GameProps = {}) {\n const { logoUrl, showLogo = true } = props;\n const containerRef = useRef<HTMLDivElement>(null);\n \n // Новые хуки\n const { validateAllSentences, errors: validationErrors } = useValidation();\n\n // Функция для определения нужно ли переносить слова\n const shouldWrapWords = () => {\n // Переносим слова на всех мобильных устройствах\n return isMobile || window.innerWidth < 768;\n };\n\n // Универсальная функция для определения мобильных устройств\n const isMobileDevice = () => {\n return isMobile || \n window.innerWidth < 768 || \n (window.innerWidth >= 320 && window.innerWidth <= 932 && window.innerHeight >= 390 && window.innerHeight <= 932);\n };\n\n // Вспомогательная функция для мобильных размеров кнопок\n const getMobileButtonStyles = (type: 'small' | 'medium' | 'large' = 'medium') => {\n if (!isMobileDevice()) {\n return {\n padding: \"12px 24px\",\n fontSize: \"16px\",\n minWidth: \"auto\"\n };\n }\n\n switch (type) {\n case 'small':\n return {\n padding: \"4px 6px\",\n fontSize: \"9px\",\n minWidth: \"40px\"\n };\n case 'medium':\n return {\n padding: \"5px 8px\",\n fontSize: \"10px\",\n minWidth: \"50px\"\n };\n case 'large':\n return {\n padding: \"6px 10px\",\n fontSize: \"11px\",\n minWidth: \"60px\"\n };\n }\n };\n\n useEffect(() => {\n globalReset();\n return () => {\n // ✅ Восстанавливаем overflow на html и body\n document.documentElement.style.overflow = \"\";\n document.body.style.overflow = \"\";\n \n // ✅ Удаляем наш style элемент\n const style = document.getElementById(\"magic-sentence-reset\");\n if (style) {\n style.remove();\n }\n };\n }, []);\n\n const [stage, setStage] = useState<Stage>(\"select\");\n const [rounds, setRounds] = useState<number | null>(null);\n const [timePerRound, setTimePerRound] = useState<number | null>(null);\n const [sentences, setSentences] = useState<string[]>([]);\n const [currentRound, setCurrentRound] = useState(0);\n const [words, setWords] = useState<Token[]>([]);\n const [selected, setSelected] = useState<Token[]>([]);\n const [timeLeft, setTimeLeft] = useState(20);\n const [score, setScore] = useState(0);\n const [countdown, setCountdown] = useState<number | null>(null);\n const [resultType, setResultType] = useState<\"correct\" | \"almost\" | \"wrong\" | null>(null);\n const [timeExpired, setTimeExpired] = useState(false);\n const [isCorrect, setIsCorrect] = useState(false);\n const [bestScore, setBestScore] = useState<number>(\n Number(localStorage.getItem(\"magicSentenceBest\")) || 0\n );\n const timerRef = useRef<number | null>(null);\n const roundsRef = useRef<number | null>(null);\n const currentRoundRef = useRef<number>(0);\n const [hover, setHover] = useState<{ list: ListName | null; id: string | null; side: \"left\" | \"right\" | null }>({ list: null, id: null, side: null });\n\n // Адаптивность\n const [isMobile, setIsMobile] = useState(false);\n const [scale, setScale] = useState(1);\n const [containerSize, setContainerSize] = useState<number | null>(null);\n const [isDesktopLayout, setIsDesktopLayout] = useState(false);\n const [isIPadMiniPortrait, setIsIPadMiniPortrait] = useState(false);\n const [isIPadMiniLandscape, setIsIPadMiniLandscape] = useState(false);\n const [isIPadAirPortrait, setIsIPadAirPortrait] = useState(false);\n const [isIPadAirLandscape, setIsIPadAirLandscape] = useState(false);\n const [isSurfaceDuoPortrait, setIsSurfaceDuoPortrait] = useState(false);\n const [isSurfaceDuoLandscape, setIsSurfaceDuoLandscape] = useState(false);\n const [isIPadProPortrait, setIsIPadProPortrait] = useState(false);\n const [isIPadProLandscape, setIsIPadProLandscape] = useState(false);\n const [isHorizontalLayout, setIsHorizontalLayout] = useState(false);\n const [isWideScreen, setIsWideScreen] = useState(false);\n\n // ✅ адаптив под мобилки, планшеты и десктоп\n useEffect(() => {\n const resize = () => {\n const width = window.innerWidth;\n const height = window.innerHeight;\n const mobile = width < 768 || (width === 926 && height === 428) || (width === 932 && height === 430);\n const isLandscape = (width > height && mobile) || (width === 926 && height === 428) || (width === 932 && height === 430);\n const isSmallHeight = height < 700;\n const isWideScreen = width / height > 1.8; // ✅ Широкие экраны\n \n // iPad размеры\n const isIPadMiniPortrait = width === 768 && height === 1024;\n const isIPadMiniLandscape = width === 1024 && height === 768;\n const isIPadAirPortrait = width === 820 && height === 1180;\n const isIPadAirLandscape = width === 1180 && height === 820;\n \n // Surface DUO размеры\n const isSurfaceDuoPortrait = width === 540 && height === 720;\n const isSurfaceDuoLandscape = width === 720 && height === 540;\n \n // iPad Pro размеры\n const isIPadProPortrait = width === 1024 && height === 1366;\n const isIPadProLandscape = width === 1366 && height === 1024;\n \n // Десктопные разрешения\n const desktopLayout = width >= 1200 && height >= 600 && !mobile;\n setIsDesktopLayout(desktopLayout);\n \n // Установка состояний для iPad и Surface DUO\n setIsIPadMiniPortrait(isIPadMiniPortrait);\n setIsIPadMiniLandscape(isIPadMiniLandscape);\n setIsIPadAirPortrait(isIPadAirPortrait);\n setIsIPadAirLandscape(isIPadAirLandscape);\n setIsSurfaceDuoPortrait(isSurfaceDuoPortrait);\n setIsSurfaceDuoLandscape(isSurfaceDuoLandscape);\n setIsIPadProPortrait(isIPadProPortrait);\n setIsIPadProLandscape(isIPadProLandscape);\n setIsWideScreen(isWideScreen); // ✅ Сохраняем состояние для широких экранов\n \n // ✅ Вычисляем горизонтальный layout ОДИН РАЗ\n const isHorizontal = \n (mobile && width > height) || \n mobile || // ✅ ВСЕ мобильные устройства (включая portrait)\n height < 700 || \n isWideScreen || // ✅ Широкие экраны\n (width === 1366 && height === 766) || \n (width === 1366 && height === 768) || \n (width === 1280 && height === 720) || \n (width === 1440 && height === 900) || \n isIPadMiniPortrait || \n isIPadMiniLandscape || \n isIPadAirPortrait || \n isIPadAirLandscape || \n isSurfaceDuoPortrait || \n isSurfaceDuoLandscape || \n isIPadProPortrait || \n isIPadProLandscape || \n desktopLayout;\n setIsHorizontalLayout(isHorizontal);\n \n setIsMobile(mobile);\n\n // ✅ Адаптивные размеры контейнера\n if (mobile) {\n setContainerSize(null);\n setScale(1);\n } else if (isSmallHeight) {\n setContainerSize(null);\n setScale(1);\n } else if (isWideScreen) {\n // ✅ Широкие экраны: используем стандартный размер но уменьшаем масштаб\n const minSize = 400;\n const maxSize = 1200;\n const finalSize = Math.min(1000, Math.min(width, height) * 0.9);\n setContainerSize(finalSize);\n setScale(0.85); // Уменьшаем масштаб на 15%\n } else {\n const minSize = 400;\n const maxSize = 1200;\n const finalSize = Math.min(1000, Math.min(width, height) * 0.9);\n setContainerSize(finalSize);\n setScale(1);\n }\n };\n resize();\n window.addEventListener(\"resize\", resize);\n return () => window.removeEventListener(\"resize\", resize);\n }, []);\n\n // =========================\n // DND HELPERS\n // =========================\n type ListName = \"bank\" | \"selected\";\n type DragPayload = { from: ListName; id: string };\n\n const moveToken = (\n from: ListName,\n to: ListName,\n id: string,\n insertIndex: number | null\n ) => {\n // Блокируем перемещение если время истекло\n if (timeExpired) return;\n\n let nextWords = [...words];\n let nextSelected = [...selected];\n\n const takeFrom = from === \"bank\" ? nextWords : nextSelected;\n const putTo = to === \"bank\" ? nextWords : nextSelected;\n\n const idx = takeFrom.findIndex((t) => t.id === id);\n if (idx === -1) return;\n const [token] = takeFrom.splice(idx, 1);\n\n let targetIndex = insertIndex;\n if (\n from === to &&\n targetIndex !== null &&\n targetIndex !== undefined\n ) {\n if (targetIndex > idx) targetIndex = targetIndex - 1;\n }\n\n if (\n targetIndex === null ||\n targetIndex === undefined ||\n targetIndex < 0 ||\n targetIndex > putTo.length\n ) {\n putTo.push(token);\n } else {\n putTo.splice(targetIndex, 0, token);\n }\n\n if (from === \"bank\") nextWords = takeFrom; else nextSelected = takeFrom;\n if (to === \"bank\") nextWords = putTo; else nextSelected = putTo;\n\n setWords(nextWords);\n setSelected(nextSelected);\n };\n\n const handleDropTo = (\n e: React.DragEvent,\n to: ListName,\n insertIndex: number | null\n ) => {\n e.preventDefault();\n \n // Блокируем drop если время истекло\n if (timeExpired) {\n setHover({ list: null, id: null, side: null });\n return;\n }\n\n const raw = e.dataTransfer.getData(\"application/x-token\") ||\n (() => {\n const fallbackId = e.dataTransfer.getData(\"text/plain\");\n if (!fallbackId) return \"\";\n const inBank = words.some((t) => t.id === fallbackId);\n const inSelected = selected.some((t) => t.id === fallbackId);\n const from: ListName | null = inBank ? \"bank\" : inSelected ? \"selected\" : null;\n return from ? JSON.stringify({ from, id: fallbackId }) : \"\";\n })();\n if (!raw) return;\n try {\n const payload = JSON.parse(raw) as DragPayload;\n if (!payload || !payload.id || !payload.from) return;\n moveToken(payload.from, to, payload.id, insertIndex);\n } catch {\n // ignore bad payload\n }\n setHover({ list: null, id: null, side: null });\n };\n\n // =========================\n // START / SETUP\n // =========================\n const handleSelect = (num: number) => {\n setRounds(num);\n roundsRef.current = num;\n setSentences(Array(num).fill(\"\"));\n setStage(\"time\");\n };\n\n const handleTimeSelect = (time: number) => {\n setTimePerRound(time);\n setStage(\"type\");\n };\n\n const handleChange = (index: number, value: string) => {\n // Ограничение на 41 символ (включая пробелы и точку)\n if (value.length > 41) {\n return;\n }\n \n // Проверка на латинские символы (a-z, A-Z, пробелы, цифры, знаки препинания)\n const latinRegex = /^[a-zA-Z0-9\\s.,!?;:'\"-]*$/;\n if (value && !latinRegex.test(value)) {\n return; // Не сохраняем, если есть нелатинские символы\n }\n \n const updated = [...sentences];\n updated[index] = value;\n setSentences(updated);\n \n // Валидация при вводе\n const validation = validateAllSentences(updated);\n if (!validation.isValid) {\n console.warn('Validation errors:', validation.errors);\n }\n };\n\n const normalizeSentence = (s: string) => s.trim().replace(/\\s+/g, \" \");\n\n // Адаптивный размер шрифта в зависимости от количества слов\n const getAdaptiveFontSize = (wordCount: number) => {\n if (wordCount <= 3) return 20;\n if (wordCount <= 5) return 18;\n if (wordCount <= 7) return 16;\n if (wordCount <= 9) return 14;\n return 12;\n };\n\n const startGame = () => {\n const hasEmpty = sentences.some((s) => s.trim().length === 0);\n if (hasEmpty) {\n return;\n }\n setSentences((prev) => prev.map((s) => normalizeSentence(s)));\n setScore(0);\n setCurrentRound(0);\n currentRoundRef.current = 0;\n setCountdown(null); // Убираем цифровой отсчет\n setStage(\"getready\");\n };\n\n useEffect(() => {\n if (stage === \"getready\") {\n const t = setTimeout(() => startRound(0), 3000);\n return () => clearTimeout(t);\n }\n }, [stage]);\n\n const startRound = (index: number) => {\n const target = sentences[index];\n if (!target) return;\n const shuffled = shuffle(target\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n );\n const tokens: Token[] = shuffled.map((w, i) => ({\n id: `${Date.now()}-${index}-${i}-${Math.random().toString(36).slice(2)}`,\n text: w,\n }));\n setWords(tokens);\n setSelected([]);\n setCurrentRound(index);\n currentRoundRef.current = index;\n setTimeLeft(timePerRound || 20); // Используем выбранное время\n setResultType(null); // Сбрасываем результат\n setTimeExpired(false); // Сбрасываем состояние истечения времени\n setIsCorrect(false); // Сбрасываем флаг правильного ответа\n setStage(\"play\");\n };\n\n const autoCheckTimeoutRef = useRef<number | null>(null);\n \n useEffect(() => {\n if (stage !== \"play\" || timeExpired) {\n if (autoCheckTimeoutRef.current !== null) {\n window.clearTimeout(autoCheckTimeoutRef.current);\n autoCheckTimeoutRef.current = null;\n }\n return;\n }\n\n const correct = sentences[currentRound];\n if (!correct) {\n setResultType(null);\n if (autoCheckTimeoutRef.current !== null) {\n window.clearTimeout(autoCheckTimeoutRef.current);\n autoCheckTimeoutRef.current = null;\n }\n return;\n }\n\n if (selected.length === 0) {\n setResultType(null);\n if (autoCheckTimeoutRef.current !== null) {\n window.clearTimeout(autoCheckTimeoutRef.current);\n autoCheckTimeoutRef.current = null;\n }\n return;\n }\n\n const correctWords = correct.trim().split(/\\s+/);\n const selectedTexts = selected.map((t) => t.text);\n\n const isSentenceCorrect = \n selectedTexts.length === correctWords.length &&\n selectedTexts.every((word, idx) => word === correctWords[idx]);\n\n if (isSentenceCorrect) {\n // Сразу показываем зеленый, если правильно\n if (autoCheckTimeoutRef.current !== null) {\n window.clearTimeout(autoCheckTimeoutRef.current);\n autoCheckTimeoutRef.current = null;\n }\n setResultType(\"correct\");\n if (!isCorrect) {\n setIsCorrect(true);\n setScore((s) => s + 1);\n playSound(\"correct\");\n announceToScreenReader(\"Correct! Well done!\");\n }\n } else {\n // Показываем ошибку только когда выбрано столько же или больше слов, чем в правильном ответе\n // Это означает, что пользователь \"закончил\" собирать предложение\n if (selectedTexts.length >= correctWords.length) {\n // Предложение \"завершено\" - показываем ошибку\n if (autoCheckTimeoutRef.current !== null) {\n window.clearTimeout(autoCheckTimeoutRef.current);\n autoCheckTimeoutRef.current = null;\n }\n \n const missingWords = correctWords.filter(word => !selectedTexts.includes(word)).length;\n const extraWords = selectedTexts.filter(word => !correctWords.includes(word)).length;\n const wrongOrder = correctWords.filter((w, i) => w !== selectedTexts[i]).length;\n const errors = missingWords + extraWords + wrongOrder;\n\n if (errors === 1) {\n setResultType(\"almost\");\n } else {\n setResultType(\"wrong\");\n }\n if (isCorrect) {\n setIsCorrect(false);\n setScore((s) => Math.max(0, s - 1));\n }\n } else {\n // Еще не выбрано достаточно слов - сбрасываем результат (не показываем ошибку)\n setResultType(null);\n if (autoCheckTimeoutRef.current !== null) {\n window.clearTimeout(autoCheckTimeoutRef.current);\n autoCheckTimeoutRef.current = null;\n }\n }\n }\n\n return () => {\n if (autoCheckTimeoutRef.current !== null) {\n window.clearTimeout(autoCheckTimeoutRef.current);\n autoCheckTimeoutRef.current = null;\n }\n };\n }, [stage, selected, sentences, currentRound, timeExpired, resultType, isCorrect, rounds]);\n\n // TIMER\n useEffect(() => {\n if (stage === \"play\" && !timeExpired) {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n if (timeLeft > 0) {\n timerRef.current = window.setTimeout(() => setTimeLeft((t) => t - 1), 1000);\n } else {\n // Время истекло - всегда проверяем предложение\n setTimeExpired(true);\n const correct = sentences[currentRound];\n if (!correct) {\n setResultType(null);\n return;\n }\n\n const correctWords = correct.trim().split(/\\s+/);\n const selectedTexts = selected.map((t) => t.text);\n \n // Всегда считаем ошибки, даже если выбрано меньше слов\n // Считаем ошибки: недостающие слова + лишние слова + неправильный порядок\n const missingWords = correctWords.filter(word => !selectedTexts.includes(word)).length;\n const extraWords = selectedTexts.filter(word => !correctWords.includes(word)).length;\n const wrongOrder = correctWords.filter((w, i) => w !== selectedTexts[i]).length;\n \n // Общее количество ошибок = недостающие + лишние + неправильный порядок\n const errors = missingWords + extraWords + wrongOrder;\n\n // Показываем результат и засчитываем очки\n if (errors === 0) {\n setResultType(\"correct\");\n if (!isCorrect) {\n setIsCorrect(true);\n setScore((s) => s + 1);\n }\n playSound(\"correct\");\n announceToScreenReader(\"Correct! Well done!\");\n } else if (errors === 1) {\n setResultType(\"almost\");\n setScore((s) => s + 0.5);\n playSound(\"half\");\n announceToScreenReader(\"Almost correct! Just one mistake.\");\n } else {\n setResultType(\"wrong\");\n playSound(\"wrong\");\n announceToScreenReader(\"Not quite right. Keep trying!\");\n }\n }\n }\n return () => {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n };\n }, [stage, timeLeft, timeExpired, sentences, currentRound, selected, isCorrect]);\n\n // =========================\n // SCORING / NEXT ROUND\n // =========================\n const handleNext = (manual = true) => {\n // Если это ручное нажатие NEXT\n if (manual) {\n // Если время уже истекло, проверка уже была выполнена в TIMER\n // Просто переходим к следующему раунду\n if (timeExpired) {\n if (currentRound + 1 < (rounds || 0)) {\n startRound(currentRound + 1);\n } else {\n setStage(\"results\");\n setTimeout(() => triggerConfetti(), 600);\n }\n return;\n }\n\n // Если время не истекло, проверяем предложение вручную\n const correct = sentences[currentRound];\n if (!correct) {\n // Если нет правильного предложения, просто переходим дальше\n if (currentRound + 1 < (rounds || 0)) {\n startRound(currentRound + 1);\n } else {\n setStage(\"results\");\n setTimeout(() => triggerConfetti(), 600);\n }\n return;\n }\n\n const correctWords = correct.trim().split(/\\s+/);\n const selectedTexts = selected.map((t) => t.text);\n \n // Всегда считаем ошибки, даже если выбрано меньше слов\n // Считаем ошибки: недостающие слова + лишние слова + неправильный порядок\n const missingWords = correctWords.filter(word => !selectedTexts.includes(word)).length;\n const extraWords = selectedTexts.filter(word => !correctWords.includes(word)).length;\n const wrongOrder = correctWords.filter((w, i) => w !== selectedTexts[i]).length;\n \n // Общее количество ошибок = недостающие + лишние + неправильный порядок\n const errors = missingWords + extraWords + wrongOrder;\n\n // Устанавливаем результат проверки и засчитываем очки\n if (errors === 0) {\n setScore((s) => s + 1);\n setResultType(\"correct\");\n setIsCorrect(true);\n playSound(\"correct\");\n announceToScreenReader(\"Correct! Well done!\");\n } else if (errors === 1) {\n setScore((s) => s + 0.5);\n setResultType(\"almost\");\n playSound(\"half\");\n announceToScreenReader(\"Almost correct! Just one mistake.\");\n } else {\n setResultType(\"wrong\");\n playSound(\"wrong\");\n announceToScreenReader(\"Not quite right. Keep trying!\");\n }\n\n // Переходим к следующему раунду после проверки\n if (currentRound + 1 < (rounds || 0)) {\n setTimeout(() => startRound(currentRound + 1), 800);\n } else {\n setTimeout(() => {\n setStage(\"results\");\n setTimeout(() => triggerConfetti(), 600);\n }, 800);\n }\n }\n };\n\n // =========================\n // SAVE BEST SCORE\n // =========================\n useEffect(() => {\n if (stage === \"results\" && score > bestScore) {\n setBestScore(score);\n localStorage.setItem(\"magicSentenceBest\", String(score));\n }\n }, [stage, score, bestScore]);\n\n // =========================\n // SOUND EFFECTS\n // =========================\n const playSound = (type: \"start\" | \"click\" | \"correct\" | \"half\" | \"wrong\") => {\n const ctx = new (window.AudioContext || (window as any).webkitAudioContext)();\n const osc = ctx.createOscillator();\n const gain = ctx.createGain();\n osc.connect(gain);\n gain.connect(ctx.destination);\n\n switch (type) {\n case \"start\": osc.frequency.value = 500; break;\n case \"click\": osc.frequency.value = 800; break;\n case \"correct\": osc.frequency.value = 1000; break;\n case \"half\": osc.frequency.value = 700; break;\n case \"wrong\": osc.frequency.value = 200; break;\n }\n gain.gain.setValueAtTime(0.1, ctx.currentTime);\n osc.start();\n osc.stop(ctx.currentTime + 0.2);\n };\n\n // =========================\n // CONFETTI EFFECT\n // =========================\n const triggerConfetti = () => {\n const duration = 2500;\n const end = Date.now() + duration;\n const colors = [\"#ec4c44\", \"#f7c948\", \"#6fcf97\", \"#56ccf2\", \"#bb6bd9\"];\n\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\")!;\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n canvas.style.position = \"fixed\";\n canvas.style.top = \"0\";\n canvas.style.left = \"0\";\n canvas.style.pointerEvents = \"none\";\n document.body.appendChild(canvas);\n\n const pieces = Array.from({ length: 100 }).map(() => ({\n x: Math.random() * canvas.width,\n y: Math.random() * canvas.height - canvas.height,\n size: 6 + Math.random() * 6,\n color: colors[Math.floor(Math.random() * colors.length)],\n speed: 2 + Math.random() * 4,\n tilt: Math.random() * 2 * Math.PI,\n }));\n\n const draw = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n pieces.forEach((p) => {\n ctx.fillStyle = p.color;\n ctx.beginPath();\n ctx.ellipse(p.x, p.y, p.size, p.size / 2, p.tilt, 0, 2 * Math.PI);\n ctx.fill();\n p.y += p.speed;\n p.x += Math.sin(p.tilt);\n });\n if (Date.now() < end) requestAnimationFrame(draw);\n else document.body.removeChild(canvas);\n };\n draw();\n };\n\n // =========================\n // RENDER SCREENS\n // =========================\n const renderSelect = () => (\n <div style={styles.gmCenterScreen}>\n <h1 style={styles.gmHeadline1}>MAGIC SENTENCE</h1>\n <p style={styles.gmBodyM}>Select number of rounds</p>\n <div style={{ \n display: \"flex\", \n gap: isMobileDevice() ? \"8px\" : \"16px\",\n justifyContent: \"center\" \n }}>\n {[3, 4, 5].map((num) => (\n <button \n key={num} \n onClick={() => handleSelect(num)} \n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n {num} ROUNDS\n </button>\n ))}\n </div>\n </div>\n );\n\n const renderTime = () => (\n <div style={styles.gmCenterScreen}>\n <h1 style={styles.gmHeadline1}>MAGIC SENTENCE</h1>\n <p style={styles.gmBodyM}>Select time per round</p>\n <div style={{ \n display: \"flex\", \n gap: isMobileDevice() ? \"8px\" : \"16px\",\n justifyContent: \"center\" \n }}>\n {[15, 20, 30].map((time) => (\n <button \n key={time} \n onClick={() => handleTimeSelect(time)} \n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n {time}s\n </button>\n ))}\n </div>\n </div>\n );\n\n const renderType = () => (\n <div style={styles.gmCenterScreen}>\n <h2 style={{...styles.gmBodyM, marginBottom: \"0px\"}}>\n Type down {rounds} sentence{rounds && rounds > 1 ? \"s\" : \"\"} for your student\n </h2>\n <p style={{...styles.gmBodyS, marginBottom: \"16px\", marginTop: \"0px\", color: \"#6b7280\"}}>\n Maximum 41 characters per sentence\n </p>\n <div style={{ \n display: \"flex\", \n flexDirection: \"column\", \n gap: 12, \n width: \"auto\", // Автоматическая ширина по содержимому\n minWidth: \"fit-content\", // Минимальная ширина по содержимому\n maxWidth: \"600px\" // Ограничиваем максимальную ширину\n }}>\n {sentences.map((text, i) => (\n <input\n key={i}\n value={text}\n placeholder={`Sentence ${i + 1}`}\n onChange={(e) => handleChange(i, e.target.value)}\n style={{\n ...styles.gmInput,\n padding: isMobileDevice() ? \"8px 12px\" : \"12px 16px\",\n fontSize: isMobileDevice() ? \"14px\" : \"16px\",\n width: \"100%\", // Поля теперь будут шире благодаря увеличенной ширине контейнера\n textAlign: \"center\" // Центрируем placeholder текст\n }}\n />\n ))}\n </div>\n <button\n onClick={startGame}\n disabled={sentences.some((s) => s.trim().length === 0)}\n style={{\n ...styles.gmButton,\n marginTop: 30,\n background: sentences.some((s) => s.trim().length === 0) ? \"#ccc\" : \"#ec4c44\",\n cursor: sentences.some((s) => s.trim().length === 0) ? \"not-allowed\" : \"pointer\",\n ...getMobileButtonStyles('large')\n }}\n >\n PLAY\n </button>\n </div>\n );\n\n const renderGetReady = () => (\n <div style={styles.gmReadyWrapper}>\n <h1 style={{ \n ...styles.gmHeadline1,\n color: \"#ec4c44\"\n }}>\n GET READY\n </h1>\n <div style={styles.gmHourglass}>⏳</div>\n </div>\n );\n\n const renderPlay = () => (\n <div style={styles.gmGameLayout}>\n <h2 style={{ \n marginBottom: isMobileDevice() ? \"5px\" : \"10px\",\n fontSize: isMobileDevice() ? \"16px\" : \"20px\"\n }}>\n Round {currentRound + 1}/{rounds} — {timeExpired ? \"TIME'S UP!\" : `Time: ${timeLeft}s`}\n </h2>\n\n {/* Progress bar */}\n <div\n style={{\n width: \"60%\",\n height: isMobileDevice() ? \"8px\" : \"14px\",\n borderRadius: 8,\n background: \"#eee\",\n overflow: \"hidden\",\n marginBottom: isMobileDevice() ? \"10px\" : \"20px\",\n }}\n >\n <div\n style={{\n height: \"100%\",\n width: `${(timeLeft / (timePerRound || 20)) * 100}%`,\n background: timeLeft <= 5 ? \"#ec4c44\" : \"#4caf50\",\n transition: \"width 1s linear\",\n }}\n ></div>\n </div>\n\n {/* Word bank */}\n <div\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => handleDropTo(e, \"bank\", null)}\n style={{\n display: \"flex\",\n flexWrap: shouldWrapWords() ? \"wrap\" : \"nowrap\",\n gap: isMobile || window.innerWidth < 768 ? \"6px\" : \"10px\",\n justifyContent: \"center\",\n marginBottom: isMobile || window.innerWidth < 768 ? \"15px\" : \"30px\",\n padding: isMobile || window.innerWidth < 768 ? \"5px\" : \"10px\",\n width: \"100%\",\n boxSizing: \"border-box\"\n }}\n >\n {words.map((t, idx) => (\n <div\n key={t.id}\n draggable={!timeExpired}\n role=\"button\"\n tabIndex={timeExpired ? -1 : 0}\n aria-label={timeExpired ? `Word: ${t.text} (time expired)` : createAriaLabel(\"Drag word\", t.text, \"to build sentence\")}\n onDragStart={(e) => {\n if (timeExpired) {\n e.preventDefault();\n return;\n }\n e.dataTransfer.setData(\n \"application/x-token\",\n JSON.stringify({ from: \"bank\", id: t.id })\n );\n e.dataTransfer.setData(\"text/plain\", t.id);\n announceToScreenReader(`Dragging word: ${t.text}`);\n }}\n onKeyDown={(e) => {\n if (timeExpired) return;\n handleKeyDown(e, () => moveToken(\"bank\", \"selected\", t.id, null));\n }}\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n const insertIndex = e.clientX > mid ? idx + 1 : idx;\n setHover({ list: null, id: null, side: null });\n e.stopPropagation();\n handleDropTo(e, \"bank\", insertIndex);\n }}\n onDragEnter={(e) => {\n if (timeExpired) return;\n const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n setHover({ list: \"bank\", id: t.id, side: e.clientX > mid ? \"right\" : \"left\" });\n }}\n onDragLeave={() => setHover({ list: null, id: null, side: null })}\n onClick={() => {\n if (timeExpired) return;\n moveToken(\"bank\", \"selected\", t.id, null);\n }}\n style={{\n padding: isMobile || window.innerWidth < 768 ? \"6px 10px\" : \"10px 16px\",\n borderRadius: isMobile || window.innerWidth < 768 ? \"6px\" : \"10px\",\n border: \"1px solid #ccc\",\n background: timeExpired ? \"#f0f0f0\" : \"#f9f9f9\",\n cursor: timeExpired ? \"not-allowed\" : (hover.list === \"bank\" && hover.id === t.id ? \"grabbing\" : \"grab\"),\n fontSize: isMobile || window.innerWidth < 768 ? \"12px\" : \"18px\",\n ...(hover.list === \"bank\" && hover.id === t.id && hover.side === \"left\" ? { borderLeft: \"3px solid #3b82f6\" } : {}),\n ...(hover.list === \"bank\" && hover.id === t.id && hover.side === \"right\" ? { borderRight: \"3px solid #3b82f6\" } : {}),\n flexShrink: 0,\n flexBasis: \"auto\",\n opacity: timeExpired ? 0.6 : 1,\n transition: \"opacity 0.3s ease, transform 0.2s ease\",\n ...(hover.list === \"bank\" && hover.id === t.id ? { \n transform: \"scale(1.05)\",\n boxShadow: \"0 2px 8px rgba(59, 130, 246, 0.3)\"\n } : {}),\n }}\n >\n {t.text}\n </div>\n ))}\n </div>\n\n {/* Selected sentence */}\n <div\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n const children = Array.from(e.currentTarget.children) as HTMLElement[];\n \n if (children.length === 0) {\n handleDropTo(e, \"selected\", 0);\n return;\n }\n \n let closestIdx = selected.length;\n let minDistance = Infinity;\n \n children.forEach((child, idx) => {\n const childRect = child.getBoundingClientRect();\n const childCenter = childRect.left + childRect.width / 2;\n const distance = Math.abs(e.clientX - childCenter);\n \n if (distance < minDistance) {\n minDistance = distance;\n closestIdx = e.clientX < childCenter ? idx : idx + 1;\n }\n });\n \n if (e.clientX > rect.right - 30) {\n closestIdx = selected.length;\n }\n if (e.clientX < rect.left + 30) {\n closestIdx = 0;\n }\n \n handleDropTo(e, \"selected\", closestIdx);\n }}\n style={{\n minHeight: isMobile || window.innerWidth < 768 ? \"50px\" : \"70px\",\n width: \"auto\", // Автоматическая ширина в зависимости от содержимого\n maxWidth: \"none\", // Убираем ограничение максимальной ширины\n minWidth: \"245px\", // Минимальная ширина для растягивания\n border: resultType === \"correct\" ? \"2px dashed #4caf50\" : \n resultType === \"almost\" ? \"2px dashed #ff9800\" : \n resultType === \"wrong\" ? \"2px dashed #f44336\" : \"2px dashed #ccc\",\n borderRadius: isMobile || window.innerWidth < 768 ? \"8px\" : \"12px\",\n padding: isMobile || window.innerWidth < 768 ? \"8px\" : \"12px\",\n display: \"flex\",\n flexWrap: shouldWrapWords() ? \"wrap\" : \"nowrap\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: `${getAdaptiveFontSize(selected.length)}px`,\n background: resultType === \"correct\" ? \"#e8f5e8\" : \n resultType === \"almost\" ? \"#fff3e0\" : \n resultType === \"wrong\" ? \"#ffebee\" : \"#fafafa\",\n overflowX: shouldWrapWords() ? \"hidden\" : \"auto\",\n whiteSpace: shouldWrapWords() ? \"normal\" : \"nowrap\",\n }}\n >\n {selected.map((t, idx) => (\n <span\n key={t.id}\n draggable={!timeExpired}\n onDragStart={(e) => {\n if (timeExpired) {\n e.preventDefault();\n return;\n }\n e.dataTransfer.setData(\n \"application/x-token\",\n JSON.stringify({ from: \"selected\", id: t.id })\n );\n e.dataTransfer.setData(\"text/plain\", t.id);\n }}\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n const rect = (e.currentTarget as HTMLSpanElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n const zoneWidth = rect.width * 0.25;\n const insertIndex = e.clientX < mid - zoneWidth ? idx : \n e.clientX > mid + zoneWidth ? idx + 1 : \n e.clientX > mid ? idx + 1 : idx;\n setHover({ list: null, id: null, side: null });\n e.stopPropagation();\n handleDropTo(e, \"selected\", insertIndex);\n }}\n onDragEnter={(e) => {\n if (timeExpired) return;\n const rect = (e.currentTarget as HTMLSpanElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n setHover({ list: \"selected\", id: t.id, side: e.clientX > mid ? \"right\" : \"left\" });\n }}\n onDragLeave={() => setHover({ list: null, id: null, side: null })}\n onClick={() => {\n if (timeExpired) return;\n moveToken(\"selected\", \"bank\", t.id, null);\n }}\n title={timeExpired ? \"Time expired\" : \"Click to remove back to bank\"}\n style={{\n padding: isMobileDevice() ? \"4px 6px\" : \"6px 10px\",\n margin: isMobileDevice() ? \"2px\" : \"4px\",\n borderRadius: isMobileDevice() ? \"4px\" : \"8px\",\n background: timeExpired ? \"#f0f0f0\" : \"#ffe9e7\",\n border: timeExpired ? \"1px solid #ccc\" : \"1px solid #ec4c44\",\n ...(hover.list === \"selected\" && hover.id === t.id && hover.side === \"left\" ? { borderLeft: \"3px solid #3b82f6\" } : {}),\n ...(hover.list === \"selected\" && hover.id === t.id && hover.side === \"right\" ? { borderRight: \"3px solid #3b82f6\" } : {}),\n cursor: timeExpired ? \"not-allowed\" : (hover.list === \"selected\" && hover.id === t.id ? \"grabbing\" : \"grab\"),\n userSelect: \"none\",\n fontSize: `${getAdaptiveFontSize(selected.length)}px`, // Адаптивный размер шрифта для слов\n fontFamily: '\"Roboto\", system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, sans-serif', // Более плотный шрифт\n whiteSpace: \"nowrap\", // Запрещаем перенос слов\n opacity: timeExpired ? 0.6 : 1,\n transition: \"opacity 0.3s ease, transform 0.2s ease\",\n ...(hover.list === \"selected\" && hover.id === t.id ? { \n transform: \"scale(1.05)\",\n boxShadow: \"0 2px 8px rgba(59, 130, 246, 0.3)\"\n } : {}),\n }}\n >\n {t.text}\n </span>\n ))}\n </div>\n\n <button\n onClick={() => handleNext(true)}\n disabled={!timeExpired && selected.length === 0}\n style={{\n marginTop: isMobileDevice() ? \"15px\" : \"30px\",\n fontSize: isMobileDevice() ? \"14px\" : \"20px\",\n padding: isMobileDevice() ? \"6px 12px\" : \"10px 24px\",\n borderRadius: isMobileDevice() ? \"8px\" : \"12px\",\n background: (timeExpired || selected.length > 0) ? \"#ec4c44\" : \"#ccc\",\n color: \"white\",\n border: \"none\",\n cursor: (timeExpired || selected.length > 0) ? \"pointer\" : \"not-allowed\",\n }}\n >\n {timeExpired ? \"NEXT\" : \"NEXT\"}\n </button>\n </div>\n );\n\n const renderResults = () => (\n <div style={styles.gmCenterScreen}>\n <h1 style={{\n ...styles.gmHeadline1,\n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"0px\" : \"0px\",\n marginBottom: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"2px\" : \"10px\",\n fontSize: (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"32px\" : \"clamp(28px, 4vw, 40px)\"\n }}>\n Game Over 🎯\n </h1>\n <h2 style={{\n ...styles.gmHeadline2,\n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"0px\" : \"0px\",\n marginBottom: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"2px\" : \"16px\",\n fontSize: (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"18px\" : \"24px\"\n }}>\n Your score: {score} out of {rounds}\n </h2>\n <p style={{ \n ...styles.gmBodyM, \n color: \"#10b981\", \n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"0px\" : \"12px\",\n marginBottom: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"2px\" : \"16px\",\n fontSize: (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"14px\" : \"16px\"\n }}>\n Best score: {bestScore}\n </p>\n\n <div style={{ \n display: \"flex\", \n gap: (isMobile && window.innerWidth > window.innerHeight) || (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"6px\" : \"12px\", \n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"2px\" : (window.innerWidth === 1366 && window.innerHeight === 766) || (window.innerWidth === 1366 && window.innerHeight === 768) || (window.innerWidth === 1280 && window.innerHeight === 720) || (window.innerWidth === 1440 && window.innerHeight === 900) || isDesktopLayout ? \"12px\" : \"24px\"\n }}>\n <button\n onClick={() => {\n triggerConfetti();\n playSound(\"start\");\n setTimeout(() => {\n setStage(\"getready\");\n setCountdown(null);\n setTimeExpired(false);\n }, 800);\n }}\n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n 🔁 Play again\n </button>\n\n <button\n onClick={() => {\n playSound(\"click\");\n setStage(\"select\");\n setRounds(null);\n setTimePerRound(null);\n setSentences([]);\n setScore(0);\n setSelected([]);\n setTimeExpired(false);\n }}\n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n ⬅️ Exit\n </button>\n </div>\n </div>\n );\n\n // Условие для отображения логотипа (на desktop и планшетах)\n const shouldShowLogo = !isMobile && showLogo;\n\n const MemoizedLogo = useMemo(\n () => {\n // Скрываем логотип на мобильных устройствах в landscape режиме и на малых экранах\n if ((isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700) {\n return null;\n }\n \n if (!shouldShowLogo) {\n return null;\n }\n \n const logoBaseUrl = logoUrl || (typeof window !== 'undefined' && window.origin \n ? `${window.origin}/cloud/speakid/games/magic%20sentence/logo`\n : \"/cloud/speakid/games/magic%20sentence/logo\");\n \n return (\n // ensure logo is positioned inside the square container\n <div style={{ ...styles.gmLogoFixed, position: \"absolute\", top: 16, left: 16, zIndex: 30 }}>\n <picture>\n <source\n srcSet={`${logoBaseUrl}.svg`}\n type=\"image/svg+xml\"\n />\n <img\n src={`${logoBaseUrl}.png`}\n alt=\"SPEAKID Logo\"\n style={styles.gmLogoImg}\n loading=\"lazy\"\n />\n </picture>\n </div>\n );\n },\n [isMobile, shouldShowLogo, logoUrl]\n );\n\n return (\n <div\n ref={containerRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n background: \"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)\",\n transition: \"background 0.3s ease\",\n overflow: \"hidden\",\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0\n }}\n >\n <div\n style={{\n width: isMobile ? \"100%\" : (containerSize || 1000),\n height: isMobile ? \"100%\" : (containerSize || 1000),\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n overflow: \"hidden\",\n borderRadius: isMobile ? 0 : \"20px\",\n background: \"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)\",\n boxShadow: isMobile ? \"none\" : \"0 0 40px rgba(0,0,0,0.1)\",\n margin: isMobile ? \"0 auto\" : \"unset\",\n position: \"relative\", // needed so absolute logo is inside the square\n transform: `scale(${scale})`, // ✅ Применяем масштаб для широких экранов\n }}\n >\n <div\n style={{\n transform: \"translateZ(0)\",\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n }}\n >\n <div id=\"magic-sentence-root\">\n {MemoizedLogo}\n {stage === \"select\" ? renderSelect() : null}\n {stage === \"time\" ? renderTime() : null}\n {stage === \"type\" ? renderType() : null}\n {stage === \"getready\" ? renderGetReady() : null}\n {stage === \"play\" ? renderPlay() : null}\n {stage === \"results\" ? renderResults() : null}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default GameComponent;","import React, { Component, ErrorInfo, ReactNode } from 'react';\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n error?: Error;\n errorInfo?: ErrorInfo;\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return {\n hasError: true,\n error,\n };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n console.error('Game Error:', error, errorInfo);\n \n // В реальном приложении здесь можно отправить ошибку в аналитику\n // analytics.track('game_error', { error: error.message, stack: error.stack });\n \n this.setState({\n error,\n errorInfo,\n });\n }\n\n handleReset = () => {\n this.setState({ hasError: false, error: undefined, errorInfo: undefined });\n };\n\n render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '100vh',\n padding: '20px',\n textAlign: 'center',\n backgroundColor: '#fef2f2',\n color: '#dc2626',\n fontFamily: 'system-ui, sans-serif'\n }}>\n <h1 style={{ fontSize: '24px', marginBottom: '16px' }}>\n 🚨 Oops! Something went wrong\n </h1>\n <p style={{ fontSize: '16px', marginBottom: '24px', maxWidth: '500px' }}>\n The game encountered an unexpected error. Don't worry, your progress is saved!\n </p>\n \n <button\n onClick={this.handleReset}\n style={{\n padding: '12px 24px',\n fontSize: '16px',\n backgroundColor: '#dc2626',\n color: 'white',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'background-color 0.2s'\n }}\n onMouseOver={(e) => e.currentTarget.style.backgroundColor = '#b91c1c'}\n onMouseOut={(e) => e.currentTarget.style.backgroundColor = '#dc2626'}\n >\n 🔄 Restart Game\n </button>\n \n {typeof process !== 'undefined' && process.env.NODE_ENV === 'development' && this.state.error && (\n <details style={{ marginTop: '20px', textAlign: 'left', maxWidth: '600px' }}>\n <summary style={{ cursor: 'pointer', fontSize: '14px' }}>\n Technical Details (Development Only)\n </summary>\n <pre style={{\n backgroundColor: '#f3f4f6',\n padding: '12px',\n borderRadius: '4px',\n fontSize: '12px',\n overflow: 'auto',\n marginTop: '8px'\n }}>\n {this.state.error.toString()}\n {this.state.errorInfo?.componentStack}\n </pre>\n </details>\n )}\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n\n"],"names":["keyframes","styleTag","animations","styles","useValidation","errors","setErrors","useState","validateSentence","useCallback","sentence","index","allSentences","newErrors","duplicateIndex","s","i","validateAllSentences","sentences","allErrors","result","error","clearErrors","createAriaLabel","action","word","context","handleKeyDown","event","allowedKeys","announceToScreenReader","message","announcement","globalReset","style","existingStyle","shuffle","arr","GameComponent","props","logoUrl","showLogo","containerRef","useRef","validationErrors","shouldWrapWords","isMobile","isMobileDevice","getMobileButtonStyles","type","useEffect","stage","setStage","rounds","setRounds","timePerRound","setTimePerRound","setSentences","currentRound","setCurrentRound","words","setWords","selected","setSelected","timeLeft","setTimeLeft","score","setScore","countdown","setCountdown","resultType","setResultType","timeExpired","setTimeExpired","isCorrect","setIsCorrect","bestScore","setBestScore","timerRef","roundsRef","currentRoundRef","hover","setHover","setIsMobile","scale","setScale","containerSize","setContainerSize","isDesktopLayout","setIsDesktopLayout","isIPadMiniPortrait","setIsIPadMiniPortrait","isIPadMiniLandscape","setIsIPadMiniLandscape","isIPadAirPortrait","setIsIPadAirPortrait","isIPadAirLandscape","setIsIPadAirLandscape","isSurfaceDuoPortrait","setIsSurfaceDuoPortrait","isSurfaceDuoLandscape","setIsSurfaceDuoLandscape","isIPadProPortrait","setIsIPadProPortrait","isIPadProLandscape","setIsIPadProLandscape","isHorizontalLayout","setIsHorizontalLayout","isWideScreen","setIsWideScreen","resize","width","height","mobile","isSmallHeight","desktopLayout","isHorizontal","finalSize","moveToken","from","to","id","insertIndex","nextWords","nextSelected","takeFrom","putTo","idx","t","token","targetIndex","handleDropTo","raw","fallbackId","inBank","inSelected","payload","handleSelect","num","handleTimeSelect","time","handleChange","value","updated","validation","normalizeSentence","getAdaptiveFontSize","wordCount","startGame","prev","startRound","target","tokens","w","autoCheckTimeoutRef","correct","correctWords","selectedTexts","playSound","missingWords","extraWords","wrongOrder","handleNext","manual","triggerConfetti","ctx","osc","gain","end","colors","canvas","pieces","draw","p","renderSelect","jsxs","jsx","renderTime","renderType","text","e","renderGetReady","renderPlay","rect","mid","children","closestIdx","minDistance","child","childRect","childCenter","distance","zoneWidth","renderResults","shouldShowLogo","MemoizedLogo","useMemo","logoBaseUrl","ErrorBoundary","Component","errorInfo"],"mappings":";;AAGA,MAAMA,KAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmClB,IAAI,OAAO,WAAa,OAAe,CAAC,SAAS,eAAe,gBAAgB,GAAG;AACjF,QAAMC,IAAW,SAAS,cAAc,OAAO;AAC/C,EAAAA,EAAS,KAAK,kBACdA,EAAS,YAAYD,IACrB,SAAS,KAAK,YAAYC,CAAQ;AACpC;AAGA,MAAMC,KAAa;AAAA,EACjB,MAAM;AAAA,IACJ,WAAW;AAAA,EAAA;AAAA,EAEb,OAAO;AAAA,IACL,WAAW;AAAA,EAAA;AAAA,EAEb,OAAO;AAAA,IACL,WAAW;AAAA,EAAA;AAAA,EAEb,SAAS;AAAA,IACP,WAAW;AAAA,EAAA;AAAA,EAEb,QAAQ;AAAA,IACN,WAAW;AAAA,EAAA;AAAA,EAEb,MAAM;AAAA,IACJ,WAAW;AAAA,EAAA;AAEf,GAGaC,IAAwC;AAAA,EACnD,gBAAgB;AAAA,IACd,UAAU;AAAA,IACV,QAAQ;AAAA;AAAA;AAAA,IAGR,WAAW;AAAA,IACX,OAAO;AAAA,IACP,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,OAAO;AAAA,IACP,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA;AAAA,EAAA;AAAA,EAGb,aAAa;AAAA,IACX,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,EAAA;AAAA,EAGd,aAAa;AAAA,IACX,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,EAAA;AAAA,EAed,SAAS;AAAA,IACP,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,EAAA;AAAA,EAGd,SAAS;AAAA,IACP,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,OAAO;AAAA,EAAA;AAAA,EAGT,UAAU;AAAA,IACR,YACE;AAAA,IACF,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,YACE;AAAA,EAAA;AAAA,EAQJ,cAAc;AAAA,IACZ,UAAU;AAAA,IACV,OAAO;AAAA;AAAA,IAEP,UAAU;AAAA;AAAA,IAEV,WAAW;AAAA,IACX,SAAS;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,OAAO;AAAA,IACP,SAAS;AAAA,IACT,QAAQ;AAAA,EAAA;AAAA,EAyCV,SAAS;AAAA,IACP,SAAS;AAAA,IACT,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,OAAO;AAAA,EAAA;AAAA;AAAA,EAsBT,aAAa;AAAA,IACX,UAAU;AAAA,IACV,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,YAAY;AAAA,EAAA;AAAA,EAGd,WAAW;AAAA,IACT,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,oBAAoB;AAAA,IACpB,qBAAqB;AAAA,IACrB,SAAS;AAAA,EAAA;AAAA,EAaX,gBAAgB;AAAA,IACd,SAAS;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,gBAAgB;AAAA;AAAA,IAEhB,QAAQ;AAAA,IACR,KAAK;AAAA,EAAA;AAAA,EAGP,aAAa;AAAA,IACX,UAAU;AAAA,IACV,GAAGD,GAAW;AAAA,EAAA;AAAA;AAAA,EAIhB,GAAGA;AACL,GC3QaE,KAAgB,MAAM;AACjC,QAAM,CAACC,GAAQC,CAAS,IAAIC,EAA4B,CAAA,CAAE,GAEpDC,IAAmBC,GAAY,CAACC,GAAkBC,GAAeC,MAA6C;AAClH,UAAMC,IAA+B,CAAA;AAGrC,IAAKH,EAAS,UACZG,EAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,SAAS;AAAA,IAAA,CACV,GAICH,EAAS,SAAS,MACpBG,EAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,SAAS,yBAAyBH,EAAS,MAAM;AAAA,IAAA,CAClD,GAKCA,KAAY,CADG,4BACS,KAAKA,CAAQ,KACvCG,EAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,SAAS;AAAA,IAAA,CACV;AAIH,UAAMC,IAAiBF,EAAa,UAAU,CAACG,GAAGC,OAAMA,OAAML,KAASI,EAAE,YAAA,EAAc,KAAA,MAAWL,EAAS,YAAA,EAAc,MAAM;AAC/H,WAAII,MAAmB,MACrBD,EAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,SAAS,wCAAwCC,IAAiB,CAAC;AAAA,IAAA,CACpE,GAGHR,EAAUO,CAAS,GACZ;AAAA,MACL,SAASA,EAAU,WAAW;AAAA,MAC9B,QAAQA;AAAA,IAAA;AAAA,EAEZ,GAAG,CAAA,CAAE,GAECI,KAAuBR,GAAY,CAACS,MAA0C;AAClF,UAAMC,IAA+B,CAAA;AAErC,WAAAD,EAAU,QAAQ,CAACR,GAAUC,MAAU;AACrC,YAAMS,IAASZ,EAAiBE,GAAUC,GAAOO,CAAS;AAC1D,MAAAC,EAAU,KAAK,GAAGC,EAAO,OAAO,IAAI,CAAAC,OAAU;AAAA,QAC5C,GAAGA;AAAA,QACH,SAAS,YAAYV,IAAQ,CAAC,KAAKU,EAAM,OAAO;AAAA,MAAA,EAChD,CAAC;AAAA,IACL,CAAC,GAEM;AAAA,MACL,SAASF,EAAU,WAAW;AAAA,MAC9B,QAAQA;AAAA,IAAA;AAAA,EAEZ,GAAG,CAACX,CAAgB,CAAC,GAEfc,KAAcb,GAAY,MAAM;AACpC,IAAAH,EAAU,CAAA,CAAE;AAAA,EACd,GAAG,CAAA,CAAE;AAEL,SAAO;AAAA,IACL,QAAAD;AAAA,IACA,kBAAAG;AAAA,IACA,sBAAAS;AAAA,IACA,aAAAK;AAAA,EAAA;AAEJ,GCpFaC,KAAkB,CAACC,GAAgBC,GAAeC,MACzDD,KAAQC,IACH,GAAGF,CAAM,UAAUC,CAAI,KAAKC,CAAO,KAExCD,IACK,GAAGD,CAAM,UAAUC,CAAI,MAEzBD,GAaIG,KAAgB,CAC3BC,GACAJ,GACAK,IAAwB,CAAC,SAAS,GAAG,MAClC;AACH,EAAIA,EAAY,SAASD,EAAM,GAAG,MAChCA,EAAM,eAAA,GACNJ,EAAA;AAEJ,GAEaM,IAAyB,CAACC,MAAoB;AAEzD,QAAMC,IAAe,SAAS,cAAc,KAAK;AACjD,EAAAA,EAAa,aAAa,aAAa,QAAQ,GAC/CA,EAAa,aAAa,eAAe,MAAM,GAC/CA,EAAa,MAAM,WAAW,YAC9BA,EAAa,MAAM,OAAO,YAC1BA,EAAa,MAAM,QAAQ,OAC3BA,EAAa,MAAM,SAAS,OAC5BA,EAAa,MAAM,WAAW,UAE9B,SAAS,KAAK,YAAYA,CAAY,GACtCA,EAAa,cAAcD,GAG3B,WAAW,MAAM;AACf,aAAS,KAAK,YAAYC,CAAY;AAAA,EACxC,GAAG,GAAI;AACT,GClCMC,KAAc,MAAM;AACxB,QAAMC,IAAQ,SAAS,cAAc,OAAO;AAC5C,EAAAA,EAAM,KAAK,wBAEXA,EAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BpB,QAAMC,IAAgB,SAAS,eAAe,sBAAsB;AACpE,EAAIA,KACFA,EAAc,OAAA,GAGhB,SAAS,KAAK,YAAYD,CAAK;AACjC,GAEME,KAAU,CAACC,MAAkB,CAAC,GAAGA,CAAG,EAAE,KAAK,MAAM,KAAK,OAAA,IAAW,GAAG;AAO1E,SAASC,GAAcC,IAAmB,IAAI;AAC5C,QAAM,EAAE,SAAAC,GAAS,UAAAC,IAAW,GAAA,IAASF,GAC/BG,KAAeC,EAAuB,IAAI,GAG1C,EAAE,sBAAA1B,IAAsB,QAAQ2B,EAAA,IAAqBxC,GAAA,GAGrDyC,IAAkB,MAEfC,KAAY,OAAO,aAAa,KAInCC,IAAiB,MACdD,KACA,OAAO,aAAa,OACnB,OAAO,cAAc,OAAO,OAAO,cAAc,OAAO,OAAO,eAAe,OAAO,OAAO,eAAe,KAI/GE,IAAwB,CAACC,IAAqC,aAAa;AAC/E,QAAI,CAACF;AACH,aAAO;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,QACV,UAAU;AAAA,MAAA;AAId,YAAQE,GAAA;AAAA,MACN,KAAK;AACH,eAAO;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,UAAU;AAAA,QAAA;AAAA,MAEd,KAAK;AACH,eAAO;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,UAAU;AAAA,QAAA;AAAA,MAEd,KAAK;AACH,eAAO;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,UAAU;AAAA,QAAA;AAAA,IACZ;AAAA,EAEN;AAEA,EAAAC,EAAU,OACRjB,GAAA,GACO,MAAM;AAEX,aAAS,gBAAgB,MAAM,WAAW,IAC1C,SAAS,KAAK,MAAM,WAAW;AAG/B,UAAMC,IAAQ,SAAS,eAAe,sBAAsB;AAC5D,IAAIA,KACFA,EAAM,OAAA;AAAA,EAEV,IACC,CAAA,CAAE;AAEL,QAAM,CAACiB,GAAOC,CAAQ,IAAI7C,EAAgB,QAAQ,GAC5C,CAAC8C,GAAQC,EAAS,IAAI/C,EAAwB,IAAI,GAClD,CAACgD,IAAcC,EAAe,IAAIjD,EAAwB,IAAI,GAC9D,CAACW,GAAWuC,EAAY,IAAIlD,EAAmB,CAAA,CAAE,GACjD,CAACmD,GAAcC,EAAe,IAAIpD,EAAS,CAAC,GAC5C,CAACqD,IAAOC,EAAQ,IAAItD,EAAkB,CAAA,CAAE,GACxC,CAACuD,GAAUC,EAAW,IAAIxD,EAAkB,CAAA,CAAE,GAC9C,CAACyD,GAAUC,EAAW,IAAI1D,EAAS,EAAE,GACrC,CAAC2D,GAAOC,CAAQ,IAAI5D,EAAS,CAAC,GAC9B,CAAC6D,IAAWC,EAAY,IAAI9D,EAAwB,IAAI,GACxD,CAAC+D,GAAYC,CAAa,IAAIhE,EAAgD,IAAI,GAClF,CAACiE,GAAaC,EAAc,IAAIlE,EAAS,EAAK,GAC9C,CAACmE,GAAWC,CAAY,IAAIpE,EAAS,EAAK,GAC1C,CAACqE,IAAWC,EAAY,IAAItE;AAAA,IAChC,OAAO,aAAa,QAAQ,mBAAmB,CAAC,KAAK;AAAA,EAAA,GAEjDuE,IAAWnC,EAAsB,IAAI,GACrCoC,KAAYpC,EAAsB,IAAI,GACtCqC,KAAkBrC,EAAe,CAAC,GAClC,CAACsC,GAAOC,CAAQ,IAAI3E,EAAsF,EAAE,MAAM,MAAM,IAAI,MAAM,MAAM,KAAA,CAAM,GAG9I,CAACuC,GAAUqC,EAAW,IAAI5E,EAAS,EAAK,GACxC,CAAC6E,IAAOC,EAAQ,IAAI9E,EAAS,CAAC,GAC9B,CAAC+E,IAAeC,EAAgB,IAAIhF,EAAwB,IAAI,GAChE,CAACiF,IAAiBC,EAAkB,IAAIlF,EAAS,EAAK,GACtD,CAACmF,GAAoBC,EAAqB,IAAIpF,EAAS,EAAK,GAC5D,CAACqF,GAAqBC,EAAsB,IAAItF,EAAS,EAAK,GAC9D,CAACuF,GAAmBC,EAAoB,IAAIxF,EAAS,EAAK,GAC1D,CAACyF,GAAoBC,EAAqB,IAAI1F,EAAS,EAAK,GAC5D,CAAC2F,GAAsBC,EAAuB,IAAI5F,EAAS,EAAK,GAChE,CAAC6F,GAAuBC,EAAwB,IAAI9F,EAAS,EAAK,GAClE,CAAC+F,GAAmBC,EAAoB,IAAIhG,EAAS,EAAK,GAC1D,CAACiG,GAAoBC,EAAqB,IAAIlG,EAAS,EAAK,GAC5D,CAACmG,IAAoBC,EAAqB,IAAIpG,EAAS,EAAK,GAC5D,CAACqG,IAAcC,EAAe,IAAItG,EAAS,EAAK;AAGtD,EAAA2C,EAAU,MAAM;AACd,UAAM4D,IAAS,MAAM;AACnB,YAAMC,IAAQ,OAAO,YACfC,IAAS,OAAO,aAChBC,IAASF,IAAQ,OAAQA,MAAU,OAAOC,MAAW,OAASD,MAAU,OAAOC,MAAW,KAE1FE,IAAgBF,IAAS,KACzBJ,IAAeG,IAAQC,IAAS,KAGhCtB,IAAqBqB,MAAU,OAAOC,MAAW,MACjDpB,IAAsBmB,MAAU,QAAQC,MAAW,KACnDlB,IAAoBiB,MAAU,OAAOC,MAAW,MAChDhB,IAAqBe,MAAU,QAAQC,MAAW,KAGlDd,IAAuBa,MAAU,OAAOC,MAAW,KACnDZ,KAAwBW,MAAU,OAAOC,MAAW,KAGpDV,KAAoBS,MAAU,QAAQC,MAAW,MACjDR,KAAqBO,MAAU,QAAQC,MAAW,MAGlDG,KAAgBJ,KAAS,QAAQC,KAAU,OAAO,CAACC;AACzD,MAAAxB,GAAmB0B,EAAa,GAGhCxB,GAAsBD,CAAkB,GACxCG,GAAuBD,CAAmB,GAC1CG,GAAqBD,CAAiB,GACtCG,GAAsBD,CAAkB,GACxCG,GAAwBD,CAAoB,GAC5CG,GAAyBD,EAAqB,GAC9CG,GAAqBD,EAAiB,GACtCG,GAAsBD,EAAkB,GACxCK,GAAgBD,CAAY;AAG5B,YAAMQ,KACHH,KAAUF,IAAQC,KACnBC;AAAA,MACAD,IAAS,OACTJ;AAAAA,MACCG,MAAU,QAAQC,MAAW,OAC7BD,MAAU,QAAQC,MAAW,OAC7BD,MAAU,QAAQC,MAAW,OAC7BD,MAAU,QAAQC,MAAW,OAC9BtB,KACAE,KACAE,KACAE,KACAE,KACAE,MACAE,MACAE,MACAW;AAMF,UALAR,GAAsBS,EAAY,GAElCjC,GAAY8B,CAAM,GAGdA;AACF,QAAA1B,GAAiB,IAAI,GACrBF,GAAS,CAAC;AAAA,eACD6B;AACT,QAAA3B,GAAiB,IAAI,GACrBF,GAAS,CAAC;AAAA,eACDuB,GAAc;AAIvB,cAAMS,KAAY,KAAK,IAAI,KAAM,KAAK,IAAIN,GAAOC,CAAM,IAAI,GAAG;AAC9D,QAAAzB,GAAiB8B,EAAS,GAC1BhC,GAAS,IAAI;AAAA,MACf,OAAO;AAGL,cAAMgC,KAAY,KAAK,IAAI,KAAM,KAAK,IAAIN,GAAOC,CAAM,IAAI,GAAG;AAC9D,QAAAzB,GAAiB8B,EAAS,GAC1BhC,GAAS,CAAC;AAAA,MACZ;AAAA,IACF;AACA,WAAAyB,EAAA,GACA,OAAO,iBAAiB,UAAUA,CAAM,GACjC,MAAM,OAAO,oBAAoB,UAAUA,CAAM;AAAA,EAC1D,GAAG,CAAA,CAAE;AAQL,QAAMQ,KAAY,CAChBC,GACAC,GACAC,GACAC,MACG;AAEH,QAAIlD,EAAa;AAEjB,QAAImD,IAAY,CAAC,GAAG/D,EAAK,GACrBgE,IAAe,CAAC,GAAG9D,CAAQ;AAE/B,UAAM+D,IAAWN,MAAS,SAASI,IAAYC,GACzCE,IAAQN,MAAO,SAASG,IAAYC,GAEpCG,IAAMF,EAAS,UAAU,CAACG,OAAMA,GAAE,OAAOP,CAAE;AACjD,QAAIM,MAAQ,GAAI;AAChB,UAAM,CAACE,CAAK,IAAIJ,EAAS,OAAOE,GAAK,CAAC;AAEtC,QAAIG,IAAcR;AAClB,IACEH,MAASC,KACTU,MAAgB,QAChBA,MAAgB,UAEZA,IAAcH,MAAKG,IAAcA,IAAc,IAInDA,KAAgB,QAEhBA,IAAc,KACdA,IAAcJ,EAAM,SAEpBA,EAAM,KAAKG,CAAK,IAEhBH,EAAM,OAAOI,GAAa,GAAGD,CAAK,GAGhCV,MAAS,SAAQI,IAAYE,IAAeD,IAAeC,GAC3DL,MAAO,SAAQG,IAAYG,IAAYF,IAAeE,GAE1DjE,GAAS8D,CAAS,GAClB5D,GAAY6D,CAAY;AAAA,EAC1B,GAEMO,IAAe,CACnB,GACAX,GACAE,MACG;AAIH,QAHA,EAAE,eAAA,GAGElD,GAAa;AACf,MAAAU,EAAS,EAAE,MAAM,MAAM,IAAI,MAAM,MAAM,MAAM;AAC7C;AAAA,IACF;AAEA,UAAMkD,IAAM,EAAE,aAAa,QAAQ,qBAAqB,MACrD,MAAM;AACL,YAAMC,IAAa,EAAE,aAAa,QAAQ,YAAY;AACtD,UAAI,CAACA,EAAY,QAAO;AACxB,YAAMC,IAAS1E,GAAM,KAAK,CAACoE,MAAMA,EAAE,OAAOK,CAAU,GAC9CE,IAAazE,EAAS,KAAK,CAACkE,MAAMA,EAAE,OAAOK,CAAU,GACrDd,IAAwBe,IAAS,SAASC,IAAa,aAAa;AAC1E,aAAOhB,IAAO,KAAK,UAAU,EAAE,MAAAA,GAAM,IAAIc,EAAA,CAAY,IAAI;AAAA,IAC3D,GAAA;AACF,QAAKD,GACL;AAAA,UAAI;AACF,cAAMI,IAAU,KAAK,MAAMJ,CAAG;AAC9B,YAAI,CAACI,KAAW,CAACA,EAAQ,MAAM,CAACA,EAAQ,KAAM;AAC9C,QAAAlB,GAAUkB,EAAQ,MAAMhB,GAAIgB,EAAQ,IAAId,CAAW;AAAA,MACrD,QAAQ;AAAA,MAER;AACA,MAAAxC,EAAS,EAAE,MAAM,MAAM,IAAI,MAAM,MAAM,MAAM;AAAA;AAAA,EAC/C,GAKMuD,KAAe,CAACC,MAAgB;AACpC,IAAApF,GAAUoF,CAAG,GACb3D,GAAU,UAAU2D,GACpBjF,GAAa,MAAMiF,CAAG,EAAE,KAAK,EAAE,CAAC,GAChCtF,EAAS,MAAM;AAAA,EACjB,GAEMuF,KAAmB,CAACC,MAAiB;AACzC,IAAApF,GAAgBoF,CAAI,GACpBxF,EAAS,MAAM;AAAA,EACjB,GAEMyF,KAAe,CAAClI,GAAemI,MAAkB;AAQrD,QANIA,EAAM,SAAS,MAMfA,KAAS,CADM,4BACM,KAAKA,CAAK;AACjC;AAGF,UAAMC,IAAU,CAAC,GAAG7H,CAAS;AAC7B,IAAA6H,EAAQpI,CAAK,IAAImI,GACjBrF,GAAasF,CAAO;AAGpB,UAAMC,IAAa/H,GAAqB8H,CAAO;AAC/C,IAAKC,EAAW,WACd,QAAQ,KAAK,sBAAsBA,EAAW,MAAM;AAAA,EAExD,GAEMC,KAAoB,CAAClI,MAAcA,EAAE,OAAO,QAAQ,QAAQ,GAAG,GAG/DmI,KAAsB,CAACC,MACvBA,KAAa,IAAU,KACvBA,KAAa,IAAU,KACvBA,KAAa,IAAU,KACvBA,KAAa,IAAU,KACpB,IAGHC,KAAY,MAAM;AAEtB,IADiBlI,EAAU,KAAK,CAACH,MAAMA,EAAE,KAAA,EAAO,WAAW,CAAC,MAI5D0C,GAAa,CAAC4F,MAASA,EAAK,IAAI,CAACtI,MAAMkI,GAAkBlI,CAAC,CAAC,CAAC,GAC5DoD,EAAS,CAAC,GACVR,GAAgB,CAAC,GACjBqB,GAAgB,UAAU,GAC1BX,GAAa,IAAI,GACjBjB,EAAS,UAAU;AAAA,EACrB;AAEA,EAAAF,EAAU,MAAM;AACd,QAAIC,MAAU,YAAY;AACxB,YAAM6E,IAAI,WAAW,MAAMsB,GAAW,CAAC,GAAG,GAAI;AAC9C,aAAO,MAAM,aAAatB,CAAC;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC7E,CAAK,CAAC;AAEV,QAAMmG,KAAa,CAAC3I,MAAkB;AACpC,UAAM4I,IAASrI,EAAUP,CAAK;AAC9B,QAAI,CAAC4I,EAAQ;AAMb,UAAMC,IALWpH;AAAA,MAAQmH,EACtB,KAAA,EACA,MAAM,KAAK,EACX,OAAO,OAAO;AAAA,IAAA,EAEgB,IAAI,CAACE,GAAGzI,OAAO;AAAA,MAC9C,IAAI,GAAG,KAAK,KAAK,IAAIL,CAAK,IAAIK,CAAC,IAAI,KAAK,SAAS,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAAA,MACtE,MAAMyI;AAAA,IAAA,EACN;AACF,IAAA5F,GAAS2F,CAAM,GACfzF,GAAY,CAAA,CAAE,GACdJ,GAAgBhD,CAAK,GACrBqE,GAAgB,UAAUrE,GAC1BsD,GAAYV,MAAgB,EAAE,GAC9BgB,EAAc,IAAI,GAClBE,GAAe,EAAK,GACpBE,EAAa,EAAK,GAClBvB,EAAS,MAAM;AAAA,EACjB,GAEMsG,IAAsB/G,EAAsB,IAAI;AAEtD,EAAAO,EAAU,MAAM;AACd,QAAIC,MAAU,UAAUqB,GAAa;AACnC,MAAIkF,EAAoB,YAAY,SAClC,OAAO,aAAaA,EAAoB,OAAO,GAC/CA,EAAoB,UAAU;AAEhC;AAAA,IACF;AAEA,UAAMC,IAAUzI,EAAUwC,CAAY;AACtC,QAAI,CAACiG,GAAS;AACZ,MAAApF,EAAc,IAAI,GACdmF,EAAoB,YAAY,SAClC,OAAO,aAAaA,EAAoB,OAAO,GAC/CA,EAAoB,UAAU;AAEhC;AAAA,IACF;AAEA,QAAI5F,EAAS,WAAW,GAAG;AACzB,MAAAS,EAAc,IAAI,GACdmF,EAAoB,YAAY,SAClC,OAAO,aAAaA,EAAoB,OAAO,GAC/CA,EAAoB,UAAU;AAEhC;AAAA,IACF;AAEA,UAAME,IAAeD,EAAQ,KAAA,EAAO,MAAM,KAAK,GACzCE,IAAgB/F,EAAS,IAAI,CAACkE,MAAMA,EAAE,IAAI;AAMhD,QAHE6B,EAAc,WAAWD,EAAa,UACtCC,EAAc,MAAM,CAACpI,GAAMsG,MAAQtG,MAASmI,EAAa7B,CAAG,CAAC;AAI7D,MAAI2B,EAAoB,YAAY,SAClC,OAAO,aAAaA,EAAoB,OAAO,GAC/CA,EAAoB,UAAU,OAEhCnF,EAAc,SAAS,GAClBG,MACHC,EAAa,EAAI,GACjBR,EAAS,CAACpD,MAAMA,IAAI,CAAC,GACrB+I,EAAU,SAAS,GACnBhI,EAAuB,qBAAqB;AAAA,aAK1C+H,EAAc,UAAUD,EAAa,QAAQ;AAE/C,MAAIF,EAAoB,YAAY,SAClC,OAAO,aAAaA,EAAoB,OAAO,GAC/CA,EAAoB,UAAU;AAGhC,YAAMK,IAAeH,EAAa,OAAO,CAAAnI,MAAQ,CAACoI,EAAc,SAASpI,CAAI,CAAC,EAAE,QAC1EuI,IAAaH,EAAc,OAAO,CAAApI,MAAQ,CAACmI,EAAa,SAASnI,CAAI,CAAC,EAAE,QACxEwI,IAAaL,EAAa,OAAO,CAACH,GAAGzI,MAAMyI,MAAMI,EAAc7I,CAAC,CAAC,EAAE,QACnEX,IAAS0J,IAAeC,IAAaC;AAE3C,MACE1F,EADElE,MAAW,IACC,WAEA,OAFQ,GAIpBqE,MACFC,EAAa,EAAK,GAClBR,EAAS,CAACpD,MAAM,KAAK,IAAI,GAAGA,IAAI,CAAC,CAAC;AAAA,IAEtC;AAEE,MAAAwD,EAAc,IAAI,GACdmF,EAAoB,YAAY,SAClC,OAAO,aAAaA,EAAoB,OAAO,GAC/CA,EAAoB,UAAU;AAKpC,WAAO,MAAM;AACX,MAAIA,EAAoB,YAAY,SAClC,OAAO,aAAaA,EAAoB,OAAO,GAC/CA,EAAoB,UAAU;AAAA,IAElC;AAAA,EACF,GAAG,CAACvG,GAAOW,GAAU5C,GAAWwC,GAAcc,GAAaF,GAAYI,GAAWrB,CAAM,CAAC,GAGzFH,EAAU,MAAM;AACd,QAAIC,MAAU,UAAU,CAACqB;AAEvB,UADIM,EAAS,YAAY,QAAM,OAAO,aAAaA,EAAS,OAAO,GAC/Dd,IAAW;AACb,QAAAc,EAAS,UAAU,OAAO,WAAW,MAAMb,GAAY,CAAC+D,MAAMA,IAAI,CAAC,GAAG,GAAI;AAAA,WACrE;AAEL,QAAAvD,GAAe,EAAI;AACnB,cAAMkF,IAAUzI,EAAUwC,CAAY;AACtC,YAAI,CAACiG,GAAS;AACZ,UAAApF,EAAc,IAAI;AAClB;AAAA,QACF;AAEA,cAAMqF,IAAeD,EAAQ,KAAA,EAAO,MAAM,KAAK,GACzCE,IAAgB/F,EAAS,IAAI,CAACkE,MAAMA,EAAE,IAAI,GAI1C+B,IAAeH,EAAa,OAAO,CAAAnI,MAAQ,CAACoI,EAAc,SAASpI,CAAI,CAAC,EAAE,QAC1EuI,IAAaH,EAAc,OAAO,CAAApI,MAAQ,CAACmI,EAAa,SAASnI,CAAI,CAAC,EAAE,QACxEwI,IAAaL,EAAa,OAAO,CAACH,GAAGzI,MAAMyI,MAAMI,EAAc7I,CAAC,CAAC,EAAE,QAGnEX,IAAS0J,IAAeC,IAAaC;AAG3C,QAAI5J,MAAW,KACbkE,EAAc,SAAS,GAClBG,MACHC,EAAa,EAAI,GACjBR,EAAS,CAACpD,MAAMA,IAAI,CAAC,IAEvB+I,EAAU,SAAS,GACnBhI,EAAuB,qBAAqB,KACnCzB,MAAW,KACpBkE,EAAc,QAAQ,GACtBJ,EAAS,CAACpD,MAAMA,IAAI,GAAG,GACvB+I,EAAU,MAAM,GAChBhI,EAAuB,mCAAmC,MAE1DyC,EAAc,OAAO,GACrBuF,EAAU,OAAO,GACjBhI,EAAuB,+BAA+B;AAAA,MAE1D;AAEF,WAAO,MAAM;AACX,MAAIgD,EAAS,YAAY,QAAM,OAAO,aAAaA,EAAS,OAAO;AAAA,IACrE;AAAA,EACF,GAAG,CAAC3B,GAAOa,GAAUQ,GAAatD,GAAWwC,GAAcI,GAAUY,CAAS,CAAC;AAK/E,QAAMwF,KAAa,CAACC,IAAS,OAAS;AAEpC,QAAIA,GAAQ;AAGV,UAAI3F,GAAa;AACf,QAAId,IAAe,KAAKL,KAAU,KAChCiG,GAAW5F,IAAe,CAAC,KAE3BN,EAAS,SAAS,GAClB,WAAW,MAAMgH,GAAA,GAAmB,GAAG;AAEzC;AAAA,MACF;AAGA,YAAMT,IAAUzI,EAAUwC,CAAY;AACtC,UAAI,CAACiG,GAAS;AAEZ,QAAIjG,IAAe,KAAKL,KAAU,KAChCiG,GAAW5F,IAAe,CAAC,KAE3BN,EAAS,SAAS,GAClB,WAAW,MAAMgH,GAAA,GAAmB,GAAG;AAEzC;AAAA,MACF;AAEA,YAAMR,IAAeD,EAAQ,KAAA,EAAO,MAAM,KAAK,GACzCE,IAAgB/F,EAAS,IAAI,CAACkE,MAAMA,EAAE,IAAI,GAI1C+B,IAAeH,EAAa,OAAO,CAAAnI,MAAQ,CAACoI,EAAc,SAASpI,CAAI,CAAC,EAAE,QAC1EuI,IAAaH,EAAc,OAAO,CAAApI,MAAQ,CAACmI,EAAa,SAASnI,CAAI,CAAC,EAAE,QACxEwI,IAAaL,EAAa,OAAO,CAACH,GAAGzI,MAAMyI,MAAMI,EAAc7I,CAAC,CAAC,EAAE,QAGnEX,IAAS0J,IAAeC,IAAaC;AAG3C,MAAI5J,MAAW,KACb8D,EAAS,CAACpD,MAAMA,IAAI,CAAC,GACrBwD,EAAc,SAAS,GACvBI,EAAa,EAAI,GACjBmF,EAAU,SAAS,GACnBhI,EAAuB,qBAAqB,KACnCzB,MAAW,KACpB8D,EAAS,CAACpD,MAAMA,IAAI,GAAG,GACvBwD,EAAc,QAAQ,GACtBuF,EAAU,MAAM,GAChBhI,EAAuB,mCAAmC,MAE1DyC,EAAc,OAAO,GACrBuF,EAAU,OAAO,GACjBhI,EAAuB,+BAA+B,IAIpD4B,IAAe,KAAKL,KAAU,KAChC,WAAW,MAAMiG,GAAW5F,IAAe,CAAC,GAAG,GAAG,IAElD,WAAW,MAAM;AACf,QAAAN,EAAS,SAAS,GAClB,WAAW,MAAMgH,GAAA,GAAmB,GAAG;AAAA,MACzC,GAAG,GAAG;AAAA,IAEV;AAAA,EACF;AAKA,EAAAlH,EAAU,MAAM;AACd,IAAIC,MAAU,aAAae,IAAQU,OACjCC,GAAaX,CAAK,GAClB,aAAa,QAAQ,qBAAqB,OAAOA,CAAK,CAAC;AAAA,EAE3D,GAAG,CAACf,GAAOe,GAAOU,EAAS,CAAC;AAK5B,QAAMkF,IAAY,CAAC7G,MAA2D;AAC5E,UAAMoH,IAAM,KAAK,OAAO,gBAAiB,OAAe,oBAAA,GAClDC,IAAMD,EAAI,iBAAA,GACVE,IAAOF,EAAI,WAAA;AAIjB,YAHAC,EAAI,QAAQC,CAAI,GAChBA,EAAK,QAAQF,EAAI,WAAW,GAEpBpH,GAAA;AAAA,MACN,KAAK;AAAS,QAAAqH,EAAI,UAAU,QAAQ;AAAK;AAAA,MACzC,KAAK;AAAS,QAAAA,EAAI,UAAU,QAAQ;AAAK;AAAA,MACzC,KAAK;AAAW,QAAAA,EAAI,UAAU,QAAQ;AAAM;AAAA,MAC5C,KAAK;AAAQ,QAAAA,EAAI,UAAU,QAAQ;AAAK;AAAA,MACxC,KAAK;AAAS,QAAAA,EAAI,UAAU,QAAQ;AAAK;AAAA,IAAA;AAE3C,IAAAC,EAAK,KAAK,eAAe,KAAKF,EAAI,WAAW,GAC7CC,EAAI,MAAA,GACJA,EAAI,KAAKD,EAAI,cAAc,GAAG;AAAA,EAChC,GAKMD,KAAkB,MAAM;AAE5B,UAAMI,IAAM,KAAK,IAAA,IAAQ,MACnBC,IAAS,CAAC,WAAW,WAAW,WAAW,WAAW,SAAS,GAE/DC,IAAS,SAAS,cAAc,QAAQ,GACxCL,IAAMK,EAAO,WAAW,IAAI;AAClC,IAAAA,EAAO,QAAQ,OAAO,YACtBA,EAAO,SAAS,OAAO,aACvBA,EAAO,MAAM,WAAW,SACxBA,EAAO,MAAM,MAAM,KACnBA,EAAO,MAAM,OAAO,KACpBA,EAAO,MAAM,gBAAgB,QAC7B,SAAS,KAAK,YAAYA,CAAM;AAEhC,UAAMC,IAAS,MAAM,KAAK,EAAE,QAAQ,IAAA,CAAK,EAAE,IAAI,OAAO;AAAA,MACpD,GAAG,KAAK,OAAA,IAAWD,EAAO;AAAA,MAC1B,GAAG,KAAK,OAAA,IAAWA,EAAO,SAASA,EAAO;AAAA,MAC1C,MAAM,IAAI,KAAK,OAAA,IAAW;AAAA,MAC1B,OAAOD,EAAO,KAAK,MAAM,KAAK,OAAA,IAAWA,EAAO,MAAM,CAAC;AAAA,MACvD,OAAO,IAAI,KAAK,OAAA,IAAW;AAAA,MAC3B,MAAM,KAAK,WAAW,IAAI,KAAK;AAAA,IAAA,EAC/B,GAEIG,IAAO,MAAM;AACjB,MAAAP,EAAI,UAAU,GAAG,GAAGK,EAAO,OAAOA,EAAO,MAAM,GAC/CC,EAAO,QAAQ,CAACE,MAAM;AACpB,QAAAR,EAAI,YAAYQ,EAAE,OAClBR,EAAI,UAAA,GACJA,EAAI,QAAQQ,EAAE,GAAGA,EAAE,GAAGA,EAAE,MAAMA,EAAE,OAAO,GAAGA,EAAE,MAAM,GAAG,IAAI,KAAK,EAAE,GAChER,EAAI,KAAA,GACJQ,EAAE,KAAKA,EAAE,OACTA,EAAE,KAAK,KAAK,IAAIA,EAAE,IAAI;AAAA,MACxB,CAAC,GACG,KAAK,IAAA,IAAQL,0BAA2BI,CAAI,IAC3C,SAAS,KAAK,YAAYF,CAAM;AAAA,IACvC;AACA,IAAAE,EAAA;AAAA,EACF,GAKME,KAAe,MACnB,gBAAAC,EAAC,OAAA,EAAI,OAAO5K,EAAO,gBACjB,UAAA;AAAA,IAAA,gBAAA6K,EAAC,MAAA,EAAG,OAAO7K,EAAO,aAAa,UAAA,kBAAc;AAAA,IAC7C,gBAAA6K,EAAC,KAAA,EAAE,OAAO7K,EAAO,SAAS,UAAA,2BAAuB;AAAA,IACjD,gBAAA6K,EAAC,SAAI,OAAO;AAAA,MACV,SAAS;AAAA,MACT,KAAKjI,MAAmB,QAAQ;AAAA,MAChC,gBAAgB;AAAA,IAAA,GAEf,WAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC2F,MACd,gBAAAqC;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,SAAS,MAAMtC,GAAaC,CAAG;AAAA,QAC/B,OAAO;AAAA,UACL,GAAGvI,EAAO;AAAA,UACV,GAAG6C,EAAsB,QAAQ;AAAA,QAAA;AAAA,QAGlC,UAAA;AAAA,UAAA0F;AAAA,UAAI;AAAA,QAAA;AAAA,MAAA;AAAA,MAPAA;AAAA,IAAA,CASR,EAAA,CACH;AAAA,EAAA,GACF,GAGIuC,KAAa,MACjB,gBAAAF,EAAC,OAAA,EAAI,OAAO5K,EAAO,gBACjB,UAAA;AAAA,IAAA,gBAAA6K,EAAC,MAAA,EAAG,OAAO7K,EAAO,aAAa,UAAA,kBAAc;AAAA,IAC7C,gBAAA6K,EAAC,KAAA,EAAE,OAAO7K,EAAO,SAAS,UAAA,yBAAqB;AAAA,IAC/C,gBAAA6K,EAAC,SAAI,OAAO;AAAA,MACV,SAAS;AAAA,MACT,KAAKjI,MAAmB,QAAQ;AAAA,MAChC,gBAAgB;AAAA,IAAA,GAEf,WAAC,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC6F,MACjB,gBAAAmC;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,SAAS,MAAMpC,GAAiBC,CAAI;AAAA,QACpC,OAAO;AAAA,UACL,GAAGzI,EAAO;AAAA,UACV,GAAG6C,EAAsB,QAAQ;AAAA,QAAA;AAAA,QAGlC,UAAA;AAAA,UAAA4F;AAAA,UAAK;AAAA,QAAA;AAAA,MAAA;AAAA,MAPDA;AAAA,IAAA,CASR,EAAA,CACH;AAAA,EAAA,GACF,GAGIsC,KAAa,MACjB,gBAAAH,EAAC,OAAA,EAAI,OAAO5K,EAAO,gBACjB,UAAA;AAAA,IAAA,gBAAA4K,EAAC,MAAA,EAAG,OAAO,EAAC,GAAG5K,EAAO,SAAS,cAAc,SAAQ,UAAA;AAAA,MAAA;AAAA,MACxCkD;AAAA,MAAO;AAAA,MAAUA,KAAUA,IAAS,IAAI,MAAM;AAAA,MAAG;AAAA,IAAA,GAC9D;AAAA,IACA,gBAAA2H,EAAC,KAAA,EAAE,OAAO,EAAC,GAAG7K,EAAO,SAAS,cAAc,QAAQ,WAAW,OAAO,OAAO,UAAA,GAAY,UAAA,sCAEzF;AAAA,IACA,gBAAA6K,EAAC,SAAI,OAAO;AAAA,MACV,SAAS;AAAA,MACT,eAAe;AAAA,MACf,KAAK;AAAA,MACL,OAAO;AAAA;AAAA,MACP,UAAU;AAAA;AAAA,MACV,UAAU;AAAA;AAAA,IAAA,GAET,UAAA9J,EAAU,IAAI,CAACiK,GAAMnK,MACpB,gBAAAgK;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,OAAOG;AAAA,QACP,aAAa,YAAYnK,IAAI,CAAC;AAAA,QAC9B,UAAU,CAACoK,MAAMvC,GAAa7H,GAAGoK,EAAE,OAAO,KAAK;AAAA,QAC/C,OAAO;AAAA,UACL,GAAGjL,EAAO;AAAA,UACV,SAAS4C,MAAmB,aAAa;AAAA,UACzC,UAAUA,MAAmB,SAAS;AAAA,UACtC,OAAO;AAAA;AAAA,UACP,WAAW;AAAA;AAAA,QAAA;AAAA,MACb;AAAA,MAVK/B;AAAA,IAAA,CAYR,GACH;AAAA,IACA,gBAAAgK;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS5B;AAAA,QACT,UAAUlI,EAAU,KAAK,CAACH,MAAMA,EAAE,KAAA,EAAO,WAAW,CAAC;AAAA,QACrD,OAAO;AAAA,UACL,GAAGZ,EAAO;AAAA,UACV,WAAW;AAAA,UACX,YAAYe,EAAU,KAAK,CAACH,MAAMA,EAAE,KAAA,EAAO,WAAW,CAAC,IAAI,SAAS;AAAA,UACpE,QAAQG,EAAU,KAAK,CAACH,MAAMA,EAAE,KAAA,EAAO,WAAW,CAAC,IAAI,gBAAgB;AAAA,UACvE,GAAGiC,EAAsB,OAAO;AAAA,QAAA;AAAA,QAEnC,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAED,GACF,GAGIqI,KAAiB,MACrB,gBAAAN,EAAC,OAAA,EAAI,OAAO5K,EAAO,gBACjB,UAAA;AAAA,IAAA,gBAAA6K,EAAC,QAAG,OAAO;AAAA,MACT,GAAG7K,EAAO;AAAA,MACV,OAAO;AAAA,IAAA,GACN,UAAA,aAEH;AAAA,IACA,gBAAA6K,EAAC,OAAA,EAAI,OAAO7K,EAAO,aAAa,UAAA,IAAA,CAAC;AAAA,EAAA,GACnC,GAGImL,KAAa,MACjB,gBAAAP,EAAC,OAAA,EAAI,OAAO5K,EAAO,cACjB,UAAA;AAAA,IAAA,gBAAA4K,EAAC,QAAG,OAAO;AAAA,MACT,cAAchI,MAAmB,QAAQ;AAAA,MACzC,UAAUA,EAAA,IAAmB,SAAS;AAAA,IAAA,GACrC,UAAA;AAAA,MAAA;AAAA,MACMW,IAAe;AAAA,MAAE;AAAA,MAAEL;AAAA,MAAO;AAAA,MAAImB,IAAc,eAAe,SAASR,CAAQ;AAAA,IAAA,GACrF;AAAA,IAGA,gBAAAgH;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,OAAO;AAAA,UACP,QAAQjI,MAAmB,QAAQ;AAAA,UACnC,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,cAAcA,EAAA,IAAmB,SAAS;AAAA,QAAA;AAAA,QAG5C,UAAA,gBAAAiI;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,OAAO;AAAA,cACL,QAAQ;AAAA,cACR,OAAO,GAAIhH,KAAYT,MAAgB,MAAO,GAAG;AAAA,cACjD,YAAYS,KAAY,IAAI,YAAY;AAAA,cACxC,YAAY;AAAA,YAAA;AAAA,UACd;AAAA,QAAA;AAAA,MACD;AAAA,IAAA;AAAA,IAIH,gBAAAgH;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,YAAY,CAAC,MAAM,EAAE,eAAA;AAAA,QACrB,QAAQ,CAAC,MAAM7C,EAAa,GAAG,QAAQ,IAAI;AAAA,QAC3C,OAAO;AAAA,UACL,SAAS;AAAA,UACT,UAAUtF,MAAoB,SAAS;AAAA,UACvC,KAAKC,KAAY,OAAO,aAAa,MAAM,QAAQ;AAAA,UACnD,gBAAgB;AAAA,UAChB,cAAcA,KAAY,OAAO,aAAa,MAAM,SAAS;AAAA,UAC7D,SAASA,KAAY,OAAO,aAAa,MAAM,QAAQ;AAAA,UACvD,OAAO;AAAA,UACP,WAAW;AAAA,QAAA;AAAA,QAGZ,UAAAc,GAAM,IAAI,CAACoE,GAAGD,MACb,gBAAAiD;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAW,CAACxG;AAAA,YACZ,MAAK;AAAA,YACL,UAAUA,IAAc,KAAK;AAAA,YAC7B,cAAYA,IAAc,SAASwD,EAAE,IAAI,oBAAoBzG,GAAgB,aAAayG,EAAE,MAAM,mBAAmB;AAAA,YACrH,aAAa,CAACoD,MAAM;AAClB,kBAAI5G,GAAa;AACf,gBAAA4G,EAAE,eAAA;AACF;AAAA,cACF;AACA,cAAAA,EAAE,aAAa;AAAA,gBACb;AAAA,gBACA,KAAK,UAAU,EAAE,MAAM,QAAQ,IAAIpD,EAAE,IAAI;AAAA,cAAA,GAE3CoD,EAAE,aAAa,QAAQ,cAAcpD,EAAE,EAAE,GACzClG,EAAuB,kBAAkBkG,EAAE,IAAI,EAAE;AAAA,YACnD;AAAA,YACA,WAAW,CAACoD,MAAM;AAChB,cAAI5G,KACJ7C,GAAcyJ,GAAG,MAAM9D,GAAU,QAAQ,YAAYU,EAAE,IAAI,IAAI,CAAC;AAAA,YAClE;AAAA,YACA,YAAY,CAACoD,MAAMA,EAAE,eAAA;AAAA,YACrB,QAAQ,CAACA,MAAM;AACb,oBAAMG,IAAQH,EAAE,cAAiC,sBAAA,GAC3CI,IAAMD,EAAK,OAAOA,EAAK,QAAQ,GAC/B7D,IAAc0D,EAAE,UAAUI,IAAMzD,IAAM,IAAIA;AAChD,cAAA7C,EAAS,EAAE,MAAM,MAAM,IAAI,MAAM,MAAM,MAAM,GAC7CkG,EAAE,gBAAA,GACFjD,EAAaiD,GAAG,QAAQ1D,CAAW;AAAA,YACrC;AAAA,YACA,aAAa,CAAC0D,MAAM;AAClB,kBAAI5G,EAAa;AACjB,oBAAM+G,IAAQH,EAAE,cAAiC,sBAAA,GAC3CI,IAAMD,EAAK,OAAOA,EAAK,QAAQ;AACrC,cAAArG,EAAS,EAAE,MAAM,QAAQ,IAAI8C,EAAE,IAAI,MAAMoD,EAAE,UAAUI,IAAM,UAAU,OAAA,CAAQ;AAAA,YAC/E;AAAA,YACA,aAAa,MAAMtG,EAAS,EAAE,MAAM,MAAM,IAAI,MAAM,MAAM,MAAM;AAAA,YAChE,SAAS,MAAM;AACb,cAAIV,KACJ8C,GAAU,QAAQ,YAAYU,EAAE,IAAI,IAAI;AAAA,YAC1C;AAAA,YACA,OAAO;AAAA,cACL,SAASlF,KAAY,OAAO,aAAa,MAAM,aAAa;AAAA,cAC5D,cAAcA,KAAY,OAAO,aAAa,MAAM,QAAQ;AAAA,cAC5D,QAAQ;AAAA,cACR,YAAY0B,IAAc,YAAY;AAAA,cACtC,QAAQA,IAAc,gBAAiBS,EAAM,SAAS,UAAUA,EAAM,OAAO+C,EAAE,KAAK,aAAa;AAAA,cACjG,UAAUlF,KAAY,OAAO,aAAa,MAAM,SAAS;AAAA,cACzD,GAAImC,EAAM,SAAS,UAAUA,EAAM,OAAO+C,EAAE,MAAM/C,EAAM,SAAS,SAAS,EAAE,YAAY,oBAAA,IAAwB,CAAA;AAAA,cAChH,GAAIA,EAAM,SAAS,UAAUA,EAAM,OAAO+C,EAAE,MAAM/C,EAAM,SAAS,UAAU,EAAE,aAAa,oBAAA,IAAwB,CAAA;AAAA,cAClH,YAAY;AAAA,cACZ,WAAW;AAAA,cACX,SAAST,IAAc,MAAM;AAAA,cAC7B,YAAY;AAAA,cACZ,GAAIS,EAAM,SAAS,UAAUA,EAAM,OAAO+C,EAAE,KAAK;AAAA,gBAC/C,WAAW;AAAA,gBACX,WAAW;AAAA,cAAA,IACT,CAAA;AAAA,YAAC;AAAA,YAGN,UAAAA,EAAE;AAAA,UAAA;AAAA,UA5DEA,EAAE;AAAA,QAAA,CA8DV;AAAA,MAAA;AAAA,IAAA;AAAA,IAIH,gBAAAgD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,YAAY,CAAC,MAAM,EAAE,eAAA;AAAA,QACrB,QAAQ,CAAC,MAAM;AACb,gBAAMO,IAAO,EAAE,cAAc,sBAAA,GACvBE,IAAW,MAAM,KAAK,EAAE,cAAc,QAAQ;AAEpD,cAAIA,EAAS,WAAW,GAAG;AACzB,YAAAtD,EAAa,GAAG,YAAY,CAAC;AAC7B;AAAA,UACF;AAEA,cAAIuD,IAAa5H,EAAS,QACtB6H,IAAc;AAElB,UAAAF,EAAS,QAAQ,CAACG,GAAO7D,MAAQ;AAC/B,kBAAM8D,IAAYD,EAAM,sBAAA,GAClBE,IAAcD,EAAU,OAAOA,EAAU,QAAQ,GACjDE,IAAW,KAAK,IAAI,EAAE,UAAUD,CAAW;AAEjD,YAAIC,IAAWJ,MACbA,IAAcI,GACdL,IAAa,EAAE,UAAUI,IAAc/D,IAAMA,IAAM;AAAA,UAEvD,CAAC,GAEG,EAAE,UAAUwD,EAAK,QAAQ,OAC3BG,IAAa5H,EAAS,SAEpB,EAAE,UAAUyH,EAAK,OAAO,OAC1BG,IAAa,IAGfvD,EAAa,GAAG,YAAYuD,CAAU;AAAA,QACxC;AAAA,QACA,OAAO;AAAA,UACL,WAAW5I,KAAY,OAAO,aAAa,MAAM,SAAS;AAAA,UAC1D,OAAO;AAAA;AAAA,UACP,UAAU;AAAA;AAAA,UACV,UAAU;AAAA;AAAA,UACV,QAAQwB,MAAe,YAAY,uBAC3BA,MAAe,WAAW,uBAC1BA,MAAe,UAAU,uBAAuB;AAAA,UACxD,cAAcxB,KAAY,OAAO,aAAa,MAAM,QAAQ;AAAA,UAC5D,SAASA,KAAY,OAAO,aAAa,MAAM,QAAQ;AAAA,UACvD,SAAS;AAAA,UACT,UAAUD,MAAoB,SAAS;AAAA,UACvC,YAAY;AAAA,UACZ,gBAAgB;AAAA,UAChB,UAAU,GAAGqG,GAAoBpF,EAAS,MAAM,CAAC;AAAA,UACjD,YAAYQ,MAAe,YAAY,YAC3BA,MAAe,WAAW,YAC1BA,MAAe,UAAU,YAAY;AAAA,UACjD,WAAWzB,MAAoB,WAAW;AAAA,UAC1C,YAAYA,EAAA,IAAoB,WAAW;AAAA,QAAA;AAAA,QAG5C,UAAAiB,EAAS,IAAI,CAACkE,GAAGD,MAChB,gBAAAiD;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAW,CAACxG;AAAA,YACZ,aAAa,CAAC4G,MAAM;AAClB,kBAAI5G,GAAa;AACf,gBAAA4G,EAAE,eAAA;AACF;AAAA,cACF;AACA,cAAAA,EAAE,aAAa;AAAA,gBACb;AAAA,gBACA,KAAK,UAAU,EAAE,MAAM,YAAY,IAAIpD,EAAE,IAAI;AAAA,cAAA,GAE/CoD,EAAE,aAAa,QAAQ,cAAcpD,EAAE,EAAE;AAAA,YAC3C;AAAA,YACA,YAAY,CAACoD,MAAMA,EAAE,eAAA;AAAA,YACrB,QAAQ,CAACA,MAAM;AACb,oBAAMG,IAAQH,EAAE,cAAkC,sBAAA,GAC5CI,IAAMD,EAAK,OAAOA,EAAK,QAAQ,GAC/BS,IAAYT,EAAK,QAAQ,MACzB7D,IAAc0D,EAAE,UAAUI,IAAMQ,IAAYjE,IAC/BqD,EAAE,UAAUI,IAAMQ,KAClBZ,EAAE,UAAUI,IADkBzD,IAAM,IACRA;AAC/C,cAAA7C,EAAS,EAAE,MAAM,MAAM,IAAI,MAAM,MAAM,MAAM,GAC7CkG,EAAE,gBAAA,GACFjD,EAAaiD,GAAG,YAAY1D,CAAW;AAAA,YACzC;AAAA,YACA,aAAa,CAAC0D,MAAM;AAClB,kBAAI5G,EAAa;AACjB,oBAAM+G,IAAQH,EAAE,cAAkC,sBAAA,GAC5CI,IAAMD,EAAK,OAAOA,EAAK,QAAQ;AACrC,cAAArG,EAAS,EAAE,MAAM,YAAY,IAAI8C,EAAE,IAAI,MAAMoD,EAAE,UAAUI,IAAM,UAAU,OAAA,CAAQ;AAAA,YACnF;AAAA,YACA,aAAa,MAAMtG,EAAS,EAAE,MAAM,MAAM,IAAI,MAAM,MAAM,MAAM;AAAA,YAChE,SAAS,MAAM;AACb,cAAIV,KACJ8C,GAAU,YAAY,QAAQU,EAAE,IAAI,IAAI;AAAA,YAC1C;AAAA,YACA,OAAOxD,IAAc,iBAAiB;AAAA,YACtC,OAAO;AAAA,cACL,SAASzB,MAAmB,YAAY;AAAA,cACxC,QAAQA,MAAmB,QAAQ;AAAA,cACnC,cAAcA,MAAmB,QAAQ;AAAA,cACzC,YAAYyB,IAAc,YAAY;AAAA,cACtC,QAAQA,IAAc,mBAAmB;AAAA,cACzC,GAAIS,EAAM,SAAS,cAAcA,EAAM,OAAO+C,EAAE,MAAM/C,EAAM,SAAS,SAAS,EAAE,YAAY,oBAAA,IAAwB,CAAA;AAAA,cACpH,GAAIA,EAAM,SAAS,cAAcA,EAAM,OAAO+C,EAAE,MAAM/C,EAAM,SAAS,UAAU,EAAE,aAAa,oBAAA,IAAwB,CAAA;AAAA,cACtH,QAAQT,IAAc,gBAAiBS,EAAM,SAAS,cAAcA,EAAM,OAAO+C,EAAE,KAAK,aAAa;AAAA,cACrG,YAAY;AAAA,cACZ,UAAU,GAAGkB,GAAoBpF,EAAS,MAAM,CAAC;AAAA;AAAA,cACjD,YAAY;AAAA;AAAA,cACZ,YAAY;AAAA;AAAA,cACZ,SAASU,IAAc,MAAM;AAAA,cAC7B,YAAY;AAAA,cACZ,GAAIS,EAAM,SAAS,cAAcA,EAAM,OAAO+C,EAAE,KAAK;AAAA,gBACnD,WAAW;AAAA,gBACX,WAAW;AAAA,cAAA,IACT,CAAA;AAAA,YAAC;AAAA,YAGN,UAAAA,EAAE;AAAA,UAAA;AAAA,UA1DEA,EAAE;AAAA,QAAA,CA4DV;AAAA,MAAA;AAAA,IAAA;AAAA,IAGH,gBAAAgD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS,MAAMd,GAAW,EAAI;AAAA,QAC9B,UAAU,CAAC1F,KAAeV,EAAS,WAAW;AAAA,QAC9C,OAAO;AAAA,UACL,WAAWf,MAAmB,SAAS;AAAA,UACvC,UAAUA,MAAmB,SAAS;AAAA,UACtC,SAASA,MAAmB,aAAa;AAAA,UACzC,cAAcA,MAAmB,QAAQ;AAAA,UACzC,YAAayB,KAAeV,EAAS,SAAS,IAAK,YAAY;AAAA,UAC/D,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,QAASU,KAAeV,EAAS,SAAS,IAAK,YAAY;AAAA,QAAA;AAAA,QAG5D,UAAc;AAAA,MAAS;AAAA,IAAA;AAAA,EAC1B,GACF,GAGImI,KAAgB,MACpB,gBAAAlB,EAAC,OAAA,EAAI,OAAO5K,EAAO,gBACjB,UAAA;AAAA,IAAA,gBAAA6K,EAAC,QAAG,OAAO;AAAA,MACT,GAAG7K,EAAO;AAAA,MACV,YAAY2C,KAAY,OAAO,aAAa,OAAO,eAAiB,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAQ4C,KAAsBE,KAAuBE,KAAqBE,KAAsBE,KAAwBE,KAAyBE,KAAqBE,GAAqB;AAAA,MAC1e,cAAe1D,KAAY,OAAO,aAAa,OAAO,eAAiB,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAQ4C,KAAsBE,KAAuBE,KAAqBE,KAAsBE,KAAwBE,KAAyBE,KAAqBE,IAAqB,QAAQ;AAAA,MACrf,UAAW1D,KAAY,OAAO,cAAc,OAAO,OAAO,eAAe,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,MAAO,SAAS;AAAA,IAAA,GAC5U,UAAA,gBAEH;AAAA,IACA,gBAAAiI,EAAC,QAAG,OAAO;AAAA,MACT,GAAG5K,EAAO;AAAA,MACV,YAAY2C,KAAY,OAAO,aAAa,OAAO,eAAiB,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAQ4C,KAAsBE,KAAuBE,KAAqBE,KAAsBE,KAAwBE,KAAyBE,KAAqBE,GAAqB;AAAA,MAC1e,cAAe1D,KAAY,OAAO,aAAa,OAAO,eAAiB,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAQ4C,KAAsBE,KAAuBE,KAAqBE,KAAsBE,KAAwBE,KAAyBE,KAAqBE,IAAqB,QAAQ;AAAA,MACrf,UAAW1D,KAAY,OAAO,cAAc,OAAO,OAAO,eAAe,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,MAAO,SAAS;AAAA,IAAA,GAC5U,UAAA;AAAA,MAAA;AAAA,MACYoB;AAAA,MAAM;AAAA,MAASb;AAAA,IAAA,GAC9B;AAAA,IACA,gBAAA0H,EAAC,OAAE,OAAO;AAAA,MACR,GAAG5K,EAAO;AAAA,MACV,OAAO;AAAA,MACP,WAAY2C,KAAY,OAAO,aAAa,OAAO,eAAiB,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAQ4C,KAAsBE,KAAuBE,KAAqBE,KAAsBE,KAAwBE,KAAyBE,KAAqBE,IAAqB,QAAQ;AAAA,MAClf,cAAe1D,KAAY,OAAO,aAAa,OAAO,eAAiB,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAQ4C,KAAsBE,KAAuBE,KAAqBE,KAAsBE,KAAwBE,KAAyBE,KAAqBE,IAAqB,QAAQ;AAAA,MACrf,UAAW1D,KAAY,OAAO,cAAc,OAAO,OAAO,eAAe,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,MAAO,SAAS;AAAA,IAAA,GAC5U,UAAA;AAAA,MAAA;AAAA,MACY8B;AAAA,IAAA,GACf;AAAA,IAEA,gBAAAmG,EAAC,SAAI,OAAO;AAAA,MACV,SAAS;AAAA,MACT,KAAMjI,KAAY,OAAO,aAAa,OAAO,eAAiBA,KAAY,OAAO,cAAc,OAAO,OAAO,eAAe,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,MAAO,QAAQ;AAAA,MAC/X,WAAYA,KAAY,OAAO,aAAa,OAAO,eAAiBA,KAAY,OAAO,cAAc,OAAO,OAAO,eAAe,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,OAAS,OAAO,eAAe,OAAO,OAAO,gBAAgB,MAAO,QAAS,OAAO,eAAe,QAAQ,OAAO,gBAAgB,OAAS,OAAO,eAAe,QAAQ,OAAO,gBAAgB,OAAS,OAAO,eAAe,QAAQ,OAAO,gBAAgB,OAAS,OAAO,eAAe,QAAQ,OAAO,gBAAgB,OAAQ0C,KAAkB,SAAS;AAAA,IAAA,GAExpB,UAAA;AAAA,MAAA,gBAAAwF;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAS,MAAM;AACb,YAAAZ,GAAA,GACAN,EAAU,OAAO,GACjB,WAAW,MAAM;AACf,cAAA1G,EAAS,UAAU,GACnBiB,GAAa,IAAI,GACjBI,GAAe,EAAK;AAAA,YACtB,GAAG,GAAG;AAAA,UACR;AAAA,UACA,OAAO;AAAA,YACL,GAAGtE,EAAO;AAAA,YACV,GAAG6C,EAAsB,QAAQ;AAAA,UAAA;AAAA,UAEpC,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAID,gBAAAgI;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAS,MAAM;AACb,YAAAlB,EAAU,OAAO,GACjB1G,EAAS,QAAQ,GACjBE,GAAU,IAAI,GACdE,GAAgB,IAAI,GACpBC,GAAa,CAAA,CAAE,GACfU,EAAS,CAAC,GACVJ,GAAY,CAAA,CAAE,GACdU,GAAe,EAAK;AAAA,UACtB;AAAA,UACA,OAAO;AAAA,YACL,GAAGtE,EAAO;AAAA,YACV,GAAG6C,EAAsB,QAAQ;AAAA,UAAA;AAAA,UAEpC,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAED,EAAA,CACF;AAAA,EAAA,GACF,GAIIkJ,KAAiB,CAACpJ,KAAYL,GAE9B0J,KAAeC;AAAA,IACnB,MAAM;AAMJ,UAJKtJ,KAAY,OAAO,aAAa,OAAO,eAAgB,OAAO,cAAc,OAI7E,CAACoJ;AACH,eAAO;AAGT,YAAMG,IAAc7J,MAAY,OAAO,SAAW,OAAe,OAAO,SACpE,GAAG,OAAO,MAAM,+CAChB;AAEJ;AAAA;AAAA,0BAEG,OAAA,EAAI,OAAO,EAAE,GAAGrC,EAAO,aAAa,UAAU,YAAY,KAAK,IAAI,MAAM,IAAI,QAAQ,GAAA,GACpF,4BAAC,WAAA,EACC,UAAA;AAAA,UAAA,gBAAA6K;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,QAAQ,GAAGqB,CAAW;AAAA,cACtB,MAAK;AAAA,YAAA;AAAA,UAAA;AAAA,UAEP,gBAAArB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,KAAK,GAAGqB,CAAW;AAAA,cACnB,KAAI;AAAA,cACJ,OAAOlM,EAAO;AAAA,cACd,SAAQ;AAAA,YAAA;AAAA,UAAA;AAAA,QACV,EAAA,CACF,EAAA,CACF;AAAA;AAAA,IAEJ;AAAA,IACA,CAAC2C,GAAUoJ,IAAgB1J,CAAO;AAAA,EAAA;AAGpC,SACE,gBAAAwI;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKtI;AAAA,MACL,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,gBAAgB;AAAA,QAChB,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,UAAU;AAAA,QACV,KAAK;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ;AAAA,MAAA;AAAA,MAGV,UAAA,gBAAAsI;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,OAAO;AAAA,YACL,OAAOlI,IAAW,SAAUwC,MAAiB;AAAA,YAC7C,QAAQxC,IAAW,SAAUwC,MAAiB;AAAA,YAC9C,SAAS;AAAA,YACT,gBAAgB;AAAA,YAChB,YAAY;AAAA,YACZ,UAAU;AAAA,YACV,cAAcxC,IAAW,IAAI;AAAA,YAC7B,YAAY;AAAA,YACZ,WAAWA,IAAW,SAAS;AAAA,YAC/B,QAAQA,IAAW,WAAW;AAAA,YAC9B,UAAU;AAAA;AAAA,YACV,WAAW,SAASsC,EAAK;AAAA;AAAA,UAAA;AAAA,UAG3B,UAAA,gBAAA4F;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,gBACL,WAAW;AAAA,gBACX,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,SAAS;AAAA,gBACT,gBAAgB;AAAA,gBAChB,YAAY;AAAA,cAAA;AAAA,cAGd,UAAA,gBAAAD,EAAC,OAAA,EAAI,IAAG,uBACL,UAAA;AAAA,gBAAAoB;AAAA,gBACAhJ,MAAU,WAAW2H,GAAA,IAAiB;AAAA,gBACtC3H,MAAU,SAAS8H,GAAA,IAAe;AAAA,gBAClC9H,MAAU,SAAS+H,GAAA,IAAe;AAAA,gBAClC/H,MAAU,aAAakI,GAAA,IAAmB;AAAA,gBAC1ClI,MAAU,SAASmI,GAAA,IAAe;AAAA,gBAClCnI,MAAU,YAAY8I,OAAkB;AAAA,cAAA,EAAA,CAC3C;AAAA,YAAA;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IACF;AAAA,EAAA;AAGN;ACnuCO,MAAMK,WAAsBC,GAAwB;AAAA,EACzD,YAAYhK,GAAc;AACxB,UAAMA,CAAK,GACX,KAAK,QAAQ,EAAE,UAAU,GAAA;AAAA,EAC3B;AAAA,EAEA,OAAO,yBAAyBlB,GAAqB;AACnD,WAAO;AAAA,MACL,UAAU;AAAA,MACV,OAAAA;AAAA,IAAA;AAAA,EAEJ;AAAA,EAEA,kBAAkBA,GAAcmL,GAAsB;AACpD,YAAQ,MAAM,eAAenL,GAAOmL,CAAS,GAK7C,KAAK,SAAS;AAAA,MACZ,OAAAnL;AAAA,MACA,WAAAmL;AAAA,IAAA,CACD;AAAA,EACH;AAAA,EAEA,cAAc,MAAM;AAClB,SAAK,SAAS,EAAE,UAAU,IAAO,OAAO,QAAW,WAAW,QAAW;AAAA,EAC3E;AAAA,EAEA,SAAS;AACP,WAAI,KAAK,MAAM,WACT,KAAK,MAAM,WACN,KAAK,MAAM,WAIlB,gBAAAzB,EAAC,SAAI,OAAO;AAAA,MACV,SAAS;AAAA,MACT,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,WAAW;AAAA,MACX,SAAS;AAAA,MACT,WAAW;AAAA,MACX,iBAAiB;AAAA,MACjB,OAAO;AAAA,MACP,YAAY;AAAA,IAAA,GAEZ,UAAA;AAAA,MAAA,gBAAAC,EAAC,MAAA,EAAG,OAAO,EAAE,UAAU,QAAQ,cAAc,OAAA,GAAU,UAAA,gCAAA,CAEvD;AAAA,MACA,gBAAAA,EAAC,KAAA,EAAE,OAAO,EAAE,UAAU,QAAQ,cAAc,QAAQ,UAAU,QAAA,GAAW,UAAA,iFAAA,CAEzE;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAS,KAAK;AAAA,UACd,OAAO;AAAA,YACL,SAAS;AAAA,YACT,UAAU;AAAA,YACV,iBAAiB;AAAA,YACjB,OAAO;AAAA,YACP,QAAQ;AAAA,YACR,cAAc;AAAA,YACd,QAAQ;AAAA,YACR,YAAY;AAAA,UAAA;AAAA,UAEd,aAAa,CAACI,MAAMA,EAAE,cAAc,MAAM,kBAAkB;AAAA,UAC5D,YAAY,CAACA,MAAMA,EAAE,cAAc,MAAM,kBAAkB;AAAA,UAC5D,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAIA,OAAO,UAAY,OAAe,QAAQ,IAAI,aAAa,iBAAiB,KAAK,MAAM,2BACrF,WAAA,EAAQ,OAAO,EAAE,WAAW,QAAQ,WAAW,QAAQ,UAAU,WAChE,UAAA;AAAA,QAAA,gBAAAJ,EAAC,WAAA,EAAQ,OAAO,EAAE,QAAQ,WAAW,UAAU,OAAA,GAAU,UAAA,uCAAA,CAEzD;AAAA,QACA,gBAAAD,EAAC,SAAI,OAAO;AAAA,UACV,iBAAiB;AAAA,UACjB,SAAS;AAAA,UACT,cAAc;AAAA,UACd,UAAU;AAAA,UACV,UAAU;AAAA,UACV,WAAW;AAAA,QAAA,GAEV,UAAA;AAAA,UAAA,KAAK,MAAM,MAAM,SAAA;AAAA,UACjB,KAAK,MAAM,WAAW;AAAA,QAAA,EAAA,CACzB;AAAA,MAAA,EAAA,CACF;AAAA,IAAA,GAEJ,IAIG,KAAK,MAAM;AAAA,EACpB;AACF;"}
1
+ {"version":3,"file":"speakid-build-a-sentence.es.js","sources":["../src/Game.styles.ts","../src/hooks/useValidation.ts","../src/utils/accessibility.ts","../src/Game.tsx","../src/components/ErrorBoundary.tsx"],"sourcesContent":["import { CSSProperties } from \"react\";\n\n// ===== Добавляем анимации в <head> =====\nconst keyframes = `\n @keyframes spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n \n @keyframes pulse {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.05); }\n }\n \n @keyframes shake {\n 0%, 100% { transform: translateX(0); }\n 25% { transform: translateX(-5px); }\n 75% { transform: translateX(5px); }\n }\n \n @keyframes slideIn {\n from { transform: translateY(-20px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes bounce {\n 0%, 20%, 53%, 80%, 100% { transform: translate3d(0,0,0); }\n 40%, 43% { transform: translate3d(0, -8px, 0); }\n 70% { transform: translate3d(0, -4px, 0); }\n 90% { transform: translate3d(0, -2px, 0); }\n }\n \n @keyframes glow {\n 0%, 100% { box-shadow: 0 0 5px rgba(76, 175, 80, 0.5); }\n 50% { box-shadow: 0 0 20px rgba(76, 175, 80, 0.8), 0 0 30px rgba(76, 175, 80, 0.6); }\n }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"game-keyframes\")) {\n const styleTag = document.createElement(\"style\");\n styleTag.id = \"game-keyframes\";\n styleTag.innerHTML = keyframes;\n document.head.appendChild(styleTag);\n}\n\n// ===== Анимации =====\nconst animations = {\n spin: {\n animation: \"spin 1.4s linear infinite\",\n },\n pulse: {\n animation: \"pulse 0.6s ease-in-out\",\n },\n shake: {\n animation: \"shake 0.4s ease-in-out\",\n },\n slideIn: {\n animation: \"slideIn 0.3s ease-out\",\n },\n bounce: {\n animation: \"bounce 0.6s ease-in-out\",\n },\n glow: {\n animation: \"glow 1s ease-in-out infinite\",\n },\n};\n\n// ===== Основные стили =====\nexport const styles: Record<string, CSSProperties> = {\n gmCenterScreen: {\n position: \"relative\",\n zIndex: 1,\n // use percent so the component fits inside the centered square container\n // (100vh caused overflow on tablets because it measured the viewport, not the container)\n minHeight: \"100%\",\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n textAlign: \"center\",\n color: \"#1f2937\",\n padding: \"24px 16px\",\n boxSizing: \"border-box\",\n transform: \"translateY(20px)\", // чуть вниз, чтобы компенсировать логотип\n },\n\n gmHeadline1: {\n fontWeight: 700,\n fontSize: \"clamp(28px, 4vw, 40px)\",\n lineHeight: \"110%\",\n },\n\n gmHeadline2: {\n fontWeight: 600,\n fontSize: \"24px\",\n lineHeight: \"120%\",\n },\n\n gmHeadline3: {\n fontWeight: 600,\n fontSize: \"18px\",\n lineHeight: \"130%\",\n },\n\n gmBodyL: {\n fontWeight: 400,\n fontSize: \"18px\",\n lineHeight: \"140%\",\n },\n\n gmBodyM: {\n fontWeight: 400,\n fontSize: \"16px\",\n lineHeight: \"140%\",\n },\n\n gmBodyS: {\n fontWeight: 400,\n fontSize: \"14px\",\n lineHeight: \"140%\",\n color: \"#6b7280\",\n },\n\n gmButton: {\n fontFamily:\n '\"Geist\", system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, \"Noto Sans\"',\n fontWeight: 600,\n fontSize: \"16px\",\n padding: \"10px 16px\",\n borderRadius: \"12px\",\n border: \"1px solid #e5e7eb\",\n background: \"#ec4c44\",\n color: \"#ffffff\",\n cursor: \"pointer\",\n boxShadow: \"0 6px 18px rgba(236, 76, 68, .18)\",\n transition:\n \"transform .06s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease\",\n },\n\n gmButtonActive: {\n background: \"#333\",\n color: \"#fff\",\n },\n\n gmGameLayout: {\n position: \"relative\",\n width: \"100%\",\n // allow the layout to expand within the square container for tablets/laptops\n maxWidth: \"none\",\n // should fill the parent square, not the full viewport\n minHeight: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n textAlign: \"center\",\n color: \"#1f2937\",\n padding: \"16px 8px\",\n margin: \"0 auto\",\n },\n\n gmGrid: {\n width: \"100%\",\n // let the grid use all available space; sizing is controlled in Game.tsx\n maxWidth: \"none\",\n margin: \"0 auto\",\n display: \"grid\",\n // defaults; overridden responsively in Game.tsx\n gridTemplateColumns: \"repeat(3, 210px)\",\n gridAutoRows: \"210px\",\n gap: \"20px\",\n justifyContent: \"center\",\n },\n\n gmCard: {\n border: \"1px solid #e5e7eb\",\n borderRadius: \"16px\",\n background: \"#f9f9f9\",\n aspectRatio: \"1 / 1\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n overflow: \"hidden\",\n transition:\n \"transform .2s ease, box-shadow .2s ease, border-color .2s ease\",\n },\n\n gmCorrect: {\n border: \"2px solid #10b981\",\n boxShadow: \"0 0 18px rgba(16,185,129,.45)\",\n background: \"#ecfdf5\",\n },\n\n gmWrong: {\n border: \"2px solid #ec4c44\",\n boxShadow: \"0 0 18px rgba(236,76,68,.35)\",\n background: \"#fef2f2\",\n },\n\n gmInput: {\n padding: \"6px 10px\",\n borderRadius: \"6px\",\n border: \"1px solid #ccc\",\n fontSize: \"16px\",\n fontFamily: '\"Geist\", system-ui',\n width: \"160px\",\n },\n\n gmTable: {\n marginTop: \"20px\",\n marginBottom: \"32px\",\n borderCollapse: \"collapse\",\n width: \"100%\",\n maxWidth: \"520px\",\n tableLayout: \"fixed\",\n textAlign: \"center\",\n },\n\n gmTableCell: {\n padding: \"8px 12px\",\n borderBottom: \"1px solid #e5e7eb\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n },\n\n // ✅ Обновлено только для качества логотипа (размер как в whats-missing)\n gmLogoFixed: {\n position: \"absolute\",\n top: \"16px\",\n left: \"16px\",\n width: \"auto\",\n zIndex: 10,\n pointerEvents: \"none\",\n background: \"transparent\",\n transform: \"none\",\n willChange: \"auto\",\n },\n\n gmLogoImg: {\n height: \"28px\",\n width: \"auto\",\n background: \"transparent\",\n objectFit: \"contain\",\n imageRendering: \"auto\",\n transform: \"translateZ(0)\",\n backfaceVisibility: \"hidden\",\n WebkitFontSmoothing: \"antialiased\",\n display: \"block\",\n },\n\n gmLogoFallback: {\n height: \"28px\",\n width: \"auto\",\n background: \"transparent\",\n color: \"#ec4c44\",\n fontSize: \"16px\",\n fontWeight: 700,\n display: \"block\",\n },\n\n gmReadyWrapper: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n // use percent so the wrapper scales with the container square\n height: \"60%\",\n gap: \"16px\",\n },\n\n gmHourglass: {\n fontSize: \"42px\",\n ...animations.spin,\n },\n\n // ===== Анимационные стили =====\n ...animations,\n};\n","import { useState, useCallback } from 'react';\n\nexport interface ValidationError {\n type: 'length' | 'characters' | 'empty' | 'duplicate';\n message: string;\n}\n\nexport interface ValidationResult {\n isValid: boolean;\n errors: ValidationError[];\n}\n\nexport const useValidation = () => {\n const [errors, setErrors] = useState<ValidationError[]>([]);\n\n const validateSentence = useCallback((sentence: string, index: number, allSentences: string[]): ValidationResult => {\n const newErrors: ValidationError[] = [];\n\n // Проверка на пустоту\n if (!sentence.trim()) {\n newErrors.push({\n type: 'empty',\n message: 'Sentence cannot be empty'\n });\n }\n\n // Проверка длины\n if (sentence.length > 41) {\n newErrors.push({\n type: 'length',\n message: `Sentence is too long (${sentence.length}/41 characters)`\n });\n }\n\n // Проверка символов (только латиница)\n const latinRegex = /^[a-zA-Z0-9\\s.,!?;:'\"-]*$/;\n if (sentence && !latinRegex.test(sentence)) {\n newErrors.push({\n type: 'characters',\n message: 'Only Latin characters, numbers, spaces and punctuation are allowed'\n });\n }\n\n // Проверка на дубликаты\n const duplicateIndex = allSentences.findIndex((s, i) => i !== index && s.toLowerCase().trim() === sentence.toLowerCase().trim());\n if (duplicateIndex !== -1) {\n newErrors.push({\n type: 'duplicate',\n message: `Duplicate sentence (same as sentence ${duplicateIndex + 1})`\n });\n }\n\n setErrors(newErrors);\n return {\n isValid: newErrors.length === 0,\n errors: newErrors\n };\n }, []);\n\n const validateAllSentences = useCallback((sentences: string[]): ValidationResult => {\n const allErrors: ValidationError[] = [];\n \n sentences.forEach((sentence, index) => {\n const result = validateSentence(sentence, index, sentences);\n allErrors.push(...result.errors.map(error => ({\n ...error,\n message: `Sentence ${index + 1}: ${error.message}`\n })));\n });\n\n return {\n isValid: allErrors.length === 0,\n errors: allErrors\n };\n }, [validateSentence]);\n\n const clearErrors = useCallback(() => {\n setErrors([]);\n }, []);\n\n return {\n errors,\n validateSentence,\n validateAllSentences,\n clearErrors,\n };\n};\n\n","// Утилиты для улучшения доступности\n\nexport const createAriaLabel = (action: string, word?: string, context?: string): string => {\n if (word && context) {\n return `${action} word \"${word}\" ${context}`;\n }\n if (word) {\n return `${action} word \"${word}\"`;\n }\n return action;\n};\n\nexport const getRoleForElement = (type: 'button' | 'draggable' | 'droppable' | 'input'): string => {\n const roles = {\n button: 'button',\n draggable: 'button',\n droppable: 'region',\n input: 'textbox'\n };\n return roles[type];\n};\n\nexport const handleKeyDown = (\n event: React.KeyboardEvent,\n action: () => void,\n allowedKeys: string[] = ['Enter', ' ']\n) => {\n if (allowedKeys.includes(event.key)) {\n event.preventDefault();\n action();\n }\n};\n\nexport const announceToScreenReader = (message: string) => {\n // Создаем временный элемент для объявления\n const announcement = document.createElement('div');\n announcement.setAttribute('aria-live', 'polite');\n announcement.setAttribute('aria-atomic', 'true');\n announcement.style.position = 'absolute';\n announcement.style.left = '-10000px';\n announcement.style.width = '1px';\n announcement.style.height = '1px';\n announcement.style.overflow = 'hidden';\n \n document.body.appendChild(announcement);\n announcement.textContent = message;\n \n // Удаляем элемент после объявления\n setTimeout(() => {\n document.body.removeChild(announcement);\n }, 1000);\n};\n\nexport const getFocusableElements = (container: HTMLElement): HTMLElement[] => {\n const focusableSelectors = [\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[role=\"button\"]:not([disabled])'\n ].join(', ');\n \n return Array.from(container.querySelectorAll(focusableSelectors));\n};\n\nexport const trapFocus = (container: HTMLElement) => {\n const focusableElements = getFocusableElements(container);\n \n if (focusableElements.length === 0) return;\n \n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n \n const handleTabKey = (e: KeyboardEvent) => {\n if (e.key === 'Tab') {\n if (e.shiftKey) {\n if (document.activeElement === firstElement) {\n lastElement.focus();\n e.preventDefault();\n }\n } else {\n if (document.activeElement === lastElement) {\n firstElement.focus();\n e.preventDefault();\n }\n }\n }\n };\n \n container.addEventListener('keydown', handleTabKey);\n \n // Фокусируем первый элемент\n firstElement.focus();\n \n // Возвращаем функцию для очистки\n return () => {\n container.removeEventListener('keydown', handleTabKey);\n };\n};\n\n","// ======================\n// MAGIC SENTENCE GAME (SPEAKID)\n// React 18 + TypeScript + Vite\n// Адаптивная верстка для всех устройств\n// ======================\n\nimport * as React from \"react\";\nimport { useState, useEffect, useRef, useMemo } from \"react\";\nimport { styles } from \"./Game.styles\";\nimport { ErrorBoundary } from \"./components/ErrorBoundary\";\nimport { useValidation } from \"./hooks/useValidation\";\nimport { createAriaLabel, handleKeyDown, announceToScreenReader } from \"./utils/accessibility\";\n\ntype Stage = \"select\" | \"time\" | \"type\" | \"getready\" | \"play\" | \"results\";\ntype Token = { id: string; text: string };\n\n// ✅ базовый reset\nconst globalReset = () => {\n const style = document.createElement(\"style\");\n style.id = \"magic-sentence-reset\"; // ✅ Добавляем ID для удаления\n \n style.textContent = `\n #magic-sentence-root, #magic-sentence-root * {\n box-sizing: border-box;\n font-family: \"Geist\", system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, sans-serif;\n }\n #magic-sentence-root img {\n max-width: 100%;\n height: auto;\n display: block;\n user-select: none;\n }\n html, body {\n margin: 0 !important;\n padding: 0 !important;\n width: 100% !important;\n height: 100% !important;\n overflow: hidden !important;\n zoom: 1 !important; /* ✅ защита от подзума */\n }\n #root {\n margin: 0 !important;\n padding: 0 !important;\n width: 100% !important;\n height: 100% !important;\n overflow: hidden !important;\n }\n `;\n \n // ✅ Удаляем старый стиль, если он есть\n const existingStyle = document.getElementById(\"magic-sentence-reset\");\n if (existingStyle) {\n existingStyle.remove();\n }\n \n document.head.appendChild(style);\n};\n\nconst shuffle = (arr: string[]) => [...arr].sort(() => Math.random() - 0.5);\n\nexport interface GameProps {\n logoUrl?: string;\n showLogo?: boolean;\n}\n\nfunction GameComponent(props: GameProps = {}) {\n const { logoUrl, showLogo = true } = props;\n const containerRef = useRef<HTMLDivElement>(null);\n \n // Новые хуки\n const { validateAllSentences, errors: validationErrors } = useValidation();\n\n // Функция для определения нужно ли переносить слова\n const shouldWrapWords = () => {\n // Переносим слова на всех мобильных устройствах\n return isMobile || window.innerWidth < 768;\n };\n\n // Универсальная функция для определения мобильных устройств\n const isMobileDevice = () => {\n return isMobile || \n window.innerWidth < 768 || \n (window.innerWidth >= 320 && window.innerWidth <= 932 && window.innerHeight >= 390 && window.innerHeight <= 932);\n };\n\n // Вспомогательная функция для мобильных размеров кнопок\n const getMobileButtonStyles = (type: 'small' | 'medium' | 'large' = 'medium') => {\n if (!isMobileDevice()) {\n return {\n padding: \"12px 24px\",\n fontSize: \"16px\",\n minWidth: \"auto\"\n };\n }\n\n switch (type) {\n case 'small':\n return {\n padding: \"4px 6px\",\n fontSize: \"9px\",\n minWidth: \"40px\"\n };\n case 'medium':\n return {\n padding: \"5px 8px\",\n fontSize: \"10px\",\n minWidth: \"50px\"\n };\n case 'large':\n return {\n padding: \"6px 10px\",\n fontSize: \"11px\",\n minWidth: \"60px\"\n };\n }\n };\n\n useEffect(() => {\n globalReset();\n return () => {\n // ✅ Восстанавливаем overflow на html и body\n document.documentElement.style.overflow = \"\";\n document.body.style.overflow = \"\";\n \n // ✅ Удаляем наш style элемент\n const style = document.getElementById(\"magic-sentence-reset\");\n if (style) {\n style.remove();\n }\n };\n }, []);\n\n const [stage, setStage] = useState<Stage>(\"select\");\n const [rounds, setRounds] = useState<number | null>(null);\n const [timePerRound, setTimePerRound] = useState<number | null>(null);\n const [sentences, setSentences] = useState<string[]>([]);\n const [currentRound, setCurrentRound] = useState(0);\n const [words, setWords] = useState<Token[]>([]);\n const [selected, setSelected] = useState<Token[]>([]);\n const [timeLeft, setTimeLeft] = useState(20);\n const [score, setScore] = useState(0);\n const [countdown, setCountdown] = useState<number | null>(null);\n const [resultType, setResultType] = useState<\"correct\" | \"almost\" | \"wrong\" | null>(null);\n const [timeExpired, setTimeExpired] = useState(false);\n const [isCorrect, setIsCorrect] = useState(false);\n const [bestScore, setBestScore] = useState<number>(\n Number(localStorage.getItem(\"magicSentenceBest\")) || 0\n );\n const timerRef = useRef<number | null>(null);\n const roundsRef = useRef<number | null>(null);\n const currentRoundRef = useRef<number>(0);\n const [hover, setHover] = useState<{ list: ListName | null; id: string | null; side: \"left\" | \"right\" | null }>({ list: null, id: null, side: null });\n\n // Адаптивность\n const [isMobile, setIsMobile] = useState(false);\n const [scale, setScale] = useState(1);\n const [containerSize, setContainerSize] = useState<number | null>(null);\n const [isDesktopLayout, setIsDesktopLayout] = useState(false);\n const [isIPadMiniPortrait, setIsIPadMiniPortrait] = useState(false);\n const [isIPadMiniLandscape, setIsIPadMiniLandscape] = useState(false);\n const [isIPadAirPortrait, setIsIPadAirPortrait] = useState(false);\n const [isIPadAirLandscape, setIsIPadAirLandscape] = useState(false);\n const [isSurfaceDuoPortrait, setIsSurfaceDuoPortrait] = useState(false);\n const [isSurfaceDuoLandscape, setIsSurfaceDuoLandscape] = useState(false);\n const [isIPadProPortrait, setIsIPadProPortrait] = useState(false);\n const [isIPadProLandscape, setIsIPadProLandscape] = useState(false);\n const [isHorizontalLayout, setIsHorizontalLayout] = useState(false);\n const [isWideScreen, setIsWideScreen] = useState(false);\n\n // ✅ адаптив под мобилки, планшеты и десктоп\n useEffect(() => {\n const resize = () => {\n const width = window.innerWidth;\n const height = window.innerHeight;\n const mobile = width < 768 || (width === 926 && height === 428) || (width === 932 && height === 430);\n const isLandscape = (width > height && mobile) || (width === 926 && height === 428) || (width === 932 && height === 430);\n const isSmallHeight = height < 700;\n const isWideScreen = width / height > 1.8; // ✅ Широкие экраны\n \n // iPad размеры\n const isIPadMiniPortrait = width === 768 && height === 1024;\n const isIPadMiniLandscape = width === 1024 && height === 768;\n const isIPadAirPortrait = width === 820 && height === 1180;\n const isIPadAirLandscape = width === 1180 && height === 820;\n \n // Surface DUO размеры\n const isSurfaceDuoPortrait = width === 540 && height === 720;\n const isSurfaceDuoLandscape = width === 720 && height === 540;\n \n // iPad Pro размеры\n const isIPadProPortrait = width === 1024 && height === 1366;\n const isIPadProLandscape = width === 1366 && height === 1024;\n \n // Десктопные разрешения\n const desktopLayout = width >= 1200 && height >= 600 && !mobile;\n setIsDesktopLayout(desktopLayout);\n \n // Установка состояний для iPad и Surface DUO\n setIsIPadMiniPortrait(isIPadMiniPortrait);\n setIsIPadMiniLandscape(isIPadMiniLandscape);\n setIsIPadAirPortrait(isIPadAirPortrait);\n setIsIPadAirLandscape(isIPadAirLandscape);\n setIsSurfaceDuoPortrait(isSurfaceDuoPortrait);\n setIsSurfaceDuoLandscape(isSurfaceDuoLandscape);\n setIsIPadProPortrait(isIPadProPortrait);\n setIsIPadProLandscape(isIPadProLandscape);\n setIsWideScreen(isWideScreen); // ✅ Сохраняем состояние для широких экранов\n \n // ✅ Вычисляем горизонтальный layout ОДИН РАЗ\n const isHorizontal = \n (mobile && width > height) || \n mobile || // ✅ ВСЕ мобильные устройства (включая portrait)\n height < 700 || \n isWideScreen || // ✅ Широкие экраны\n (width === 1366 && height === 766) || \n (width === 1366 && height === 768) || \n (width === 1280 && height === 720) || \n (width === 1440 && height === 900) || \n isIPadMiniPortrait || \n isIPadMiniLandscape || \n isIPadAirPortrait || \n isIPadAirLandscape || \n isSurfaceDuoPortrait || \n isSurfaceDuoLandscape || \n isIPadProPortrait || \n isIPadProLandscape || \n desktopLayout;\n setIsHorizontalLayout(isHorizontal);\n \n setIsMobile(mobile);\n\n // ✅ Адаптивные размеры контейнера\n if (mobile) {\n setContainerSize(null);\n setScale(1);\n } else if (isSmallHeight) {\n setContainerSize(null);\n setScale(1);\n } else if (isWideScreen) {\n // ✅ Широкие экраны: используем стандартный размер но уменьшаем масштаб\n const minSize = 400;\n const maxSize = 1200;\n const finalSize = Math.min(1000, Math.min(width, height) * 0.9);\n setContainerSize(finalSize);\n setScale(0.85); // Уменьшаем масштаб на 15%\n } else {\n const minSize = 400;\n const maxSize = 1200;\n const finalSize = Math.min(1000, Math.min(width, height) * 0.9);\n setContainerSize(finalSize);\n setScale(1);\n }\n };\n resize();\n window.addEventListener(\"resize\", resize);\n return () => window.removeEventListener(\"resize\", resize);\n }, []);\n\n // =========================\n // DND HELPERS\n // =========================\n type ListName = \"bank\" | \"selected\";\n type DragPayload = { from: ListName; id: string };\n\n const moveToken = (\n from: ListName,\n to: ListName,\n id: string,\n insertIndex: number | null\n ) => {\n // Блокируем перемещение если время истекло\n if (timeExpired) return;\n\n let nextWords = [...words];\n let nextSelected = [...selected];\n\n const takeFrom = from === \"bank\" ? nextWords : nextSelected;\n const putTo = to === \"bank\" ? nextWords : nextSelected;\n\n const idx = takeFrom.findIndex((t) => t.id === id);\n if (idx === -1) return;\n const [token] = takeFrom.splice(idx, 1);\n\n let targetIndex = insertIndex;\n if (\n from === to &&\n targetIndex !== null &&\n targetIndex !== undefined\n ) {\n if (targetIndex > idx) targetIndex = targetIndex - 1;\n }\n\n if (\n targetIndex === null ||\n targetIndex === undefined ||\n targetIndex < 0 ||\n targetIndex > putTo.length\n ) {\n putTo.push(token);\n } else {\n putTo.splice(targetIndex, 0, token);\n }\n\n if (from === \"bank\") nextWords = takeFrom; else nextSelected = takeFrom;\n if (to === \"bank\") nextWords = putTo; else nextSelected = putTo;\n\n setWords(nextWords);\n setSelected(nextSelected);\n };\n\n const handleDropTo = (\n e: React.DragEvent,\n to: ListName,\n insertIndex: number | null\n ) => {\n e.preventDefault();\n \n // Блокируем drop если время истекло\n if (timeExpired) {\n setHover({ list: null, id: null, side: null });\n return;\n }\n\n const raw = e.dataTransfer.getData(\"application/x-token\") ||\n (() => {\n const fallbackId = e.dataTransfer.getData(\"text/plain\");\n if (!fallbackId) return \"\";\n const inBank = words.some((t) => t.id === fallbackId);\n const inSelected = selected.some((t) => t.id === fallbackId);\n const from: ListName | null = inBank ? \"bank\" : inSelected ? \"selected\" : null;\n return from ? JSON.stringify({ from, id: fallbackId }) : \"\";\n })();\n if (!raw) return;\n try {\n const payload = JSON.parse(raw) as DragPayload;\n if (!payload || !payload.id || !payload.from) return;\n moveToken(payload.from, to, payload.id, insertIndex);\n } catch {\n // ignore bad payload\n }\n setHover({ list: null, id: null, side: null });\n };\n\n // =========================\n // START / SETUP\n // =========================\n const handleSelect = (num: number) => {\n setRounds(num);\n roundsRef.current = num;\n setSentences(Array(num).fill(\"\"));\n setStage(\"time\");\n };\n\n const handleTimeSelect = (time: number) => {\n setTimePerRound(time);\n setStage(\"type\");\n };\n\n const handleChange = (index: number, value: string) => {\n // Ограничение на 41 символ (включая пробелы и точку)\n if (value.length > 41) {\n return;\n }\n \n // Проверка на латинские символы (a-z, A-Z, пробелы, цифры, знаки препинания)\n const latinRegex = /^[a-zA-Z0-9\\s.,!?;:'\"-]*$/;\n if (value && !latinRegex.test(value)) {\n return; // Не сохраняем, если есть нелатинские символы\n }\n \n const updated = [...sentences];\n updated[index] = value;\n setSentences(updated);\n \n // Валидация при вводе\n const validation = validateAllSentences(updated);\n if (!validation.isValid) {\n console.warn('Validation errors:', validation.errors);\n }\n };\n\n const normalizeSentence = (s: string) => s.trim().replace(/\\s+/g, \" \");\n\n // Адаптивный размер шрифта в зависимости от количества слов\n const getAdaptiveFontSize = (wordCount: number) => {\n if (wordCount <= 3) return 20;\n if (wordCount <= 5) return 18;\n if (wordCount <= 7) return 16;\n if (wordCount <= 9) return 14;\n return 12;\n };\n\n const startGame = () => {\n const hasEmpty = sentences.some((s) => s.trim().length === 0);\n if (hasEmpty) {\n return;\n }\n setSentences((prev) => prev.map((s) => normalizeSentence(s)));\n setScore(0);\n setCurrentRound(0);\n currentRoundRef.current = 0;\n setCountdown(null); // Убираем цифровой отсчет\n setStage(\"getready\");\n };\n\n useEffect(() => {\n if (stage === \"getready\") {\n const t = setTimeout(() => startRound(0), 3000);\n return () => clearTimeout(t);\n }\n }, [stage]);\n\n const startRound = (index: number) => {\n const target = sentences[index];\n if (!target) return;\n const shuffled = shuffle(target\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n );\n const tokens: Token[] = shuffled.map((w, i) => ({\n id: `${Date.now()}-${index}-${i}-${Math.random().toString(36).slice(2)}`,\n text: w,\n }));\n setWords(tokens);\n setSelected([]);\n setCurrentRound(index);\n currentRoundRef.current = index;\n setTimeLeft(timePerRound || 20); // Используем выбранное время\n setResultType(null); // Сбрасываем результат\n setTimeExpired(false); // Сбрасываем состояние истечения времени\n setIsCorrect(false); // Сбрасываем флаг правильного ответа\n setStage(\"play\");\n };\n\n // Убираем автоматическую проверку во время сборки\n // Проверка происходит только при нажатии NEXT или при истечении времени\n\n // TIMER\n useEffect(() => {\n if (stage === \"play\" && !timeExpired) {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n if (timeLeft > 0) {\n timerRef.current = window.setTimeout(() => setTimeLeft((t) => t - 1), 1000);\n } else {\n // Время истекло - всегда проверяем предложение\n setTimeExpired(true);\n const correct = sentences[currentRound];\n if (!correct) {\n setResultType(null);\n return;\n }\n\n const correctWords = correct.trim().split(/\\s+/);\n const selectedTexts = selected.map((t) => t.text);\n \n // Всегда считаем ошибки, даже если выбрано меньше слов\n // Считаем ошибки: недостающие слова + лишние слова + неправильный порядок\n const missingWords = correctWords.filter(word => !selectedTexts.includes(word)).length;\n const extraWords = selectedTexts.filter(word => !correctWords.includes(word)).length;\n const wrongOrder = correctWords.filter((w, i) => w !== selectedTexts[i]).length;\n \n // Общее количество ошибок = недостающие + лишние + неправильный порядок\n const errors = missingWords + extraWords + wrongOrder;\n\n // Показываем результат и засчитываем очки\n if (errors === 0) {\n setResultType(\"correct\");\n if (!isCorrect) {\n setIsCorrect(true);\n setScore((s) => s + 1);\n }\n playSound(\"correct\");\n announceToScreenReader(\"Correct! Well done!\");\n } else if (errors === 1) {\n setResultType(\"almost\");\n setScore((s) => s + 0.5);\n playSound(\"half\");\n announceToScreenReader(\"Almost correct! Just one mistake.\");\n } else {\n setResultType(\"wrong\");\n playSound(\"wrong\");\n announceToScreenReader(\"Not quite right. Keep trying!\");\n }\n }\n }\n return () => {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n };\n }, [stage, timeLeft, timeExpired, sentences, currentRound, selected, isCorrect]);\n\n // =========================\n // SCORING / NEXT ROUND\n // =========================\n const handleNext = (manual = true) => {\n // Если это ручное нажатие NEXT\n if (manual) {\n // Если время уже истекло, проверка уже была выполнена в TIMER\n // Просто переходим к следующему раунду\n if (timeExpired) {\n if (currentRound + 1 < (rounds || 0)) {\n startRound(currentRound + 1);\n } else {\n setStage(\"results\");\n setTimeout(() => triggerConfetti(), 600);\n }\n return;\n }\n\n // Если время не истекло, проверяем предложение вручную\n const correct = sentences[currentRound];\n if (!correct) {\n // Если нет правильного предложения, просто переходим дальше\n if (currentRound + 1 < (rounds || 0)) {\n startRound(currentRound + 1);\n } else {\n setStage(\"results\");\n setTimeout(() => triggerConfetti(), 600);\n }\n return;\n }\n\n const correctWords = correct.trim().split(/\\s+/);\n const selectedTexts = selected.map((t) => t.text);\n \n // Всегда считаем ошибки, даже если выбрано меньше слов\n // Считаем ошибки: недостающие слова + лишние слова + неправильный порядок\n const missingWords = correctWords.filter(word => !selectedTexts.includes(word)).length;\n const extraWords = selectedTexts.filter(word => !correctWords.includes(word)).length;\n const wrongOrder = correctWords.filter((w, i) => w !== selectedTexts[i]).length;\n \n // Общее количество ошибок = недостающие + лишние + неправильный порядок\n const errors = missingWords + extraWords + wrongOrder;\n\n // Устанавливаем результат проверки и засчитываем очки\n if (errors === 0) {\n setScore((s) => s + 1);\n setResultType(\"correct\");\n setIsCorrect(true);\n playSound(\"correct\");\n announceToScreenReader(\"Correct! Well done!\");\n } else if (errors === 1) {\n setScore((s) => s + 0.5);\n setResultType(\"almost\");\n playSound(\"half\");\n announceToScreenReader(\"Almost correct! Just one mistake.\");\n } else {\n setResultType(\"wrong\");\n playSound(\"wrong\");\n announceToScreenReader(\"Not quite right. Keep trying!\");\n }\n\n // Переходим к следующему раунду после проверки\n if (currentRound + 1 < (rounds || 0)) {\n setTimeout(() => startRound(currentRound + 1), 800);\n } else {\n setTimeout(() => {\n setStage(\"results\");\n setTimeout(() => triggerConfetti(), 600);\n }, 800);\n }\n }\n };\n\n // =========================\n // SAVE BEST SCORE\n // =========================\n useEffect(() => {\n if (stage === \"results\" && score > bestScore) {\n setBestScore(score);\n localStorage.setItem(\"magicSentenceBest\", String(score));\n }\n }, [stage, score, bestScore]);\n\n // =========================\n // SOUND EFFECTS\n // =========================\n const playSound = (type: \"start\" | \"click\" | \"correct\" | \"half\" | \"wrong\") => {\n const ctx = new (window.AudioContext || (window as any).webkitAudioContext)();\n const osc = ctx.createOscillator();\n const gain = ctx.createGain();\n osc.connect(gain);\n gain.connect(ctx.destination);\n\n switch (type) {\n case \"start\": osc.frequency.value = 500; break;\n case \"click\": osc.frequency.value = 800; break;\n case \"correct\": osc.frequency.value = 1000; break;\n case \"half\": osc.frequency.value = 700; break;\n case \"wrong\": osc.frequency.value = 200; break;\n }\n gain.gain.setValueAtTime(0.1, ctx.currentTime);\n osc.start();\n osc.stop(ctx.currentTime + 0.2);\n };\n\n // =========================\n // CONFETTI EFFECT\n // =========================\n const triggerConfetti = () => {\n const duration = 2500;\n const end = Date.now() + duration;\n const colors = [\"#ec4c44\", \"#f7c948\", \"#6fcf97\", \"#56ccf2\", \"#bb6bd9\"];\n\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\")!;\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n canvas.style.position = \"fixed\";\n canvas.style.top = \"0\";\n canvas.style.left = \"0\";\n canvas.style.pointerEvents = \"none\";\n document.body.appendChild(canvas);\n\n const pieces = Array.from({ length: 100 }).map(() => ({\n x: Math.random() * canvas.width,\n y: Math.random() * canvas.height - canvas.height,\n size: 6 + Math.random() * 6,\n color: colors[Math.floor(Math.random() * colors.length)],\n speed: 2 + Math.random() * 4,\n tilt: Math.random() * 2 * Math.PI,\n }));\n\n const draw = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n pieces.forEach((p) => {\n ctx.fillStyle = p.color;\n ctx.beginPath();\n ctx.ellipse(p.x, p.y, p.size, p.size / 2, p.tilt, 0, 2 * Math.PI);\n ctx.fill();\n p.y += p.speed;\n p.x += Math.sin(p.tilt);\n });\n if (Date.now() < end) requestAnimationFrame(draw);\n else document.body.removeChild(canvas);\n };\n draw();\n };\n\n // =========================\n // RENDER SCREENS\n // =========================\n const renderSelect = () => (\n <div style={styles.gmCenterScreen}>\n <h1 style={styles.gmHeadline1}>MAGIC SENTENCE</h1>\n <p style={styles.gmBodyM}>Select number of rounds</p>\n <div style={{ \n display: \"flex\", \n gap: isMobileDevice() ? \"8px\" : \"16px\",\n justifyContent: \"center\" \n }}>\n {[3, 4, 5].map((num) => (\n <button \n key={num} \n onClick={() => handleSelect(num)} \n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n {num} ROUNDS\n </button>\n ))}\n </div>\n </div>\n );\n\n const renderTime = () => (\n <div style={styles.gmCenterScreen}>\n <h1 style={styles.gmHeadline1}>MAGIC SENTENCE</h1>\n <p style={styles.gmBodyM}>Select time per round</p>\n <div style={{ \n display: \"flex\", \n gap: isMobileDevice() ? \"8px\" : \"16px\",\n justifyContent: \"center\" \n }}>\n {[15, 20, 30].map((time) => (\n <button \n key={time} \n onClick={() => handleTimeSelect(time)} \n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n {time}s\n </button>\n ))}\n </div>\n </div>\n );\n\n const renderType = () => (\n <div style={styles.gmCenterScreen}>\n <h2 style={{...styles.gmBodyM, marginBottom: \"0px\"}}>\n Type down {rounds} sentence{rounds && rounds > 1 ? \"s\" : \"\"} for your student\n </h2>\n <p style={{...styles.gmBodyS, marginBottom: \"16px\", marginTop: \"0px\", color: \"#6b7280\"}}>\n Maximum 41 characters per sentence\n </p>\n <div style={{ \n display: \"flex\", \n flexDirection: \"column\", \n gap: 12, \n width: \"auto\", // Автоматическая ширина по содержимому\n minWidth: \"fit-content\", // Минимальная ширина по содержимому\n maxWidth: \"600px\" // Ограничиваем максимальную ширину\n }}>\n {sentences.map((text, i) => (\n <input\n key={i}\n value={text}\n placeholder={`Sentence ${i + 1}`}\n onChange={(e) => handleChange(i, e.target.value)}\n style={{\n ...styles.gmInput,\n padding: isMobileDevice() ? \"8px 12px\" : \"12px 16px\",\n fontSize: isMobileDevice() ? \"14px\" : \"16px\",\n width: \"100%\", // Поля теперь будут шире благодаря увеличенной ширине контейнера\n textAlign: \"center\" // Центрируем placeholder текст\n }}\n />\n ))}\n </div>\n <button\n onClick={startGame}\n disabled={sentences.some((s) => s.trim().length === 0)}\n style={{\n ...styles.gmButton,\n marginTop: 30,\n background: sentences.some((s) => s.trim().length === 0) ? \"#ccc\" : \"#ec4c44\",\n cursor: sentences.some((s) => s.trim().length === 0) ? \"not-allowed\" : \"pointer\",\n ...getMobileButtonStyles('large')\n }}\n >\n PLAY\n </button>\n </div>\n );\n\n const renderGetReady = () => (\n <div style={styles.gmReadyWrapper}>\n <h1 style={{ \n ...styles.gmHeadline1,\n color: \"#ec4c44\"\n }}>\n GET READY\n </h1>\n <div style={styles.gmHourglass}>⏳</div>\n </div>\n );\n\n const renderPlay = () => (\n <div style={styles.gmGameLayout}>\n <h2 style={{ \n marginBottom: isMobileDevice() ? \"5px\" : \"10px\",\n fontSize: isMobileDevice() ? \"16px\" : \"20px\"\n }}>\n Round {currentRound + 1}/{rounds} — {timeExpired ? \"TIME'S UP!\" : `Time: ${timeLeft}s`}\n </h2>\n\n {/* Progress bar */}\n <div\n style={{\n width: \"60%\",\n height: isMobileDevice() ? \"8px\" : \"14px\",\n borderRadius: 8,\n background: \"#eee\",\n overflow: \"hidden\",\n marginBottom: isMobileDevice() ? \"10px\" : \"20px\",\n }}\n >\n <div\n style={{\n height: \"100%\",\n width: `${(timeLeft / (timePerRound || 20)) * 100}%`,\n background: timeLeft <= 5 ? \"#ec4c44\" : \"#4caf50\",\n transition: \"width 1s linear\",\n }}\n ></div>\n </div>\n\n {/* Word bank */}\n <div\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => handleDropTo(e, \"bank\", null)}\n style={{\n display: \"flex\",\n flexWrap: shouldWrapWords() ? \"wrap\" : \"nowrap\",\n gap: isMobile || window.innerWidth < 768 ? \"6px\" : \"10px\",\n justifyContent: \"center\",\n marginBottom: isMobile || window.innerWidth < 768 ? \"15px\" : \"30px\",\n padding: isMobile || window.innerWidth < 768 ? \"5px\" : \"10px\",\n width: \"100%\",\n boxSizing: \"border-box\"\n }}\n >\n {words.map((t, idx) => (\n <div\n key={t.id}\n draggable={!timeExpired}\n role=\"button\"\n tabIndex={timeExpired ? -1 : 0}\n aria-label={timeExpired ? `Word: ${t.text} (time expired)` : createAriaLabel(\"Drag word\", t.text, \"to build sentence\")}\n onDragStart={(e) => {\n if (timeExpired) {\n e.preventDefault();\n return;\n }\n e.dataTransfer.setData(\n \"application/x-token\",\n JSON.stringify({ from: \"bank\", id: t.id })\n );\n e.dataTransfer.setData(\"text/plain\", t.id);\n announceToScreenReader(`Dragging word: ${t.text}`);\n }}\n onKeyDown={(e) => {\n if (timeExpired) return;\n handleKeyDown(e, () => moveToken(\"bank\", \"selected\", t.id, null));\n }}\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n const insertIndex = e.clientX > mid ? idx + 1 : idx;\n setHover({ list: null, id: null, side: null });\n e.stopPropagation();\n handleDropTo(e, \"bank\", insertIndex);\n }}\n onDragEnter={(e) => {\n if (timeExpired) return;\n const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n setHover({ list: \"bank\", id: t.id, side: e.clientX > mid ? \"right\" : \"left\" });\n }}\n onDragLeave={() => setHover({ list: null, id: null, side: null })}\n onClick={() => {\n if (timeExpired) return;\n moveToken(\"bank\", \"selected\", t.id, null);\n }}\n style={{\n padding: isMobile || window.innerWidth < 768 ? \"6px 10px\" : \"10px 16px\",\n borderRadius: isMobile || window.innerWidth < 768 ? \"6px\" : \"10px\",\n border: \"1px solid #ccc\",\n background: timeExpired ? \"#f0f0f0\" : \"#f9f9f9\",\n cursor: timeExpired ? \"not-allowed\" : (hover.list === \"bank\" && hover.id === t.id ? \"grabbing\" : \"grab\"),\n fontSize: isMobile || window.innerWidth < 768 ? \"12px\" : \"18px\",\n ...(hover.list === \"bank\" && hover.id === t.id && hover.side === \"left\" ? { borderLeft: \"3px solid #3b82f6\" } : {}),\n ...(hover.list === \"bank\" && hover.id === t.id && hover.side === \"right\" ? { borderRight: \"3px solid #3b82f6\" } : {}),\n flexShrink: 0,\n flexBasis: \"auto\",\n opacity: timeExpired ? 0.6 : 1,\n transition: \"opacity 0.3s ease, transform 0.2s ease\",\n ...(hover.list === \"bank\" && hover.id === t.id ? { \n transform: \"scale(1.05)\",\n boxShadow: \"0 2px 8px rgba(59, 130, 246, 0.3)\"\n } : {}),\n }}\n >\n {t.text}\n </div>\n ))}\n </div>\n\n {/* Selected sentence */}\n <div\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n const children = Array.from(e.currentTarget.children) as HTMLElement[];\n \n if (children.length === 0) {\n handleDropTo(e, \"selected\", 0);\n return;\n }\n \n let closestIdx = selected.length;\n let minDistance = Infinity;\n \n children.forEach((child, idx) => {\n const childRect = child.getBoundingClientRect();\n const childCenter = childRect.left + childRect.width / 2;\n const distance = Math.abs(e.clientX - childCenter);\n \n if (distance < minDistance) {\n minDistance = distance;\n closestIdx = e.clientX < childCenter ? idx : idx + 1;\n }\n });\n \n if (e.clientX > rect.right - 30) {\n closestIdx = selected.length;\n }\n if (e.clientX < rect.left + 30) {\n closestIdx = 0;\n }\n \n handleDropTo(e, \"selected\", closestIdx);\n }}\n style={{\n minHeight: isMobile || window.innerWidth < 768 ? \"50px\" : \"70px\",\n width: \"auto\", // Автоматическая ширина в зависимости от содержимого\n maxWidth: \"none\", // Убираем ограничение максимальной ширины\n minWidth: \"245px\", // Минимальная ширина для растягивания\n border: resultType === \"correct\" ? \"2px dashed #4caf50\" : \n resultType === \"almost\" ? \"2px dashed #ff9800\" : \n resultType === \"wrong\" ? \"2px dashed #f44336\" : \"2px dashed #ccc\",\n borderRadius: isMobile || window.innerWidth < 768 ? \"8px\" : \"12px\",\n padding: isMobile || window.innerWidth < 768 ? \"8px\" : \"12px\",\n display: \"flex\",\n flexWrap: shouldWrapWords() ? \"wrap\" : \"nowrap\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: `${getAdaptiveFontSize(selected.length)}px`,\n background: resultType === \"correct\" ? \"#e8f5e8\" : \n resultType === \"almost\" ? \"#fff3e0\" : \n resultType === \"wrong\" ? \"#ffebee\" : \"#fafafa\",\n overflowX: shouldWrapWords() ? \"hidden\" : \"auto\",\n whiteSpace: shouldWrapWords() ? \"normal\" : \"nowrap\",\n }}\n >\n {selected.map((t, idx) => (\n <span\n key={t.id}\n draggable={!timeExpired}\n onDragStart={(e) => {\n if (timeExpired) {\n e.preventDefault();\n return;\n }\n e.dataTransfer.setData(\n \"application/x-token\",\n JSON.stringify({ from: \"selected\", id: t.id })\n );\n e.dataTransfer.setData(\"text/plain\", t.id);\n }}\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n const rect = (e.currentTarget as HTMLSpanElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n const zoneWidth = rect.width * 0.25;\n const insertIndex = e.clientX < mid - zoneWidth ? idx : \n e.clientX > mid + zoneWidth ? idx + 1 : \n e.clientX > mid ? idx + 1 : idx;\n setHover({ list: null, id: null, side: null });\n e.stopPropagation();\n handleDropTo(e, \"selected\", insertIndex);\n }}\n onDragEnter={(e) => {\n if (timeExpired) return;\n const rect = (e.currentTarget as HTMLSpanElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n setHover({ list: \"selected\", id: t.id, side: e.clientX > mid ? \"right\" : \"left\" });\n }}\n onDragLeave={() => setHover({ list: null, id: null, side: null })}\n onClick={() => {\n if (timeExpired) return;\n moveToken(\"selected\", \"bank\", t.id, null);\n }}\n title={timeExpired ? \"Time expired\" : \"Click to remove back to bank\"}\n style={{\n padding: isMobileDevice() ? \"4px 6px\" : \"6px 10px\",\n margin: isMobileDevice() ? \"2px\" : \"4px\",\n borderRadius: isMobileDevice() ? \"4px\" : \"8px\",\n background: timeExpired ? \"#f0f0f0\" : \"#ffe9e7\",\n border: timeExpired ? \"1px solid #ccc\" : \"1px solid #ec4c44\",\n ...(hover.list === \"selected\" && hover.id === t.id && hover.side === \"left\" ? { borderLeft: \"3px solid #3b82f6\" } : {}),\n ...(hover.list === \"selected\" && hover.id === t.id && hover.side === \"right\" ? { borderRight: \"3px solid #3b82f6\" } : {}),\n cursor: timeExpired ? \"not-allowed\" : (hover.list === \"selected\" && hover.id === t.id ? \"grabbing\" : \"grab\"),\n userSelect: \"none\",\n fontSize: `${getAdaptiveFontSize(selected.length)}px`, // Адаптивный размер шрифта для слов\n fontFamily: '\"Roboto\", system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, sans-serif', // Более плотный шрифт\n whiteSpace: \"nowrap\", // Запрещаем перенос слов\n opacity: timeExpired ? 0.6 : 1,\n transition: \"opacity 0.3s ease, transform 0.2s ease\",\n ...(hover.list === \"selected\" && hover.id === t.id ? { \n transform: \"scale(1.05)\",\n boxShadow: \"0 2px 8px rgba(59, 130, 246, 0.3)\"\n } : {}),\n }}\n >\n {t.text}\n </span>\n ))}\n </div>\n\n <button\n onClick={() => handleNext(true)}\n disabled={!timeExpired && selected.length === 0}\n style={{\n marginTop: isMobileDevice() ? \"15px\" : \"30px\",\n fontSize: isMobileDevice() ? \"14px\" : \"20px\",\n padding: isMobileDevice() ? \"6px 12px\" : \"10px 24px\",\n borderRadius: isMobileDevice() ? \"8px\" : \"12px\",\n background: (timeExpired || selected.length > 0) ? \"#ec4c44\" : \"#ccc\",\n color: \"white\",\n border: \"none\",\n cursor: (timeExpired || selected.length > 0) ? \"pointer\" : \"not-allowed\",\n }}\n >\n {timeExpired ? \"NEXT\" : \"NEXT\"}\n </button>\n </div>\n );\n\n const renderResults = () => (\n <div style={styles.gmCenterScreen}>\n <h1 style={{\n ...styles.gmHeadline1,\n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"0px\" : \"0px\",\n marginBottom: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"2px\" : \"10px\",\n fontSize: (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"32px\" : \"clamp(28px, 4vw, 40px)\"\n }}>\n Game Over 🎯\n </h1>\n <h2 style={{\n ...styles.gmHeadline2,\n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"0px\" : \"0px\",\n marginBottom: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"2px\" : \"16px\",\n fontSize: (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"18px\" : \"24px\"\n }}>\n Your score: {score} out of {rounds}\n </h2>\n <p style={{ \n ...styles.gmBodyM, \n color: \"#10b981\", \n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"0px\" : \"12px\",\n marginBottom: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"2px\" : \"16px\",\n fontSize: (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"14px\" : \"16px\"\n }}>\n Best score: {bestScore}\n </p>\n\n <div style={{ \n display: \"flex\", \n gap: (isMobile && window.innerWidth > window.innerHeight) || (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"6px\" : \"12px\", \n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"2px\" : (window.innerWidth === 1366 && window.innerHeight === 766) || (window.innerWidth === 1366 && window.innerHeight === 768) || (window.innerWidth === 1280 && window.innerHeight === 720) || (window.innerWidth === 1440 && window.innerHeight === 900) || isDesktopLayout ? \"12px\" : \"24px\"\n }}>\n <button\n onClick={() => {\n triggerConfetti();\n playSound(\"start\");\n setTimeout(() => {\n setStage(\"getready\");\n setCountdown(null);\n setTimeExpired(false);\n }, 800);\n }}\n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n 🔁 Play again\n </button>\n\n <button\n onClick={() => {\n playSound(\"click\");\n setStage(\"select\");\n setRounds(null);\n setTimePerRound(null);\n setSentences([]);\n setScore(0);\n setSelected([]);\n setTimeExpired(false);\n }}\n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n ⬅️ Exit\n </button>\n </div>\n </div>\n );\n\n // Условие для отображения логотипа (на desktop и планшетах)\n const shouldShowLogo = !isMobile && showLogo;\n\n const MemoizedLogo = useMemo(\n () => {\n // Скрываем логотип на мобильных устройствах в landscape режиме и на малых экранах\n if ((isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700) {\n return null;\n }\n \n if (!shouldShowLogo) {\n return null;\n }\n \n const logoBaseUrl = logoUrl || (typeof window !== 'undefined' && window.origin \n ? `${window.origin}/cloud/speakid/games/magic%20sentence/logo`\n : \"/cloud/speakid/games/magic%20sentence/logo\");\n \n return (\n // ensure logo is positioned inside the square container\n <div style={{ ...styles.gmLogoFixed, position: \"absolute\", top: 16, left: 16, zIndex: 30 }}>\n <picture>\n <source\n srcSet={`${logoBaseUrl}.svg`}\n type=\"image/svg+xml\"\n />\n <img\n src={`${logoBaseUrl}.png`}\n alt=\"SPEAKID Logo\"\n style={styles.gmLogoImg}\n loading=\"lazy\"\n />\n </picture>\n </div>\n );\n },\n [isMobile, shouldShowLogo, logoUrl]\n );\n\n return (\n <div\n ref={containerRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n background: \"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)\",\n transition: \"background 0.3s ease\",\n overflow: \"hidden\",\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0\n }}\n >\n <div\n style={{\n width: isMobile ? \"100%\" : (containerSize || 1000),\n height: isMobile ? \"100%\" : (containerSize || 1000),\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n overflow: \"hidden\",\n borderRadius: isMobile ? 0 : \"20px\",\n background: \"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)\",\n boxShadow: isMobile ? \"none\" : \"0 0 40px rgba(0,0,0,0.1)\",\n margin: isMobile ? \"0 auto\" : \"unset\",\n position: \"relative\", // needed so absolute logo is inside the square\n transform: `scale(${scale})`, // ✅ Применяем масштаб для широких экранов\n }}\n >\n <div\n style={{\n transform: \"translateZ(0)\",\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n }}\n >\n <div id=\"magic-sentence-root\">\n {MemoizedLogo}\n {stage === \"select\" ? renderSelect() : null}\n {stage === \"time\" ? renderTime() : null}\n {stage === \"type\" ? renderType() : null}\n {stage === \"getready\" ? renderGetReady() : null}\n {stage === \"play\" ? renderPlay() : null}\n {stage === \"results\" ? renderResults() : null}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default GameComponent;","import React, { Component, ErrorInfo, ReactNode } from 'react';\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n error?: Error;\n errorInfo?: ErrorInfo;\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return {\n hasError: true,\n error,\n };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n console.error('Game Error:', error, errorInfo);\n \n // В реальном приложении здесь можно отправить ошибку в аналитику\n // analytics.track('game_error', { error: error.message, stack: error.stack });\n \n this.setState({\n error,\n errorInfo,\n });\n }\n\n handleReset = () => {\n this.setState({ hasError: false, error: undefined, errorInfo: undefined });\n };\n\n render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '100vh',\n padding: '20px',\n textAlign: 'center',\n backgroundColor: '#fef2f2',\n color: '#dc2626',\n fontFamily: 'system-ui, sans-serif'\n }}>\n <h1 style={{ fontSize: '24px', marginBottom: '16px' }}>\n 🚨 Oops! Something went wrong\n </h1>\n <p style={{ fontSize: '16px', marginBottom: '24px', maxWidth: '500px' }}>\n The game encountered an unexpected error. Don't worry, your progress is saved!\n </p>\n \n <button\n onClick={this.handleReset}\n style={{\n padding: '12px 24px',\n fontSize: '16px',\n backgroundColor: '#dc2626',\n color: 'white',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'background-color 0.2s'\n }}\n onMouseOver={(e) => e.currentTarget.style.backgroundColor = '#b91c1c'}\n onMouseOut={(e) => e.currentTarget.style.backgroundColor = '#dc2626'}\n >\n 🔄 Restart Game\n </button>\n \n {typeof process !== 'undefined' && process.env.NODE_ENV === 'development' && this.state.error && (\n <details style={{ marginTop: '20px', textAlign: 'left', maxWidth: '600px' }}>\n <summary style={{ cursor: 'pointer', fontSize: '14px' }}>\n Technical Details (Development Only)\n </summary>\n <pre style={{\n backgroundColor: '#f3f4f6',\n padding: '12px',\n borderRadius: '4px',\n fontSize: '12px',\n overflow: 'auto',\n marginTop: '8px'\n }}>\n {this.state.error.toString()}\n {this.state.errorInfo?.componentStack}\n </pre>\n </details>\n )}\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n\n"],"names":["keyframes","styleTag","animations","styles","useValidation","errors","setErrors","useState","validateSentence","useCallback","sentence","index","allSentences","newErrors","duplicateIndex","s","i","validateAllSentences","sentences","allErrors","result","error","clearErrors","createAriaLabel","action","word","context","handleKeyDown","event","allowedKeys","announceToScreenReader","message","announcement","globalReset","style","existingStyle","shuffle","arr","GameComponent","props","logoUrl","showLogo","containerRef","useRef","validationErrors","shouldWrapWords","isMobile","isMobileDevice","getMobileButtonStyles","type","useEffect","stage","setStage","rounds","setRounds","timePerRound","setTimePerRound","setSentences","currentRound","setCurrentRound","words","setWords","selected","setSelected","timeLeft","setTimeLeft","score","setScore","countdown","setCountdown","resultType","setResultType","timeExpired","setTimeExpired","isCorrect","setIsCorrect","bestScore","setBestScore","timerRef","roundsRef","currentRoundRef","hover","setHover","setIsMobile","scale","setScale","containerSize","setContainerSize","isDesktopLayout","setIsDesktopLayout","isIPadMiniPortrait","setIsIPadMiniPortrait","isIPadMiniLandscape","setIsIPadMiniLandscape","isIPadAirPortrait","setIsIPadAirPortrait","isIPadAirLandscape","setIsIPadAirLandscape","isSurfaceDuoPortrait","setIsSurfaceDuoPortrait","isSurfaceDuoLandscape","setIsSurfaceDuoLandscape","isIPadProPortrait","setIsIPadProPortrait","isIPadProLandscape","setIsIPadProLandscape","isHorizontalLayout","setIsHorizontalLayout","isWideScreen","setIsWideScreen","resize","width","height","mobile","isSmallHeight","desktopLayout","isHorizontal","finalSize","moveToken","from","to","id","insertIndex","nextWords","nextSelected","takeFrom","putTo","idx","t","token","targetIndex","handleDropTo","raw","fallbackId","inBank","inSelected","payload","handleSelect","num","handleTimeSelect","time","handleChange","value","updated","validation","normalizeSentence","getAdaptiveFontSize","wordCount","startGame","prev","startRound","target","tokens","w","correct","correctWords","selectedTexts","missingWords","extraWords","wrongOrder","playSound","handleNext","manual","triggerConfetti","ctx","osc","gain","end","colors","canvas","pieces","draw","p","renderSelect","jsxs","jsx","renderTime","renderType","text","e","renderGetReady","renderPlay","rect","mid","children","closestIdx","minDistance","child","childRect","childCenter","distance","zoneWidth","renderResults","shouldShowLogo","MemoizedLogo","useMemo","logoBaseUrl","ErrorBoundary","Component","errorInfo"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speakid-build-a-sentence",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "description": "Magic Sentence Game - Interactive word building game for SPEAKID platform",
5
5
  "main": "dist/speakid-build-a-sentence.cjs.js",
6
6
  "module": "dist/speakid-build-a-sentence.es.js",