@mblinkov/whats-missing 20.0.43 → 20.0.45

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.
package/src/Game.tsx CHANGED
@@ -1,10 +1,8 @@
1
- import { useState, useEffect, useMemo, useRef, useLayoutEffect } from "react";
2
- import { createPortal } from "react-dom";
1
+ import { useState, useEffect, useMemo, useRef } from "react";
3
2
  import { themes } from "./themes";
4
3
  import { styles } from "./Game.styles";
5
4
  import type { Theme } from "./themes";
6
5
 
7
-
8
6
  type ImageItem = { src: string; name: string };
9
7
  type RoundResult = {
10
8
  round: number;
@@ -13,9 +11,40 @@ type RoundResult = {
13
11
  result: "correct" | "almost" | "wrong";
14
12
  };
15
13
 
16
- // ✅ globalReset удален - теперь используется Shadow DOM изоляция
14
+ // ✅ базовый reset
15
+ const globalReset = () => {
16
+ const style = document.createElement("style");
17
+ style.textContent = `
18
+ #whats-missing-root, #whats-missing-root * {
19
+ box-sizing: border-box;
20
+ font-family: "Geist", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
21
+ }
22
+ #whats-missing-root img {
23
+ max-width: 100%;
24
+ height: auto;
25
+ display: block;
26
+ user-select: none;
27
+ }
28
+ html, body {
29
+ margin: 0 !important;
30
+ padding: 0 !important;
31
+ width: 100% !important;
32
+ height: 100% !important;
33
+ overflow: hidden !important;
34
+ zoom: 1 !important; /* ✅ защита от подзума */
35
+ }
36
+ #root {
37
+ margin: 0 !important;
38
+ padding: 0 !important;
39
+ width: 100% !important;
40
+ height: 100% !important;
41
+ overflow: hidden !important;
42
+ }
43
+ `;
44
+ document.head.appendChild(style);
45
+ };
17
46
 
18
- // расстояние Левенштейна — для проверки “почти правильно”
47
+ // простая функция сравнения
19
48
  const levenshtein = (a: string, b: string) => {
20
49
  const dp = Array.from({ length: a.length + 1 }, () => Array(b.length + 1).fill(0));
21
50
  for (let i = 0; i <= a.length; i++) dp[i][0] = i;
@@ -31,114 +60,6 @@ const levenshtein = (a: string, b: string) => {
31
60
  return dp[a.length][b.length];
32
61
  };
33
62
 
34
- // ✅ фикс визуального подзума
35
- export function useNeutralizeBodyZoom(
36
- ref: React.RefObject<HTMLDivElement | null>,
37
- opts: { minDesktopWidth?: number; forceResize?: boolean } = { minDesktopWidth: 1200, forceResize: false }
38
- ) {
39
- const saved = useRef<Record<string, string | null> | null>(null);
40
- const minDesktopWidth = opts.minDesktopWidth ?? 1200;
41
- const forceResize = !!opts.forceResize;
42
-
43
- useLayoutEffect(() => {
44
- if (typeof window === "undefined" || !ref || !ref.current) return;
45
- const el = ref.current;
46
-
47
- const getBodyScale = (): number => {
48
- try {
49
- const body = document.body;
50
- const cs = getComputedStyle(body) as CSSStyleDeclaration & { zoom?: string };
51
- const zoomInline = parseFloat((body.style && body.style.zoom) || "");
52
- if (zoomInline && !isNaN(zoomInline) && zoomInline > 0) return zoomInline;
53
- const zoomComputed = parseFloat((cs.zoom as string) || "");
54
- if (zoomComputed && !isNaN(zoomComputed) && zoomComputed > 0) return zoomComputed;
55
- const probe = document.createElement("div");
56
- probe.style.position = "absolute";
57
- probe.style.left = "0";
58
- probe.style.top = "0";
59
- probe.style.width = "100px";
60
- probe.style.height = "1px";
61
- probe.style.visibility = "hidden";
62
- document.documentElement.appendChild(probe);
63
- const rect = probe.getBoundingClientRect();
64
- document.documentElement.removeChild(probe);
65
- if (rect && rect.width > 0) {
66
- const measured = rect.width / 100;
67
- if (!isNaN(measured) && measured > 0) return measured;
68
- }
69
- } catch {}
70
- return 1;
71
- };
72
-
73
- const apply = () => {
74
- if (minDesktopWidth && window.innerWidth < minDesktopWidth) {
75
- restore();
76
- return;
77
- }
78
- const scale = getBodyScale();
79
- if (!scale || scale === 1) {
80
- restore();
81
- return;
82
- }
83
- if (!saved.current) {
84
- saved.current = {
85
- transform: el.style.transform || null,
86
- transformOrigin: el.style.transformOrigin || null,
87
- width: el.style.width || null,
88
- height: el.style.height || null,
89
- willChange: el.style.willChange || null,
90
- };
91
- }
92
- const inv = 1 / scale;
93
- if (forceResize) {
94
- el.style.width = `${scale * 100}%`;
95
- el.style.height = `${scale * 100}%`;
96
- }
97
- el.style.transformOrigin = "50% 50%";
98
- el.style.transform = `scale(${inv})`;
99
- el.style.willChange = "transform";
100
- };
101
-
102
- const restore = () => {
103
- if (!saved.current) return;
104
- const s = saved.current;
105
- el.style.transform = s.transform ?? "";
106
- el.style.transformOrigin = s.transformOrigin ?? "";
107
- el.style.width = s.width ?? "";
108
- el.style.height = s.height ?? "";
109
- el.style.willChange = s.willChange ?? "";
110
- saved.current = null;
111
- };
112
-
113
- let raf = 0;
114
- const scheduled = () => {
115
- cancelAnimationFrame(raf);
116
- raf = requestAnimationFrame(apply);
117
- };
118
- const mo = new MutationObserver((m) => {
119
- for (const x of m)
120
- if (x.type === "attributes" && (x.attributeName === "style" || x.attributeName === "class")) {
121
- scheduled();
122
- break;
123
- }
124
- });
125
- mo.observe(document.body, { attributes: true, attributeFilter: ["style", "class"] });
126
- window.addEventListener("resize", scheduled);
127
- scheduled();
128
-
129
- return () => {
130
- cancelAnimationFrame(raf);
131
- mo.disconnect();
132
- window.removeEventListener("resize", scheduled);
133
- restore();
134
- };
135
- }, [ref, minDesktopWidth, forceResize]);
136
- }
137
-
138
- // =====================================
139
- // ИГРА
140
- // =====================================
141
-
142
63
  export default function Game({
143
64
  gameCubeSize,
144
65
  screenHeight,
@@ -148,119 +69,10 @@ export default function Game({
148
69
  screenHeight?: number;
149
70
  screenWidth?: number;
150
71
  }) {
151
- const containerRef = useRef<HTMLDivElement | null>(null);
152
- const squareRef = useRef<HTMLDivElement | null>(null);
153
- const [squareSize, setSquareSize] = useState<number | null>(null);
154
- const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);
155
- useNeutralizeBodyZoom(containerRef, { minDesktopWidth: 1024, forceResize: false });
156
-
157
- // ✅ Shadow DOM изоляция - создаем сначала, потом рендерим
158
- useLayoutEffect(() => {
159
- const container = containerRef.current;
160
- if (!container) return;
161
-
162
- // Создаем Shadow DOM если его нет
163
- let root = container.shadowRoot;
164
- if (!root) {
165
- root = container.attachShadow({ mode: 'open' });
166
- }
167
-
168
- // Растягиваем хост-элемент на весь экран
169
- container.style.position = 'fixed';
170
- container.style.top = '0';
171
- container.style.left = '0';
172
- container.style.width = '100vw';
173
- container.style.height = '100vh';
174
- container.style.zIndex = '9999';
175
- container.style.background = 'linear-gradient(to bottom, #fff8f8, #f9fafb)';
176
- container.style.margin = '0';
177
- container.style.padding = '0';
178
- container.style.transform = 'none';
179
- container.style.zoom = '1';
180
-
181
- // Очищаем содержимое shadow root
182
- root.innerHTML = '';
183
-
184
- // Создаем стили для изоляции
185
- const style = document.createElement('style');
186
- style.textContent = `
187
- :host {
188
- display: flex;
189
- justify-content: center;
190
- align-items: center;
191
- overflow: hidden;
192
- }
193
-
194
- #whats-missing-root, #whats-missing-root * {
195
- box-sizing: border-box;
196
- }
197
-
198
- #whats-missing-root img {
199
- max-width: 100%;
200
- height: auto;
201
- display: block;
202
- user-select: none;
203
- }
204
-
205
- #whats-missing-root {
206
- position: relative;
207
- width: 100%;
208
- height: 100%;
209
- max-width: 1200px;
210
- display: flex;
211
- justify-content: center;
212
- align-items: center;
213
- }
214
- `;
215
-
216
- // Добавляем стили в shadow root
217
- root.appendChild(style);
218
-
219
- // Устанавливаем shadow root для рендера
220
- setShadowRoot(root);
221
- }, []);
222
-
223
- useEffect(() => {
224
- const b = document.body;
225
- const h = document.documentElement;
226
-
227
- const oldBodyZoom = b.style.zoom;
228
- const oldBodyTransform = b.style.transform;
229
- const oldHtmlZoom = h.style.zoom;
230
- const oldHtmlTransform = h.style.transform;
231
-
232
- b.style.zoom = "1";
233
- b.style.transform = "none";
234
- h.style.zoom = "1";
235
- h.style.transform = "none";
236
-
237
- return () => {
238
- b.style.zoom = oldBodyZoom;
239
- b.style.transform = oldBodyTransform;
240
- h.style.zoom = oldHtmlZoom;
241
- h.style.transform = oldHtmlTransform;
242
- };
243
- }, []);
244
-
245
- // ✅ защита от слишком маленьких размеров игры
246
- const effectiveGameCubeSize = useMemo(() => {
247
- const baseSize = gameCubeSize ?? Math.min(screenWidth ?? 1000, screenHeight ?? 1000);
248
- const currentWidth = screenWidth ?? (typeof window !== "undefined" ? window.innerWidth : 1000);
249
-
250
- // минимальный предел для десктопа и планшета
251
- if (baseSize < 600 && currentWidth > 768) {
252
- return 600;
253
- }
254
-
255
- // для мобилок в портретной ориентации пусть остаётся адаптивным
256
- if (currentWidth <= 768) {
257
- return Math.min(baseSize, currentWidth - 20);
258
- }
259
-
260
- return baseSize;
261
- }, [gameCubeSize, screenWidth, screenHeight]);
72
+ const containerRef = useRef<HTMLDivElement>(null);
262
73
 
263
74
  useEffect(() => {
75
+ globalReset();
264
76
  return () => {
265
77
  document.body.style.overflow = "";
266
78
  };
@@ -285,44 +97,121 @@ export default function Game({
285
97
  const [resultsTable, setResultsTable] = useState<RoundResult[]>([]);
286
98
  const [usedHidden, setUsedHidden] = useState<string[]>([]);
287
99
  const [isMobile, setIsMobile] = useState(false);
288
-
289
- // simple responsive flag; we still compute exact sizes from the measured square
100
+ const [scale, setScale] = useState(1);
101
+ const [containerSize, setContainerSize] = useState<number | null>(null);
102
+ const [isDesktopLayout, setIsDesktopLayout] = useState(false);
103
+ const [isIPadMiniPortrait, setIsIPadMiniPortrait] = useState(false);
104
+ const [isIPadMiniLandscape, setIsIPadMiniLandscape] = useState(false);
105
+ const [isIPadAirPortrait, setIsIPadAirPortrait] = useState(false);
106
+ const [isIPadAirLandscape, setIsIPadAirLandscape] = useState(false);
107
+ const [isSurfaceDuoPortrait, setIsSurfaceDuoPortrait] = useState(false);
108
+ const [isSurfaceDuoLandscape, setIsSurfaceDuoLandscape] = useState(false);
109
+ const [isIPadProPortrait, setIsIPadProPortrait] = useState(false);
110
+ const [isIPadProLandscape, setIsIPadProLandscape] = useState(false);
111
+
112
+ // ✅ адаптив под мобилки, планшеты и десктоп
290
113
  useEffect(() => {
291
- if (typeof window === "undefined") return;
292
- const update = () => {
293
- const w = screenWidth ?? window.innerWidth;
294
- const hasCoarsePointer = window.matchMedia && window.matchMedia('(pointer: coarse)').matches;
295
- setIsMobile(w <= 768 || hasCoarsePointer);
296
- };
297
- update();
298
- window.addEventListener("resize", update);
299
- window.addEventListener("orientationchange", update);
300
- return () => {
301
- window.removeEventListener("resize", update);
302
- window.removeEventListener("orientationchange", update);
114
+ const resize = () => {
115
+ const width = screenWidth ?? window.innerWidth;
116
+ const height = screenHeight ?? window.innerHeight;
117
+ const mobile = width < 768 || (width === 926 && height === 428) || (width === 932 && height === 430); // iPhone 14 Pro Max в landscape тоже считается мобильным
118
+ const isLandscape = (width > height && mobile) || (width === 926 && height === 428) || (width === 932 && height === 430); // iPhone 14 Pro Max в landscape
119
+ const isSmallHeight = height < 700; // Nest Hub, маленькие экраны
120
+
121
+ // Определяем iPhone до 14 Pro Max в landscape режиме
122
+ // iPhone 14 Pro Max: 926x428 (landscape)
123
+ // iPhone 13 Pro Max: 926x428 (landscape)
124
+ // iPhone 12 Pro Max: 926x428 (landscape)
125
+ // iPhone 11 Pro Max: 896x414 (landscape)
126
+ // iPhone XR: 896x414 (landscape)
127
+ // iPhone XS Max: 896x414 (landscape)
128
+ // iPhone X: 812x375 (landscape)
129
+ // iPhone 8 Plus: 736x414 (landscape)
130
+ // iPhone 8: 667x375 (landscape)
131
+ // iPhone SE: 667x375 (landscape)
132
+
133
+ // iPhone XR: 896x414 (landscape)
134
+ const isIPhoneXRLandscape = isLandscape && width === 896 && height === 414;
135
+
136
+ // iPhone 12 Pro: 844x390 (landscape)
137
+ const isIPhone12ProLandscape = isLandscape && width === 844 && height === 390;
138
+
139
+ // Разрешение 1366x766 - ноутбуки и небольшие десктопы
140
+ const is1366x766 = width === 1366 && height === 766;
141
+
142
+ // Разрешение 1366x768 - ноутбуки и небольшие десктопы
143
+ const is1366x768 = width === 1366 && height === 768;
144
+
145
+ // Разрешение 1280x720 - ноутбуки и небольшие десктопы
146
+ const is1280x720 = width === 1280 && height === 720;
147
+
148
+ // Разрешение 1440x900 - ноутбуки и небольшие десктопы
149
+ const is1440x900 = width === 1440 && height === 900;
150
+
151
+ // iPad Mini/Air размеры
152
+ // iPad Mini: 768x1024 (portrait), 1024x768 (landscape) - Chrome DevTools размеры
153
+ // iPad Air: 820x1180 (portrait), 1180x820 (landscape)
154
+ const isIPadMiniPortrait = width === 768 && height === 1024;
155
+ const isIPadMiniLandscape = width === 1024 && height === 768;
156
+ const isIPadAirPortrait = width === 820 && height === 1180;
157
+ const isIPadAirLandscape = width === 1180 && height === 820;
158
+
159
+ // Surface DUO размеры
160
+ // Surface DUO: 540x720 (portrait), 720x540 (landscape)
161
+ const isSurfaceDuoPortrait = width === 540 && height === 720;
162
+ const isSurfaceDuoLandscape = width === 720 && height === 540;
163
+
164
+ // iPad Pro размеры
165
+ // iPad Pro: 1024x1366 (portrait), 1366x1024 (landscape)
166
+ const isIPadProPortrait = width === 1024 && height === 1366;
167
+ const isIPadProLandscape = width === 1366 && height === 1024;
168
+
169
+ // Популярные разрешения для горизонтального расположения кнопки Check
170
+ const desktopLayout = width >= 1200 && height >= 600 && !mobile;
171
+ setIsDesktopLayout(desktopLayout);
172
+
173
+ // Установка состояний для iPad и Surface DUO
174
+ setIsIPadMiniPortrait(isIPadMiniPortrait);
175
+ setIsIPadMiniLandscape(isIPadMiniLandscape);
176
+ setIsIPadAirPortrait(isIPadAirPortrait);
177
+ setIsIPadAirLandscape(isIPadAirLandscape);
178
+ setIsSurfaceDuoPortrait(isSurfaceDuoPortrait);
179
+ setIsSurfaceDuoLandscape(isSurfaceDuoLandscape);
180
+ setIsIPadProPortrait(isIPadProPortrait);
181
+ setIsIPadProLandscape(isIPadProLandscape);
182
+
183
+ const isOldIPhoneLandscape = isLandscape && height <= 428; // до iPhone 14 Pro Max включительно
184
+
185
+ // treat only phones as "mobile" so tablets use the desktop (square/centered) layout
186
+ setIsMobile(mobile);
187
+
188
+ // ✅ Используем gameCubeSize от родительского сайта, но с защитой от слишком маленьких размеров
189
+ if (mobile) {
190
+ // Мобилки: используем переданный gameCubeSize или полную ширину
191
+ setContainerSize(gameCubeSize && gameCubeSize >= 320 ? gameCubeSize : null);
192
+ setScale(1);
193
+ } else if (isSmallHeight) {
194
+ // Маленькие экраны: используем переданный gameCubeSize или полную высоту
195
+ setContainerSize(gameCubeSize && gameCubeSize >= 400 ? gameCubeSize : null);
196
+ setScale(1);
197
+ } else {
198
+ // Десктопы: используем переданный gameCubeSize с разумными ограничениями
199
+ const minSize = 400;
200
+ const maxSize = 1200;
201
+ const finalSize = gameCubeSize
202
+ ? Math.max(minSize, Math.min(maxSize, gameCubeSize))
203
+ : Math.min(1000, Math.min(width, height) * 0.9);
204
+ setContainerSize(finalSize);
205
+ setScale(1);
206
+ }
303
207
  };
304
- }, [screenWidth]);
208
+ resize();
209
+ window.addEventListener("resize", resize);
210
+ return () => window.removeEventListener("resize", resize);
211
+ }, [screenWidth, screenHeight, gameCubeSize]);
305
212
 
306
- useLayoutEffect(() => {
307
- const el = squareRef.current;
308
- if (!el || typeof window === "undefined") return;
309
- let ro: ResizeObserver | null = null;
310
- try {
311
- ro = new ResizeObserver((entries) => {
312
- for (const e of entries) {
313
- const cr = e.contentRect;
314
- setSquareSize(Math.round(Math.min(cr.width, cr.height)));
315
- }
316
- });
317
- ro.observe(el);
318
- setSquareSize(Math.round(Math.min(el.clientWidth, el.clientHeight)));
319
- } catch {
320
- setSquareSize(Math.round(Math.min(el.clientWidth, el.clientHeight)));
321
- }
322
- return () => ro?.disconnect();
323
- }, [isMobile]);
324
-
325
- const getRandomSix = (arr: ImageItem[]) => [...arr].sort(() => Math.random() - 0.5).slice(0, 6);
213
+ const getRandomSix = (arr: ImageItem[]) =>
214
+ [...arr].sort(() => Math.random() - 0.5).slice(0, 6);
326
215
 
327
216
  const startGame = () => {
328
217
  if (!theme) return;
@@ -431,279 +320,697 @@ export default function Game({
431
320
  };
432
321
 
433
322
  const MemoizedLogo = useMemo(
434
- () => (
435
- <div style={{ ...styles.gmLogoFixed, position: "absolute", top: 16, left: 16, zIndex: 30 }}>
436
- <picture>
437
- <source
438
- srcSet={window.origin + "/cloud/speakid/games/whatsmissing/logo.svg"}
439
- type="image/svg+xml"
440
- />
441
- <img
442
- src={window.origin + "/cloud/speakid/games/whatsmissing/logo.png"}
443
- alt="SPEAKID Logo"
444
- style={styles.gmLogoImg}
445
- loading="lazy"
446
- />
447
- </picture>
448
- </div>
449
- ),
450
- []
323
+ () => {
324
+ // Скрываем логотип на мобильных устройствах в landscape режиме и на малых экранах
325
+ if ((isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700) {
326
+ return null;
327
+ }
328
+
329
+ return (
330
+ // ensure logo is positioned inside the square container
331
+ <div style={{ ...styles.gmLogoFixed, position: "absolute", top: 16, left: 16, zIndex: 30 }}>
332
+ <picture>
333
+ <source
334
+ srcSet={window.origin + "/cloud/speakid/games/whatsmissing/logo.svg"}
335
+ type="image/svg+xml"
336
+ />
337
+ <img
338
+ src={window.origin + "/cloud/speakid/games/whatsmissing/logo.png"}
339
+ alt="SPEAKID Logo"
340
+ style={styles.gmLogoImg}
341
+ loading="lazy"
342
+ />
343
+ </picture>
344
+ </div>
345
+ );
346
+ },
347
+ [isMobile]
451
348
  );
452
349
 
453
- // ✅ масштаб интерфейса под размеры окна — с мягкими лимитами и кэшированием
454
- // оптимизированные базовые размеры для лучшего покрытия экрана на десктопах
455
- const baseWidth = 1200;
456
- const baseHeight = 700;
457
- const scale = useMemo(() => {
458
- const effectiveWidth = screenWidth ?? (typeof window !== "undefined" ? window.innerWidth : baseWidth);
459
- const effectiveHeight = screenHeight ?? (typeof window !== "undefined" ? window.innerHeight : baseHeight);
460
- const rawScale = Math.min(effectiveWidth / baseWidth, effectiveHeight / baseHeight);
461
- // мягкие границы роста/сжатия - увеличен верхний лимит для лучшего заполнения экрана
462
- return Math.min(1.35, Math.max(1.0, rawScale));
463
- }, [screenWidth, screenHeight, isMobile]);
464
-
465
350
  return (
466
- <div ref={containerRef} style={{ width: "100%", height: "100%" }}>
467
- {shadowRoot && createPortal(
351
+ <div
352
+ ref={containerRef}
353
+ style={{
354
+ width: "100%",
355
+ height: "100%",
356
+ display: "flex",
357
+ justifyContent: "center",
358
+ alignItems: "center",
359
+ background: "linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",
360
+ transition: "background 0.3s ease",
361
+ overflow: "hidden",
362
+ position: "absolute",
363
+ top: 0,
364
+ left: 0,
365
+ right: 0,
366
+ bottom: 0
367
+ }}
368
+ >
369
+ <div
370
+ style={{
371
+ width: isMobile ? "100%" : (containerSize || gameCubeSize || 1000),
372
+ height: isMobile ? "100%" : (containerSize || gameCubeSize || 1000),
373
+ display: "flex",
374
+ justifyContent: "center",
375
+ alignItems: "center",
376
+ overflow: "hidden",
377
+ borderRadius: isMobile ? 0 : "20px",
378
+ background: "linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",
379
+ boxShadow: isMobile ? "none" : "0 0 40px rgba(0,0,0,0.1)",
380
+ margin: isMobile ? "0 auto" : "unset",
381
+ position: "relative", // needed so absolute logo is inside the square
382
+ }}
383
+ >
468
384
  <div
469
- id="whats-missing-root"
470
- style={{ all: "unset" }}
385
+ style={{
386
+ transform: "none",
387
+ width: "100%",
388
+ height: "100%",
389
+ display: "flex",
390
+ justifyContent: "center",
391
+ alignItems: "center",
392
+ }}
471
393
  >
472
- <div
473
- ref={squareRef}
474
- style={{
475
- width: isMobile
476
- ? "100%"
477
- : `${effectiveGameCubeSize}px`,
478
- height: isMobile
479
- ? "100%"
480
- : `${effectiveGameCubeSize}px`,
481
- borderRadius: isMobile ? 0 : "20px",
482
- background: "linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",
483
- position: "relative",
484
- overflow: "hidden",
485
- boxShadow: isMobile ? "none" : "0 0 40px rgba(0,0,0,0.08)",
486
- display: "flex",
487
- justifyContent: "center",
488
- alignItems: "center",
489
- }}
490
- >
491
- <div
492
- style={{
493
- transform: `scale(${scale})`,
494
- transformOrigin: "center center",
495
- transition: "transform 0.2s ease-out",
496
- width: "100%",
497
- height: "100%",
498
- display: "flex",
499
- flexDirection: "column",
500
- justifyContent: "center",
501
- alignItems: "center",
502
- }}
503
- >
504
- {!isMobile && MemoizedLogo}
505
-
506
- {/* ====== ЛОББИ ====== */}
507
- {!theme && !started && (
508
- <div style={styles.gmCenterScreen}>
509
- <h1 style={styles.gmHeadline1}>WHAT'S MISSING?</h1>
510
- <p style={styles.gmBodyM}>Select a theme:</p>
511
- <div style={{ display: "flex", gap: 16 }}>
512
- {["animals", "food", "toys"].map((t) => (
513
- <button key={t} style={styles.gmButton} onClick={() => setTheme(t as Theme)}>
514
- {t === "animals" ? "🐶 Animals" : t === "food" ? "🍎 Food" : "🧸 Toys"}
515
- </button>
516
- ))}
517
- </div>
518
- <div style={{ marginTop: 24 }}>
519
- <p style={styles.gmBodyS}>Choose number of rounds:</p>
520
- <div style={{ display: "flex", gap: 12, marginTop: 8 }}>
521
- {[3, 4, 5].map((n) => (
522
- <button
523
- key={n}
524
- style={{
525
- ...styles.gmButton,
526
- ...(rounds === n ? styles.gmButtonActive : {}),
527
- }}
528
- onClick={() => setRounds(n)}
529
- >
530
- {n}
394
+ <div id="whats-missing-root">
395
+ {!isMobile && MemoizedLogo}
396
+ {/* ====== ИГРОВАЯ ЛОГИКА ====== */}
397
+ {!theme && !started && (
398
+ <div style={styles.gmCenterScreen}>
399
+ <h1 style={styles.gmHeadline1}>WHAT'S MISSING?</h1>
400
+ <p style={styles.gmBodyM}>Select a theme:</p>
401
+ <div style={{ display: "flex", 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) ? "8px" : "16px" }}>
402
+ {["animals", "food", "toys"].map((t) => (
403
+ <button key={t} style={{
404
+ ...styles.gmButton,
405
+ padding: (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) ? "8px 12px" : "12px 24px",
406
+ fontSize: (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) ? "12px" : "16px",
407
+ minWidth: (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) ? "70px" : "auto"
408
+ }} onClick={() => setTheme(t as Theme)}>
409
+ {t === "animals" ? "🐶 Animals" : t === "food" ? "🍎 Food" : "🧸 Toys"}
531
410
  </button>
532
411
  ))}
533
412
  </div>
413
+ <div style={{ marginTop: 24 }}>
414
+ <p style={styles.gmBodyS}>Choose number of rounds:</p>
415
+ <div style={{ display: "flex", 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", marginTop: 8 }}>
416
+ {[3, 4, 5].map((n) => (
417
+ <button
418
+ key={n}
419
+ style={{
420
+ ...styles.gmButton,
421
+ ...(rounds === n ? styles.gmButtonActive : {}),
422
+ padding: (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 10px" : "12px 24px",
423
+ fontSize: (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) ? "12px" : "16px",
424
+ minWidth: (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) ? "40px" : "auto"
425
+ }}
426
+ onClick={() => setRounds(n)}
427
+ >
428
+ {n}
429
+ </button>
430
+ ))}
431
+ </div>
432
+ </div>
534
433
  </div>
535
- </div>
536
- )}
537
-
538
- {/* ====== ПОДТВЕРЖДЕНИЕ ====== */}
539
- {theme && !started && (
540
- <div style={styles.gmCenterScreen}>
541
- <h1 style={styles.gmHeadline1}>Theme selected: {theme}</h1>
542
- <p style={styles.gmBodyM}>Rounds: {rounds}</p>
543
- <button style={styles.gmButton} onClick={startGame}>
544
- Start game
545
- </button>
546
- </div>
547
- )}
548
-
549
- {/* ====== РЕЗУЛЬТАТЫ ====== */}
550
- {finished && (
551
- <div style={styles.gmCenterScreen}>
552
- <h1 style={styles.gmHeadline1}>Results</h1>
553
- <h2 style={styles.gmHeadline3}>
434
+ )}
435
+ {theme && !started && (
436
+ <div style={styles.gmCenterScreen}>
437
+ <h1 style={styles.gmHeadline1}>Theme selected: {theme}</h1>
438
+ <p style={styles.gmBodyM}>Rounds: {rounds}</p>
439
+ <button style={{
440
+ ...styles.gmButton,
441
+ padding: (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) ? "8px 16px" : "12px 24px",
442
+ fontSize: (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) ? "14px" : "16px",
443
+ minWidth: (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) ? "120px" : "auto"
444
+ }} onClick={startGame}>
445
+ ▶ Start game
446
+ </button>
447
+ </div>
448
+ )}
449
+ {finished && (
450
+ <div style={styles.gmCenterScreen}>
451
+ <h1 style={{
452
+ ...styles.gmHeadline1,
453
+ 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" : styles.gmHeadline1.marginTop,
454
+ 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" : styles.gmHeadline1.marginBottom
455
+ }}>Results</h1>
456
+ <h2 style={{
457
+ ...styles.gmHeadline3,
458
+ 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" : styles.gmHeadline3.marginTop,
459
+ 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" : styles.gmHeadline3.marginBottom
460
+ }}>
554
461
  Your score: {score} / {rounds}
555
462
  </h2>
556
- <p style={{ ...styles.gmBodyM, color: "#10b981", marginTop: 12 }}>
557
- Yahoo! You did it! 🍬✨
558
- </p>
559
- <table style={styles.gmTable}>
560
- <thead>
561
- <tr>
562
- <th>Round</th>
563
- <th>Your Answer</th>
564
- <th>Correct</th>
565
- <th>Result</th>
566
- </tr>
567
- </thead>
568
- <tbody>
569
- {resultsTable.map((r, i) => (
570
- <tr key={i}>
571
- <td style={styles.gmTableCell}>{r.round}</td>
572
- <td style={styles.gmTableCell}>{r.answer || "—"}</td>
573
- <td style={styles.gmTableCell}>{r.correct}</td>
574
- <td style={styles.gmTableCell}>
575
- {r.result === "correct"
576
- ? "✔ Correct"
577
- : r.result === "almost"
578
- ? "◐ Almost (0.5)"
579
- : "✘ Wrong"}
580
- </td>
463
+ <p style={{
464
+ ...styles.gmBodyM,
465
+ color: "#10b981",
466
+ 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",
467
+ 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" : styles.gmBodyM.marginBottom
468
+ }}>Yahoo! You did it! 🍬✨</p>
469
+ <table style={{
470
+ ...styles.gmTable,
471
+ 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" : "20px",
472
+ 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 ? "4px" : "32px"
473
+ }}>
474
+ <thead>
475
+ <tr>
476
+ <th>Round</th>
477
+ <th>Your Answer</th>
478
+ <th>Correct</th>
479
+ <th>Result</th>
581
480
  </tr>
582
- ))}
583
- </tbody>
584
- </table>
585
- <div style={{ display: "flex", gap: 12, marginTop: 24 }}>
586
- <button style={styles.gmButton} onClick={startGame}>
587
- 🔁 Play again
588
- </button>
589
- <button style={styles.gmButton} onClick={exitGame}>
590
- ⬅️ Choose theme
591
- </button>
592
- </div>
593
- </div>
594
- )}
595
-
596
- {/* ====== ИГРОВОЙ ЭКРАН ====== */}
597
- {started && !finished && (
598
- <div style={styles.gmGameLayout}>
599
- <div
600
- style={{
601
- minHeight: 160,
602
- display: "flex",
603
- flexDirection: "column",
604
- justifyContent: "center",
605
- alignItems: "center",
606
- }}
607
- >
608
- {phase === "ready" && (
609
- <>
610
- <h1 style={{ ...styles.gmHeadline1, color: "#ec4c44" }}>GET READY</h1>
611
- <div style={styles.gmHourglass}>⏳</div>
612
- </>
613
- )}
614
- {phase === "memorize" && (
615
- <p style={{ ...styles.gmBodyM, color: "#10b981" }}>
616
- MEMORIZE ({memorizeTime})
617
- </p>
618
- )}
619
- {phase === "guess" && !answered && (
620
- <p style={styles.gmBodyM}>⏳ Time left: {timeLeft}s</p>
621
- )}
481
+ </thead>
482
+ <tbody>
483
+ {resultsTable.map((r, i) => (
484
+ <tr key={i}>
485
+ <td style={styles.gmTableCell}>{r.round}</td>
486
+ <td style={styles.gmTableCell}>{r.answer || "—"}</td>
487
+ <td style={styles.gmTableCell}>{r.correct}</td>
488
+ <td style={styles.gmTableCell}>
489
+ {r.result === "correct"
490
+ ? "✔ Correct"
491
+ : r.result === "almost"
492
+ ? "◐ Almost (0.5)"
493
+ : "✘ Wrong"}
494
+ </td>
495
+ </tr>
496
+ ))}
497
+ </tbody>
498
+ </table>
499
+ <div style={{
500
+ display: "flex",
501
+ 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",
502
+ 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"
503
+ }}>
504
+ <button style={{
505
+ ...styles.gmButton,
506
+ padding: (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 10px" : "12px 24px",
507
+ fontSize: (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) ? "12px" : "16px",
508
+ minWidth: (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) ? "80px" : "auto"
509
+ }} onClick={startGame}>
510
+ 🔁 Play again
511
+ </button>
512
+ <button style={{
513
+ ...styles.gmButton,
514
+ padding: (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 10px" : "12px 24px",
515
+ fontSize: (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) ? "12px" : "16px",
516
+ minWidth: (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) ? "80px" : "auto"
517
+ }} onClick={exitGame}>
518
+ ⬅️ Choose theme
519
+ </button>
520
+ </div>
622
521
  </div>
623
-
624
- {/* ===== Сетка карточек (фикс 3×2 на десктопе, 2×3 на мобилках) ===== */}
625
- {phase !== "ready" && (
522
+ )}
523
+ {started && !finished && (
524
+ <div style={styles.gmGameLayout}>
626
525
  <div
627
526
  style={{
628
- ...styles.gmGrid,
629
- display: "grid",
630
- gridTemplateColumns: `repeat(${isMobile ? 2 : 3}, 1fr)`,
631
- gridTemplateRows: `repeat(${isMobile ? 3 : 2}, 1fr)`,
632
- gap: isMobile ? 12 : 20,
527
+ minHeight: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
528
+ ? "45px" // iPhone SE: еще более компактная высота
529
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
530
+ ? "45px" // iPhone до 14 Pro Max в landscape: такая же компактная как SE
531
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
532
+ ? "45px" // iPhone XR в landscape: такая же компактная как SE
533
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
534
+ ? "45px" // iPhone 12 Pro в landscape: такая же компактная как SE
535
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
536
+ ? "45px" // iPhone 14 Pro Max в landscape: такая же компактная как SE
537
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700
538
+ ? "60px" // iPhone landscape и малые экраны: компактная высота
539
+ : "160px",
540
+ display: "flex",
541
+ flexDirection: "column",
633
542
  justifyContent: "center",
634
- alignContent: "center",
635
- padding: isMobile ? 8 : 16,
636
- width: "100%",
637
- height: "100%",
638
- maxWidth: isMobile ? "100%" : 600,
639
- maxHeight: isMobile ? "100%" : 400,
640
- boxSizing: "border-box",
543
+ alignItems: "center",
544
+ paddingTop: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
545
+ ? "8px" // iPhone SE: поднимаем таймер еще выше
546
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
547
+ ? "8px" // iPhone до 14 Pro Max в landscape: поднимаем еще выше
548
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
549
+ ? "8px" // iPhone XR в landscape: поднимаем еще выше
550
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
551
+ ? "8px" // iPhone 12 Pro в landscape: поднимаем еще выше
552
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
553
+ ? "8px" // iPhone 14 Pro Max в landscape: поднимаем еще выше
554
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700
555
+ ? "15px" // iPhone landscape и малые экраны: поднимаем выше
556
+ : "40px"
641
557
  }}
642
558
  >
643
- {files.map((file, i) => {
644
- const isHidden = hiddenIndex === i && phase === "guess" && !answered;
645
- return (
646
- <div
647
- key={i}
648
- style={{
649
- ...styles.gmCard,
650
- width: "100%",
651
- height: "100%",
652
- ...(result === "correct" && hiddenIndex === i ? styles.gmCorrect : {}),
653
- ...(result === "wrong" && hiddenIndex === i ? styles.gmWrong : {}),
654
- }}
655
- >
656
- {!isHidden && (
657
- <img
658
- src={file.src}
659
- alt={file.name}
559
+ {phase === "ready" && (
560
+ <>
561
+ <h1 style={{ ...styles.gmHeadline1, color: "#ec4c44" }}>GET READY</h1>
562
+ <div style={styles.gmHourglass}>⏳</div>
563
+ </>
564
+ )}
565
+ {phase === "memorize" && (
566
+ <p style={{ ...styles.gmBodyM, color: "#10b981" }}>
567
+ MEMORIZE ({memorizeTime})
568
+ </p>
569
+ )}
570
+ {phase === "guess" && !answered && (
571
+ <p style={styles.gmBodyM}>⏳ Time left: {timeLeft}s</p>
572
+ )}
573
+ </div>
574
+ {phase !== "ready" && (
575
+ <div
576
+ style={{
577
+ ...styles.gmGrid,
578
+ gridTemplateColumns: isMobile && window.innerWidth > window.innerHeight
579
+ ? "repeat(3, 1fr)" // mobile landscape: 3 колонки
580
+ : isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
581
+ ? "repeat(3, 1fr)" // iPhone SE: 3 колонки для лучшего использования пространства
582
+ : isMobile
583
+ ? "repeat(2, 1fr)" // mobile portrait: 2 колонки
584
+ : window.innerHeight < 700
585
+ ? "repeat(3, 1fr)" // Nest Hub и малые экраны: 3 колонки
586
+ : "repeat(3, 210px)", // desktop: 3 колонки фиксированного размера
587
+ gridAutoRows: isMobile && window.innerWidth > window.innerHeight
588
+ ? "120px" // mobile landscape: меньшая высота
589
+ : isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
590
+ ? "100px" // iPhone SE: очень компактная высота
591
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
592
+ ? "100px" // iPhone XR в landscape: такая же компактная как SE
593
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
594
+ ? "100px" // iPhone 12 Pro в landscape: такая же компактная как SE
595
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
596
+ ? "100px" // iPhone 14 Pro Max в landscape: такая же компактная как SE
597
+ : isMobile
598
+ ? "150px" // mobile portrait: стандартная высота
599
+ : window.innerHeight < 700
600
+ ? "140px" // Nest Hub: компактная высота
601
+ : "210px", // desktop: стандартная высота
602
+ gap: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
603
+ ? "12px" // iPhone SE: больше отступов
604
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
605
+ ? "12px" // iPhone XR в landscape: такие же отступы как SE
606
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
607
+ ? "12px" // iPhone 12 Pro в landscape: такие же отступы как SE
608
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
609
+ ? "12px" // iPhone 14 Pro Max в landscape: такие же отступы как SE
610
+ : isMobile || window.innerHeight < 700 ? "8px" : "20px",
611
+ justifyItems: "center",
612
+ maxWidth: isMobile && window.innerWidth > window.innerHeight
613
+ ? "90%" // mobile landscape: используем больше ширины
614
+ : isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
615
+ ? "95%" // iPhone SE: используем почти всю ширину
616
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
617
+ ? "95%" // iPhone XR в landscape: используем почти всю ширину как SE
618
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
619
+ ? "95%" // iPhone 12 Pro в landscape: используем почти всю ширину как SE
620
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
621
+ ? "95%" // iPhone 14 Pro Max в landscape: используем почти всю ширину как SE
622
+ : "100%",
623
+ padding: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
624
+ ? "8px" // iPhone SE: минимальные внутренние отступы
625
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
626
+ ? "8px" // iPhone XR в landscape: минимальные отступы как SE
627
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
628
+ ? "8px" // iPhone 12 Pro в landscape: минимальные отступы как SE
629
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
630
+ ? "8px" // iPhone 14 Pro Max в landscape: минимальные отступы как SE
631
+ : "16px",
632
+ }}
633
+ >
634
+ {files.map((file, i) => {
635
+ const isHidden =
636
+ hiddenIndex === i && phase === "guess" && !answered;
637
+ return (
638
+ <div
639
+ key={i}
640
+ style={{
641
+ width: "100%",
642
+ height: "100%",
643
+ borderRadius: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
644
+ ? "6px" // iPhone SE: меньшие скругления
645
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
646
+ ? "6px" // iPhone XR в landscape: меньшие скругления как SE
647
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
648
+ ? "6px" // iPhone 12 Pro в landscape: меньшие скругления как SE
649
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
650
+ ? "6px" // iPhone 14 Pro Max в landscape: меньшие скругления как SE
651
+ : "12px",
652
+ overflow: "hidden",
653
+ boxShadow: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
654
+ ? "0 1px 4px rgba(0,0,0,0.1)" // iPhone SE: меньшие тени
655
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
656
+ ? "0 1px 4px rgba(0,0,0,0.1)" // iPhone XR в landscape: меньшие тени как SE
657
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
658
+ ? "0 1px 4px rgba(0,0,0,0.1)" // iPhone 12 Pro в landscape: меньшие тени как SE
659
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
660
+ ? "0 1px 4px rgba(0,0,0,0.1)" // iPhone 14 Pro Max в landscape: меньшие тени как SE
661
+ : "0 4px 12px rgba(0,0,0,0.15)",
662
+ transition: "all 0.3s ease",
663
+ cursor: "pointer",
664
+ ...(result === "correct" && hiddenIndex === i
665
+ ? {
666
+ boxShadow: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
667
+ ? "0 0 15px #10b981"
668
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
669
+ ? "0 0 15px #10b981" // iPhone XR в landscape: такие же тени как SE
670
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
671
+ ? "0 0 15px #10b981" // iPhone 12 Pro в landscape: такие же тени как SE
672
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
673
+ ? "0 0 15px #10b981" // iPhone 14 Pro Max в landscape: такие же тени как SE
674
+ : "0 0 20px #10b981",
675
+ transform: "scale(1.03)"
676
+ }
677
+ : {}),
678
+ ...(result === "wrong" && hiddenIndex === i
679
+ ? {
680
+ boxShadow: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
681
+ ? "0 0 15px #ef4444"
682
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
683
+ ? "0 0 15px #ef4444" // iPhone XR в landscape: такие же тени как SE
684
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
685
+ ? "0 0 15px #ef4444" // iPhone 12 Pro в landscape: такие же тени как SE
686
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
687
+ ? "0 0 15px #ef4444" // iPhone 14 Pro Max в landscape: такие же тени как SE
688
+ : "0 0 20px #ef4444",
689
+ transform: "scale(1.03)"
690
+ }
691
+ : {}),
692
+ }}
693
+ >
694
+ {!isHidden && (
695
+ <img
696
+ src={file.src}
697
+ alt={file.name}
698
+ style={{
699
+ width: "100%",
700
+ height: "100%",
701
+ objectFit: "cover",
702
+ }}
703
+ />
704
+ )}
705
+ </div>
706
+ );
707
+ })}
708
+ </div>
709
+ )}
710
+ <div style={{
711
+ marginTop: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
712
+ ? "1px" // iPhone SE: еще более минимальный отступ
713
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
714
+ ? "1px" // iPhone до 14 Pro Max в landscape: такой же как SE
715
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
716
+ ? "1px" // iPhone XR в landscape: такой же как SE
717
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
718
+ ? "1px" // iPhone 12 Pro в landscape: такой же как SE
719
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
720
+ ? "1px" // iPhone 14 Pro Max в landscape: такой же как SE
721
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700
722
+ ? "4px" // iPhone landscape и малые экраны: минимальный отступ
723
+ : "16px",
724
+ height: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
725
+ ? "40px" // iPhone SE: еще более компактная высота
726
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
727
+ ? "40px" // iPhone до 14 Pro Max в landscape: такая же как SE
728
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
729
+ ? "40px" // iPhone XR в landscape: такая же как SE
730
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
731
+ ? "40px" // iPhone 12 Pro в landscape: такая же как SE
732
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
733
+ ? "40px" // iPhone 14 Pro Max в landscape: такая же как SE
734
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700
735
+ ? "50px" // iPhone landscape и малые экраны: компактная высота
736
+ : "80px"
737
+ }}>
738
+ {phase === "guess" && !answered && (
739
+ <div style={{
740
+ display: "flex",
741
+ flexDirection: (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 || (window.innerWidth === 1366 && window.innerHeight === 766) || (window.innerWidth === 1366 && window.innerHeight === 768) || (window.innerWidth === 1280 && window.innerHeight === 720) || (window.innerWidth === 1440 && window.innerHeight === 900) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape || isDesktopLayout ? "row" : "column",
742
+ gap: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
743
+ ? "3px" // iPhone SE: еще более минимальный отступ
744
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
745
+ ? "3px" // iPhone до 14 Pro Max в landscape: такой же как SE
746
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
747
+ ? "3px" // iPhone XR в landscape: такой же как SE
748
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
749
+ ? "3px" // iPhone 12 Pro в landscape: такой же как SE
750
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
751
+ ? "3px" // iPhone 14 Pro Max в landscape: такой же как SE
752
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
753
+ ? "8px" // 1366x766: отступ между инпутом и кнопкой
754
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
755
+ ? "8px" // 1366x768: отступ между инпутом и кнопкой
756
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
757
+ ? "8px" // 1280x720: отступ между инпутом и кнопкой
758
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
759
+ ? "8px" // 1440x900: отступ между инпутом и кнопкой
760
+ : isDesktopLayout // Десктопные разрешения
761
+ ? "8px" // Десктопные разрешения: отступ между инпутом и кнопкой
762
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
763
+ ? "8px" // iPad и Surface DUO: отступ между инпутом и кнопкой
764
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "6px" : "12px",
765
+ alignItems: "center",
766
+ justifyContent: "center",
767
+ width: "100%",
768
+ maxWidth: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
769
+ ? "270px" // iPhone SE: еще более компактная ширина
770
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
771
+ ? "270px" // iPhone до 14 Pro Max в landscape: такая же как SE
772
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
773
+ ? "270px" // iPhone XR в landscape: такая же как SE
774
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
775
+ ? "270px" // iPhone 12 Pro в landscape: такая же как SE
776
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
777
+ ? "270px" // iPhone 14 Pro Max в landscape: такая же как SE
778
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
779
+ ? "400px" // 1366x766: ширина контейнера
780
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
781
+ ? "400px" // 1366x768: ширина контейнера
782
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
783
+ ? "400px" // 1280x720: ширина контейнера
784
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
785
+ ? "400px" // 1440x900: ширина контейнера
786
+ : isDesktopLayout // Десктопные разрешения
787
+ ? "400px" // Десктопные разрешения: ширина контейнера
788
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
789
+ ? "400px" // iPad и Surface DUO: ширина контейнера
790
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "400px" : "300px"
791
+ }}>
792
+ <>
793
+ <input
794
+ type="text"
795
+ placeholder="Type the missing word"
796
+ value={inputValue}
797
+ onChange={(e) => setInputValue(e.target.value)}
660
798
  style={{
661
- width: "100%",
662
- height: "100%",
663
- objectFit: "cover",
664
- display: "block",
799
+ ...styles.gmInput,
800
+ width: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
801
+ ? "170px" // iPhone SE: еще более компактная ширина
802
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
803
+ ? "170px" // iPhone до 14 Pro Max в landscape: такая же как SE
804
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
805
+ ? "170px" // iPhone XR в landscape: такая же как SE
806
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
807
+ ? "170px" // iPhone 12 Pro в landscape: такая же как SE
808
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
809
+ ? "170px" // iPhone 14 Pro Max в landscape: такая же как SE
810
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
811
+ ? "250px" // 1366x766: ширина инпута
812
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
813
+ ? "250px" // 1366x768: ширина инпута
814
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
815
+ ? "250px" // 1280x720: ширина инпута
816
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
817
+ ? "250px" // 1440x900: ширина инпута
818
+ : isDesktopLayout // Десктопные разрешения
819
+ ? "250px" // Десктопные разрешения: ширина инпута
820
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
821
+ ? "250px" // iPad и Surface DUO: ширина инпута
822
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "250px" : "auto",
823
+ padding: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
824
+ ? "5px 6px" // iPhone SE: еще более компактный padding
825
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
826
+ ? "5px 6px" // iPhone до 14 Pro Max в landscape: такой же как SE
827
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
828
+ ? "5px 6px" // iPhone XR в landscape: такой же как SE
829
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
830
+ ? "5px 6px" // iPhone 12 Pro в landscape: такой же как SE
831
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
832
+ ? "5px 6px" // iPhone 14 Pro Max в landscape: такой же как SE
833
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
834
+ ? "10px 12px" // 1366x766: padding инпута
835
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
836
+ ? "10px 12px" // 1366x768: padding инпута
837
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
838
+ ? "10px 12px" // 1280x720: padding инпута
839
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
840
+ ? "10px 12px" // 1440x900: padding инпута
841
+ : isDesktopLayout // Десктопные разрешения
842
+ ? "10px 12px" // Десктопные разрешения: padding инпута
843
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
844
+ ? "10px 12px" // iPad и Surface DUO: padding инпута
845
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "10px 12px" : "12px 16px",
846
+ fontSize: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
847
+ ? "10px" // iPhone SE: еще меньший шрифт
848
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
849
+ ? "10px" // iPhone до 14 Pro Max в landscape: такой же как SE
850
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
851
+ ? "11px" // iPhone XR в landscape: компактный шрифт
852
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
853
+ ? "10px" // iPhone 12 Pro в landscape: такой же как SE
854
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
855
+ ? "10px" // iPhone 14 Pro Max в landscape: такой же как SE
856
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
857
+ ? "14px" // 1366x766: размер шрифта инпута
858
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
859
+ ? "14px" // 1366x768: размер шрифта инпута
860
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
861
+ ? "14px" // 1280x720: размер шрифта инпута
862
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
863
+ ? "14px" // 1440x900: размер шрифта инпута
864
+ : isDesktopLayout // Десктопные разрешения
865
+ ? "14px" // Десктопные разрешения: размер шрифта инпута
866
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
867
+ ? "14px" // iPad и Surface DUO: размер шрифта инпута
868
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "14px" : "16px",
869
+ flex: (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 || (window.innerWidth === 1366 && window.innerHeight === 766) || (window.innerWidth === 1366 && window.innerHeight === 768) || (window.innerWidth === 1280 && window.innerHeight === 720) || (window.innerWidth === 1440 && window.innerHeight === 900) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape || isDesktopLayout ? "1" : "none"
665
870
  }}
666
871
  />
667
- )}
668
- </div>
669
- );
670
- })}
671
- </div>
672
- )}
673
-
674
- {/* Инпут и кнопки */}
675
- <div style={{ marginTop: 16, height: 80 }}>
676
- {phase === "guess" && !answered && (
677
- <div>
678
- <input
679
- type="text"
680
- placeholder="Type the missing word"
681
- value={inputValue}
682
- onChange={(e) => setInputValue(e.target.value)}
683
- style={styles.gmInput}
684
- />
685
- <button
686
- style={{ ...styles.gmButton, marginLeft: 8 }}
687
- onClick={checkAnswer}
688
- disabled={animating}
689
- >
690
- {animating ? "..." : "Check"}
872
+ <button
873
+ style={{
874
+ ...styles.gmButton,
875
+ marginLeft: (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 || (window.innerWidth === 1366 && window.innerHeight === 766) || (window.innerWidth === 1366 && window.innerHeight === 768) || (window.innerWidth === 1280 && window.innerHeight === 720) || (window.innerWidth === 1440 && window.innerHeight === 900) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape || isDesktopLayout ? "8px" : "0",
876
+ padding: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
877
+ ? "5px 8px" // iPhone SE: еще более компактный padding
878
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
879
+ ? "6px 10px" // iPhone до 14 Pro Max в landscape: компактный padding
880
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
881
+ ? "6px 10px" // iPhone XR в landscape: компактный padding
882
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
883
+ ? "6px 10px" // iPhone 12 Pro в landscape: компактный padding
884
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
885
+ ? "6px 10px" // iPhone 14 Pro Max в landscape: компактный padding
886
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
887
+ ? "10px 16px" // 1366x766: padding кнопки Check
888
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
889
+ ? "10px 16px" // 1366x768: padding кнопки Check
890
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
891
+ ? "10px 16px" // 1280x720: padding кнопки Check
892
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
893
+ ? "10px 16px" // 1440x900: padding кнопки Check
894
+ : isDesktopLayout // Десктопные разрешения
895
+ ? "10px 16px" // Десктопные разрешения: padding кнопки Check
896
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
897
+ ? "10px 16px" // iPad и Surface DUO: padding кнопки Check
898
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "10px 16px" : "12px 24px",
899
+ fontSize: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
900
+ ? "10px" // iPhone SE: еще меньший шрифт
901
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
902
+ ? "11px" // iPhone до 14 Pro Max в landscape: компактный шрифт
903
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
904
+ ? "11px" // iPhone XR в landscape: компактный шрифт
905
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
906
+ ? "11px" // iPhone 12 Pro в landscape: компактный шрифт
907
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
908
+ ? "11px" // iPhone 14 Pro Max в landscape: компактный шрифт
909
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
910
+ ? "14px" // 1366x766: размер шрифта кнопки Check
911
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
912
+ ? "14px" // 1366x768: размер шрифта кнопки Check
913
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
914
+ ? "14px" // 1280x720: размер шрифта кнопки Check
915
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
916
+ ? "14px" // 1440x900: размер шрифта кнопки Check
917
+ : isDesktopLayout // Десктопные разрешения
918
+ ? "14px" // Десктопные разрешения: размер шрифта кнопки Check
919
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
920
+ ? "14px" // iPad и Surface DUO: размер шрифта кнопки Check
921
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "14px" : "16px",
922
+ minWidth: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
923
+ ? "45px" // iPhone SE: еще более компактная ширина
924
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
925
+ ? "55px" // iPhone до 14 Pro Max в landscape: компактная ширина
926
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
927
+ ? "55px" // iPhone XR в landscape: компактная ширина
928
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
929
+ ? "55px" // iPhone 12 Pro в landscape: компактная ширина
930
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
931
+ ? "55px" // iPhone 14 Pro Max в landscape: компактная ширина
932
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
933
+ ? "80px" // 1366x766: минимальная ширина кнопки Check
934
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
935
+ ? "80px" // 1366x768: минимальная ширина кнопки Check
936
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
937
+ ? "80px" // 1280x720: минимальная ширина кнопки Check
938
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
939
+ ? "80px" // 1440x900: минимальная ширина кнопки Check
940
+ : isDesktopLayout // Десктопные разрешения
941
+ ? "80px" // Десктопные разрешения: минимальная ширина кнопки Check
942
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
943
+ ? "80px" // iPad и Surface DUO: минимальная ширина кнопки Check
944
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "80px" : "100px",
945
+ flexShrink: 0
946
+ }}
947
+ onClick={checkAnswer}
948
+ disabled={animating}
949
+ >
950
+ {animating ? "..." : "Check"}
951
+ </button>
952
+ </>
953
+ </div>
954
+ )}
955
+ {answered && (
956
+ <button style={{
957
+ ...styles.gmButton,
958
+ padding: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
959
+ ? "5px 8px" // iPhone SE: еще более компактный padding
960
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
961
+ ? "6px 10px" // iPhone до 14 Pro Max в landscape: компактный padding
962
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
963
+ ? "6px 10px" // iPhone XR в landscape: компактный padding
964
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
965
+ ? "6px 10px" // iPhone 12 Pro в landscape: компактный padding
966
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
967
+ ? "6px 10px" // iPhone 14 Pro Max в landscape: компактный padding
968
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
969
+ ? "10px 16px" // 1366x766: padding кнопки Next round
970
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
971
+ ? "10px 16px" // 1366x768: padding кнопки Next round
972
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
973
+ ? "10px 16px" // 1280x720: padding кнопки Next round
974
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
975
+ ? "10px 16px" // 1440x900: padding кнопки Next round
976
+ : isDesktopLayout // Десктопные разрешения
977
+ ? "10px 16px" // Десктопные разрешения: padding кнопки Next round
978
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
979
+ ? "10px 16px" // iPad и Surface DUO: padding кнопки Next round
980
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "10px 16px" : "12px 24px",
981
+ fontSize: isMobile && window.innerWidth <= 375 && window.innerHeight <= 667
982
+ ? "10px" // iPhone SE: еще меньший шрифт
983
+ : (isMobile && window.innerWidth > window.innerHeight && window.innerHeight <= 428)
984
+ ? "11px" // iPhone до 14 Pro Max в landscape: компактный шрифт
985
+ : (window.innerWidth === 896 && window.innerHeight === 414) // iPhone XR
986
+ ? "11px" // iPhone XR в landscape: компактный шрифт
987
+ : (window.innerWidth === 844 && window.innerHeight === 390) // iPhone 12 Pro
988
+ ? "11px" // iPhone 12 Pro в landscape: компактный шрифт
989
+ : (window.innerWidth === 926 && window.innerHeight === 428) // iPhone 14 Pro Max
990
+ ? "11px" // iPhone 14 Pro Max в landscape: компактный шрифт
991
+ : (window.innerWidth === 1366 && window.innerHeight === 766) // 1366x766
992
+ ? "14px" // 1366x766: размер шрифта кнопки Next round
993
+ : (window.innerWidth === 1366 && window.innerHeight === 768) // 1366x768
994
+ ? "14px" // 1366x768: размер шрифта кнопки Next round
995
+ : (window.innerWidth === 1280 && window.innerHeight === 720) // 1280x720
996
+ ? "14px" // 1280x720: размер шрифта кнопки Next round
997
+ : (window.innerWidth === 1440 && window.innerHeight === 900) // 1440x900
998
+ ? "14px" // 1440x900: размер шрифта кнопки Next round
999
+ : isDesktopLayout // Десктопные разрешения
1000
+ ? "14px" // Десктопные разрешения: размер шрифта кнопки Next round
1001
+ : isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape
1002
+ ? "14px" // iPad и Surface DUO: размер шрифта кнопки Next round
1003
+ : (isMobile && window.innerWidth > window.innerHeight) || window.innerHeight < 700 ? "14px" : "16px"
1004
+ }} onClick={nextRound}>
1005
+ Next round
691
1006
  </button>
692
- </div>
693
- )}
694
- {answered && (
695
- <button type="button" style={styles.gmButton} onClick={nextRound}>
696
- Next round
697
- </button>
698
- )}
1007
+ )}
1008
+ </div>
699
1009
  </div>
700
- </div>
701
- )}
702
- </div>
1010
+ )}
703
1011
  </div>
704
- </div>,
705
- shadowRoot
706
- )}
1012
+ </div>
1013
+ </div>
707
1014
  </div>
708
1015
  );
709
- }
1016
+ }