Kexin-251202 commited on
Commit
6e5dc1f
·
verified ·
1 Parent(s): 4b920eb

update tutorial layout

Browse files
Files changed (2) hide show
  1. src/src/App.css +2047 -0
  2. src/src/App.jsx +125 -0
src/src/App.css ADDED
@@ -0,0 +1,2047 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* =========================================
2
+ 1. REACT layout setting
3
+ ========================================= */
4
+ html, body, #root {
5
+ width: 100%;
6
+ height: 100%;
7
+ margin: 0;
8
+ padding: 0;
9
+ }
10
+
11
+ .app-container {
12
+ width: 100%;
13
+ min-height: 100vh; /* screen height */
14
+ display: flex;
15
+ flex-direction: column;
16
+ background-color: #f9f9f9;
17
+ }
18
+
19
+ /* =========================================
20
+ 2. original layout
21
+ ========================================= */
22
+
23
+ /* GLOBAL STYLES */
24
+ body {
25
+ font-family: 'Nunito', sans-serif;
26
+ background-color: #f9f9f9;
27
+ overflow-x: hidden;
28
+ overflow-y: auto;
29
+ }
30
+
31
+ /* dynamic class name */
32
+ .hidden {
33
+ display: none !important;
34
+ }
35
+
36
+ /* TOP MENU */
37
+ #top-menu {
38
+ height: 60px;
39
+ background-color: white;
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ gap: 0;
44
+ padding: 0 16px 0 20px;
45
+ box-sizing: border-box;
46
+ box-shadow: 0 2px 5px rgba(0,0,0,0.05);
47
+ position: fixed;
48
+ top: 0;
49
+ left: 0;
50
+ right: 0;
51
+ width: 100%;
52
+ z-index: 1000;
53
+ overflow-x: auto;
54
+ overflow-y: hidden;
55
+ white-space: nowrap;
56
+ }
57
+
58
+ .top-menu-links {
59
+ flex: 1;
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ flex-wrap: wrap;
64
+ gap: 0;
65
+ min-width: 0;
66
+ }
67
+
68
+ .menu-btn {
69
+ background: none;
70
+ border: none;
71
+ font-family: 'Nunito', sans-serif;
72
+ font-size: 16px;
73
+ color: #333;
74
+ padding: 10px 20px;
75
+ cursor: pointer;
76
+ transition: background-color 0.2s;
77
+ }
78
+
79
+ .menu-btn:hover {
80
+ background-color: #f0f0f0;
81
+ border-radius: 4px;
82
+ }
83
+
84
+ /* active for React */
85
+ .menu-btn.active {
86
+ font-weight: bold;
87
+ color: #007BFF;
88
+ background-color: #eef7ff;
89
+ border-radius: 4px;
90
+ }
91
+
92
+ .separator {
93
+ width: 1px;
94
+ height: 20px;
95
+ background-color: #555; /* Dark gray separator */
96
+ margin: 0 5px;
97
+ }
98
+
99
+ /* PAGE CONTAINER */
100
+ .page {
101
+ /* content under menu */
102
+ min-height: calc(100vh - 60px);
103
+ width: 100%;
104
+ padding-top: 60px; /* Space for fixed menu */
105
+ padding-bottom: 40px; /* Space at bottom for scrolling */
106
+ box-sizing: border-box;
107
+ display: flex;
108
+ flex-direction: column;
109
+ align-items: center;
110
+ overflow-y: auto;
111
+ }
112
+
113
+ /* Ensure page titles are black */
114
+ .page h1 {
115
+ color: #000 !important;
116
+ background: transparent !important;
117
+ }
118
+
119
+ .page-title {
120
+ color: #000 !important;
121
+ background: transparent !important;
122
+ }
123
+
124
+ /* PAGE A SPECIFIC */
125
+ #page-a {
126
+ justify-content: center; /* Center vertically */
127
+ /* Fine-tune this margin if the Home screen sits slightly too low. */
128
+ margin-top: -40px;
129
+ flex: 1; /* Fill the remaining height so vertical centering still works. */
130
+ }
131
+
132
+ #page-a h1 {
133
+ font-size: 80px;
134
+ margin: 0 0 10px 0;
135
+ color: #000;
136
+ text-align: center; /* Keep the heading centered. */
137
+ }
138
+
139
+ #page-a p {
140
+ color: #666;
141
+ font-size: 20px;
142
+ margin-bottom: 40px;
143
+ text-align: center;
144
+ }
145
+
146
+ .btn-main {
147
+ background-color: #007BFF; /* Blue */
148
+ color: white;
149
+ border: none;
150
+ padding: 15px 50px;
151
+ font-size: 20px;
152
+ font-family: 'Nunito', sans-serif;
153
+ border-radius: 30px; /* Fully rounded corners */
154
+ cursor: pointer;
155
+ transition: transform 0.2s ease;
156
+ }
157
+
158
+ .btn-main:hover {
159
+ transform: scale(1.1); /* Zoom effect */
160
+ }
161
+
162
+ /* PAGE B SPECIFIC */
163
+ #page-b {
164
+ justify-content: space-evenly; /* Distribute vertical space */
165
+ padding-bottom: 20px;
166
+ min-height: calc(100vh - 60px); /* Ensure the page still fills the viewport. */
167
+ }
168
+
169
+ /* 1. Display Area */
170
+ #display-area {
171
+ width: 60%;
172
+ height: 50vh; /* Use viewport height to scale more consistently across screens. */
173
+ min-height: 300px;
174
+ border: 2px solid #ddd;
175
+ border-radius: 12px;
176
+ background-color: #fff;
177
+ display: flex;
178
+ align-items: center;
179
+ justify-content: center;
180
+ color: #555;
181
+ font-size: 24px;
182
+ position: relative;
183
+ /* Keep video content centered without overflowing the frame. */
184
+ overflow: hidden;
185
+ }
186
+
187
+ .focus-display-shell {
188
+ background: #101010;
189
+ }
190
+
191
+ @keyframes fadeInOverlay {
192
+ from { opacity: 0; }
193
+ to { opacity: 1; }
194
+ }
195
+
196
+ @keyframes slideUpCard {
197
+ from { opacity: 0; transform: translateY(30px); }
198
+ to { opacity: 1; transform: translateY(0); }
199
+ }
200
+
201
+
202
+ .focus-flow-overlay {
203
+ position: fixed;
204
+ top: 76px;
205
+ right: 20px;
206
+ bottom: 20px;
207
+ left: 20px;
208
+ display: flex;
209
+ align-items: center;
210
+ justify-content: center;
211
+ padding: 0;
212
+ background: rgba(17, 31, 52, 0.18);
213
+ backdrop-filter: blur(10px);
214
+ z-index: 900;
215
+ animation: fadeInOverlay 0.3s ease-out forwards;
216
+ }
217
+
218
+ .focus-flow-card {
219
+ width: min(1040px, 100%);
220
+ background: #fff;
221
+ border-radius: 24px;
222
+ padding: 30px 34px;
223
+ box-shadow: 0 28px 80px rgba(14, 44, 88, 0.18);
224
+ border: 1px solid rgba(0, 123, 255, 0.12);
225
+ box-sizing: border-box;
226
+ animation: slideUpCard 0.4s ease-out forwards;
227
+ }
228
+
229
+ .focus-flow-header {
230
+ display: flex;
231
+ align-items: center;
232
+ justify-content: space-between;
233
+ gap: 24px;
234
+ margin-bottom: 18px;
235
+ }
236
+
237
+ .focus-flow-eyebrow {
238
+ display: inline-block;
239
+ padding: 6px 12px;
240
+ border-radius: 999px;
241
+ background: #e7f3ff;
242
+ color: #007BFF;
243
+ font-size: 0.82rem;
244
+ font-weight: 800;
245
+ letter-spacing: 0.04em;
246
+ text-transform: uppercase;
247
+ }
248
+
249
+ .focus-flow-header h2 {
250
+ margin: 14px 0 0;
251
+ color: #333;
252
+ font-size: clamp(1.8rem, 2.5vw, 2.5rem);
253
+ line-height: 1.1;
254
+ }
255
+
256
+ .focus-flow-icon {
257
+ flex: 0 0 auto;
258
+ display: flex;
259
+ align-items: center;
260
+ justify-content: center;
261
+ width: 116px;
262
+ height: 116px;
263
+ border-radius: 24px;
264
+ background: linear-gradient(180deg, #f4f9ff 0%, #edf5ff 100%);
265
+ border: 1px solid rgba(0, 123, 255, 0.12);
266
+ }
267
+
268
+ .focus-flow-lead {
269
+ margin: 0 0 20px;
270
+ color: #4a4a4a;
271
+ font-size: 1rem;
272
+ line-height: 1.6;
273
+ }
274
+
275
+ .focus-flow-grid {
276
+ display: grid;
277
+ grid-template-columns: repeat(3, minmax(0, 1fr));
278
+ gap: 16px;
279
+ }
280
+
281
+ .focus-flow-panel {
282
+ background: #f8fbff;
283
+ border: 1px solid #d9eaff;
284
+ border-radius: 14px;
285
+ padding: 18px;
286
+ }
287
+ .focus-flow-grid .focus-flow-panel:last-child {
288
+ grid-column: 1 / -1;
289
+ }
290
+
291
+ .focus-flow-panel h3,
292
+ .focus-flow-step-copy h3 {
293
+ margin: 0 0 8px;
294
+ color: #333;
295
+ font-size: 1rem;
296
+ }
297
+
298
+ .focus-flow-panel p,
299
+ .focus-flow-step-copy p {
300
+ margin: 0;
301
+ color: #5e6670;
302
+ font-size: 0.95rem;
303
+ line-height: 1.6;
304
+ }
305
+
306
+ .focus-flow-steps {
307
+ display: grid;
308
+ grid-template-columns: repeat(3, minmax(0, 1fr));
309
+ gap: 14px;
310
+ }
311
+
312
+ .focus-flow-step {
313
+ display: flex;
314
+ align-items: flex-start;
315
+ gap: 14px;
316
+ background: #f8fbff;
317
+ border: 1px solid #d9eaff;
318
+ border-radius: 14px;
319
+ padding: 16px 18px;
320
+ min-height: 100px;
321
+ box-sizing: border-box;
322
+ }
323
+
324
+ .focus-flow-step-number {
325
+ flex: 0 0 auto;
326
+ display: inline-flex;
327
+ align-items: center;
328
+ justify-content: center;
329
+ width: 34px;
330
+ height: 34px;
331
+ border-radius: 50%;
332
+ background: #007BFF;
333
+ color: #fff;
334
+ font-size: 0.95rem;
335
+ font-weight: 800;
336
+ }
337
+
338
+ .focus-flow-step-copy {
339
+ min-width: 0;
340
+ }
341
+
342
+ .focus-flow-footer {
343
+ display: flex;
344
+ align-items: center;
345
+ justify-content: space-between;
346
+ gap: 16px;
347
+ margin-top: 20px;
348
+ }
349
+
350
+ .focus-flow-note {
351
+ color: #667281;
352
+ font-size: 0.94rem;
353
+ line-height: 1.6;
354
+ }
355
+
356
+ .focus-flow-glasses-note {
357
+ background: #fffbea;
358
+ border: 1px solid #f5c518;
359
+ border-radius: 10px;
360
+ padding: 12px 16px;
361
+ font-size: 0.9rem;
362
+ color: #5a4a00;
363
+ line-height: 1.55;
364
+ margin-top: 4px;
365
+ margin-bottom: 4px;
366
+ }
367
+
368
+ .focus-flow-panel-warn {
369
+ border-left: 3px solid #f5a623;
370
+ background: #fff9f0;
371
+ }
372
+
373
+ .eye-gaze-modal-checkbox {
374
+ display: flex;
375
+ align-items: center;
376
+ gap: 8px;
377
+ margin-top: 16px;
378
+ font-size: 0.9rem;
379
+ color: #667281;
380
+ cursor: pointer;
381
+ user-select: none;
382
+ }
383
+
384
+ .focus-flow-button,
385
+ .focus-flow-secondary {
386
+ border: none;
387
+ border-radius: 999px;
388
+ padding: 13px 24px;
389
+ font-family: 'Nunito', sans-serif;
390
+ font-size: 0.98rem;
391
+ font-weight: 800;
392
+ cursor: pointer;
393
+ transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
394
+ }
395
+
396
+ .focus-flow-button {
397
+ background: #007BFF;
398
+ color: #fff;
399
+ box-shadow: 0 12px 24px rgba(0, 123, 255, 0.18);
400
+ }
401
+
402
+ .focus-flow-button:hover {
403
+ background: #0069d9;
404
+ border-color: transparent;
405
+ transform: translateY(-1px);
406
+ }
407
+
408
+ .focus-flow-secondary {
409
+ background: #eef3f8;
410
+ color: #4b5a6b;
411
+ }
412
+
413
+ .focus-flow-secondary:hover {
414
+ background: #e2eaf3;
415
+ border-color: transparent;
416
+ }
417
+
418
+ .focus-state-pill {
419
+ position: absolute;
420
+ top: 18px;
421
+ left: 18px;
422
+ display: inline-flex;
423
+ align-items: center;
424
+ gap: 10px;
425
+ padding: 10px 16px;
426
+ border-radius: 999px;
427
+ color: #fff;
428
+ font-size: 0.88rem;
429
+ font-weight: 800;
430
+ letter-spacing: 0.04em;
431
+ text-transform: uppercase;
432
+ z-index: 2;
433
+ box-shadow: 0 12px 24px rgba(0, 0, 0, 0.18);
434
+ }
435
+
436
+ .focus-state-pill.pending {
437
+ background: rgba(87, 96, 111, 0.92);
438
+ }
439
+
440
+ .focus-state-pill.focused {
441
+ background: rgba(33, 163, 102, 0.94);
442
+ }
443
+
444
+ .focus-state-pill.not-focused {
445
+ background: rgba(215, 68, 68, 0.94);
446
+ }
447
+
448
+ .focus-state-dot {
449
+ width: 10px;
450
+ height: 10px;
451
+ border-radius: 50%;
452
+ background: currentColor;
453
+ box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.16);
454
+ }
455
+
456
+ .focus-idle-overlay {
457
+ position: absolute;
458
+ inset: 0;
459
+ display: flex;
460
+ flex-direction: column;
461
+ align-items: center;
462
+ justify-content: center;
463
+ gap: 10px;
464
+ background: radial-gradient(circle at center, rgba(255, 255, 255, 0.12), rgba(0, 0, 0, 0.72));
465
+ color: #fff;
466
+ text-align: center;
467
+ z-index: 1;
468
+ }
469
+
470
+ .focus-idle-overlay p {
471
+ margin: 0;
472
+ font-size: 1.6rem;
473
+ font-weight: 800;
474
+ }
475
+
476
+ .focus-idle-overlay span {
477
+ max-width: 420px;
478
+ color: rgba(255, 255, 255, 0.82);
479
+ font-size: 0.98rem;
480
+ line-height: 1.5;
481
+ }
482
+
483
+ .focus-inline-error {
484
+ margin-top: 18px;
485
+ padding: 12px 16px;
486
+ max-width: 620px;
487
+ border-radius: 12px;
488
+ background: #fff1ee;
489
+ color: #b54028;
490
+ font-size: 0.95rem;
491
+ font-weight: 700;
492
+ box-shadow: 0 10px 20px rgba(181, 64, 40, 0.08);
493
+ }
494
+
495
+ .focus-inline-error-standalone {
496
+ width: 60%;
497
+ box-sizing: border-box;
498
+ }
499
+
500
+ .focus-debug-panel {
501
+ position: absolute;
502
+ top: 10px;
503
+ right: 10px;
504
+ background: rgba(0,0,0,0.7);
505
+ color: white;
506
+ padding: 10px;
507
+ border-radius: 5px;
508
+ font-size: 12px;
509
+ font-family: monospace;
510
+ }
511
+
512
+ .focus-model-strip {
513
+ display: flex;
514
+ align-items: center;
515
+ justify-content: center;
516
+ flex-wrap: wrap;
517
+ gap: 8px;
518
+ padding: 10px 16px;
519
+ background: #fff;
520
+ border: 1px solid #e0e0e0;
521
+ border-radius: 12px;
522
+ margin: 10px auto;
523
+ max-width: 700px;
524
+ box-shadow: 0 2px 8px rgba(0,0,0,0.06);
525
+ }
526
+
527
+ /* --- Model info card --- */
528
+ .model-card {
529
+ width: 60%;
530
+ margin: 14px auto 0;
531
+ background: #fff;
532
+ border: 1px solid #e0e0e0;
533
+ border-radius: 14px;
534
+ padding: 18px 22px 14px;
535
+ box-shadow: 0 2px 10px rgba(0,0,0,0.06);
536
+ animation: cardFadeIn 0.25s ease;
537
+ box-sizing: border-box;
538
+ }
539
+
540
+ .model-card-details {
541
+ display: grid;
542
+ grid-template-columns: repeat(3, 1fr);
543
+ gap: 12px;
544
+ }
545
+
546
+ @keyframes cardFadeIn {
547
+ from { opacity: 0; transform: translateY(4px); }
548
+ to { opacity: 1; transform: translateY(0); }
549
+ }
550
+
551
+ .model-card-header {
552
+ display: flex;
553
+ align-items: center;
554
+ gap: 10px;
555
+ margin-bottom: 4px;
556
+ }
557
+
558
+ .model-card-title {
559
+ margin: 0;
560
+ font-size: 1.05rem;
561
+ color: #1a1a2e;
562
+ }
563
+
564
+ .model-card-badge {
565
+ padding: 3px 10px;
566
+ border-radius: 999px;
567
+ background: #e7f3ff;
568
+ color: #007BFF;
569
+ font-size: 0.7rem;
570
+ font-weight: 800;
571
+ letter-spacing: 0.04em;
572
+ text-transform: uppercase;
573
+ }
574
+
575
+ .model-card-badge-baseline {
576
+ padding: 3px 10px;
577
+ border-radius: 999px;
578
+ background: #fff3e0;
579
+ color: #e67e22;
580
+ font-size: 0.7rem;
581
+ font-weight: 800;
582
+ letter-spacing: 0.04em;
583
+ text-transform: uppercase;
584
+ }
585
+
586
+ .model-card-tagline {
587
+ margin: 0 0 12px;
588
+ color: #667281;
589
+ font-size: 0.85rem;
590
+ line-height: 1.4;
591
+ }
592
+
593
+ .model-card-metrics {
594
+ display: grid;
595
+ grid-template-columns: repeat(4, 1fr);
596
+ gap: 8px;
597
+ margin-bottom: 14px;
598
+ }
599
+
600
+ .model-card-metric {
601
+ text-align: center;
602
+ padding: 8px 4px;
603
+ background: #f8fbff;
604
+ border: 1px solid #e8f0fe;
605
+ border-radius: 10px;
606
+ }
607
+
608
+ .model-card-metric-value {
609
+ display: block;
610
+ font-size: 1.1rem;
611
+ font-weight: 800;
612
+ color: #007BFF;
613
+ line-height: 1.2;
614
+ }
615
+
616
+ .model-card-metric-label {
617
+ display: block;
618
+ font-size: 0.65rem;
619
+ color: #8899aa;
620
+ font-weight: 700;
621
+ text-transform: uppercase;
622
+ letter-spacing: 0.04em;
623
+ margin-top: 2px;
624
+ }
625
+
626
+ .model-card-section {
627
+ margin-bottom: 8px;
628
+ }
629
+
630
+ .model-card-section h4 {
631
+ margin: 0 0 2px;
632
+ font-size: 0.78rem;
633
+ color: #555;
634
+ font-weight: 800;
635
+ text-transform: uppercase;
636
+ letter-spacing: 0.03em;
637
+ }
638
+
639
+ .model-card-section p {
640
+ margin: 0;
641
+ font-size: 0.82rem;
642
+ color: #4a4a4a;
643
+ line-height: 1.5;
644
+ }
645
+
646
+ .model-card-eval {
647
+ margin-top: 10px;
648
+ padding: 6px 10px;
649
+ background: #f5f7fa;
650
+ border-radius: 8px;
651
+ font-size: 0.72rem;
652
+ color: #7a8a9a;
653
+ font-weight: 600;
654
+ }
655
+
656
+ @media (max-width: 768px) {
657
+ .model-card {
658
+ width: 90%;
659
+ }
660
+ .model-card-metrics {
661
+ grid-template-columns: repeat(2, 1fr);
662
+ }
663
+ .model-card-details {
664
+ grid-template-columns: 1fr;
665
+ }
666
+ }
667
+
668
+ .focus-model-label {
669
+ color: #666;
670
+ font-size: 13px;
671
+ font-weight: 700;
672
+ margin-right: 4px;
673
+ }
674
+
675
+ .focus-model-button {
676
+ padding: 6px 16px;
677
+ border-radius: 16px;
678
+ border: 1px solid #d0d0d0;
679
+ background: #f5f5f5;
680
+ color: #555;
681
+ font-size: 12px;
682
+ font-weight: 600;
683
+ text-transform: uppercase;
684
+ cursor: pointer;
685
+ transition: all 0.2s;
686
+ }
687
+
688
+ .focus-model-button:hover {
689
+ border-color: #007BFF;
690
+ color: #007BFF;
691
+ background: #f0f7ff;
692
+ }
693
+
694
+ .focus-model-button.active {
695
+ border: 2px solid #007BFF;
696
+ background: #007BFF;
697
+ color: #fff;
698
+ }
699
+
700
+ .focus-model-sep {
701
+ width: 1px;
702
+ height: 24px;
703
+ background: #d0d0d0;
704
+ margin: 0 4px;
705
+ }
706
+
707
+ .eye-gaze-toggle {
708
+ display: inline-flex;
709
+ align-items: center;
710
+ gap: 6px;
711
+ padding: 6px 14px;
712
+ border-radius: 16px;
713
+ font-size: 12px;
714
+ font-weight: 700;
715
+ cursor: pointer;
716
+ transition: all 0.25s ease;
717
+ }
718
+
719
+ .eye-gaze-toggle.off {
720
+ border: 1px solid #d0d0d0;
721
+ background: #f5f5f5;
722
+ color: #888;
723
+ }
724
+
725
+ .eye-gaze-toggle.off:hover {
726
+ border-color: #007BFF;
727
+ color: #007BFF;
728
+ background: #f0f7ff;
729
+ }
730
+
731
+ .eye-gaze-toggle.on {
732
+ border: 2px solid #007BFF;
733
+ background: #007BFF;
734
+ color: #fff;
735
+ box-shadow: 0 2px 8px rgba(0, 123, 255, 0.25);
736
+ }
737
+
738
+ .eye-gaze-toggle.on:hover {
739
+ background: #0069d9;
740
+ border-color: #0069d9;
741
+ }
742
+
743
+ .eye-gaze-icon {
744
+ flex-shrink: 0;
745
+ }
746
+
747
+ .focus-model-button.recalibrate {
748
+ border: 1px solid #007BFF;
749
+ background: transparent;
750
+ color: #007BFF;
751
+ font-weight: 600;
752
+ font-size: 11px;
753
+ }
754
+
755
+ .focus-model-button.recalibrate:hover {
756
+ background: #f0f7ff;
757
+ }
758
+
759
+ .focus-system-stats {
760
+ display: flex;
761
+ align-items: center;
762
+ justify-content: center;
763
+ gap: 12px;
764
+ padding: 4px 16px;
765
+ margin: 4px auto;
766
+ max-width: 400px;
767
+ font-size: 12px;
768
+ color: #888;
769
+ }
770
+
771
+ .focus-system-stats strong {
772
+ color: #555;
773
+ }
774
+
775
+ .focus-system-stats-sep {
776
+ width: 1px;
777
+ height: 12px;
778
+ background: #ccc;
779
+ }
780
+
781
+ #display-area video {
782
+ width: 100%;
783
+ height: 100%;
784
+ object-fit: cover; /* Behaves similarly to background-size: cover. */
785
+ }
786
+
787
+ /* 2. Timeline Area */
788
+ #timeline-area {
789
+ width: 60%;
790
+ height: 80px;
791
+ position: relative;
792
+ display: flex;
793
+ flex-direction: column;
794
+ justify-content: flex-end;
795
+ align-self: center;
796
+ margin: 0 auto;
797
+ }
798
+
799
+ #timeline-visuals {
800
+ display: flex;
801
+ justify-content: center;
802
+ flex-wrap: wrap;
803
+ align-items: flex-end;
804
+ gap: 2px;
805
+ width: 100%;
806
+ }
807
+
808
+ .timeline-label {
809
+ position: absolute;
810
+ top: 0;
811
+ left: 0;
812
+ color: #888;
813
+ font-size: 14px;
814
+ }
815
+
816
+ #timeline-line {
817
+ width: 100%;
818
+ height: 2px;
819
+ background-color: #87CEEB; /* Light blue */
820
+ }
821
+
822
+ /* 3. Control Panel */
823
+ #control-panel {
824
+ display: flex;
825
+ gap: 20px;
826
+ width: 60%;
827
+ justify-content: space-between;
828
+ }
829
+
830
+ .action-btn {
831
+ flex: 1; /* Evenly distributed width */
832
+ padding: 12px 0;
833
+ border: none;
834
+ border-radius: 12px;
835
+ font-size: 16px;
836
+ font-family: 'Nunito', sans-serif;
837
+ font-weight: 700;
838
+ cursor: pointer;
839
+ color: white;
840
+ transition: opacity 0.2s;
841
+ }
842
+
843
+ .action-btn:hover {
844
+ opacity: 0.9;
845
+ }
846
+
847
+ .action-btn.green { background-color: #28a745; }
848
+ .action-btn.blue { background-color: #007BFF; }
849
+ .action-btn.orange { background-color: #e67e22; }
850
+ .action-btn.red { background-color: #dc3545; }
851
+
852
+ /* 4. Frame Control */
853
+ #frame-control {
854
+ display: flex;
855
+ align-items: center;
856
+ gap: 15px;
857
+ color: #333;
858
+ font-weight: bold;
859
+ }
860
+
861
+ #frame-slider {
862
+ width: 200px;
863
+ cursor: pointer;
864
+ }
865
+
866
+ #frame-input {
867
+ width: 50px;
868
+ padding: 5px;
869
+ border: 1px solid #ccc;
870
+ border-radius: 5px;
871
+ text-align: center;
872
+ font-family: 'Nunito', sans-serif;
873
+ }
874
+
875
+ /* ================ ACHIEVEMENT PAGE ================ */
876
+
877
+ .stats-grid {
878
+ display: grid;
879
+ grid-template-columns: repeat(4, 1fr);
880
+ gap: 20px;
881
+ width: 80%;
882
+ margin: 40px auto;
883
+ }
884
+
885
+ .stat-card {
886
+ background: white;
887
+ padding: 30px;
888
+ border-radius: 12px;
889
+ text-align: center;
890
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
891
+ }
892
+
893
+ .stat-number {
894
+ font-size: 48px;
895
+ font-weight: bold;
896
+ color: #007BFF;
897
+ margin-bottom: 10px;
898
+ }
899
+
900
+ .stat-label {
901
+ font-size: 16px;
902
+ color: #666;
903
+ }
904
+
905
+ .achievements-section {
906
+ width: 80%;
907
+ margin: 0 auto;
908
+ }
909
+
910
+ .achievements-section h2 {
911
+ color: #333;
912
+ margin-bottom: 20px;
913
+ }
914
+
915
+ .badges-grid {
916
+ display: grid;
917
+ grid-template-columns: repeat(3, 1fr);
918
+ gap: 20px;
919
+ }
920
+
921
+ .badge {
922
+ background: white;
923
+ padding: 30px 20px;
924
+ border-radius: 12px;
925
+ text-align: center;
926
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
927
+ transition: transform 0.2s;
928
+ }
929
+
930
+ .badge:hover {
931
+ transform: translateY(-5px);
932
+ }
933
+
934
+ .badge.locked {
935
+ opacity: 0.4;
936
+ filter: grayscale(100%);
937
+ }
938
+
939
+ .badge-icon {
940
+ font-size: 64px;
941
+ margin-bottom: 15px;
942
+ }
943
+
944
+ .badge-name {
945
+ font-size: 16px;
946
+ font-weight: bold;
947
+ color: #333;
948
+ }
949
+
950
+ /* ================ RECORDS PAGE ================ */
951
+
952
+ .records-controls {
953
+ display: flex;
954
+ gap: 10px;
955
+ margin: 20px auto;
956
+ width: 80%;
957
+ justify-content: center;
958
+ }
959
+
960
+ .filter-btn {
961
+ padding: 10px 20px;
962
+ border: 2px solid #007BFF;
963
+ background: white;
964
+ color: #007BFF;
965
+ border-radius: 8px;
966
+ cursor: pointer;
967
+ font-family: 'Nunito', sans-serif;
968
+ font-weight: 600;
969
+ transition: all 0.2s;
970
+ }
971
+
972
+ .filter-btn:hover {
973
+ background: #e7f3ff;
974
+ }
975
+
976
+ .filter-btn.active {
977
+ background: #007BFF;
978
+ color: white;
979
+ }
980
+
981
+ .chart-container {
982
+ width: 80%;
983
+ background: white;
984
+ padding: 30px;
985
+ border-radius: 12px;
986
+ margin: 20px auto;
987
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
988
+ }
989
+
990
+ #focus-chart {
991
+ display: block;
992
+ margin: 0 auto;
993
+ /* Make sure the chart scales within its container. */
994
+ max-width: 100%;
995
+ }
996
+
997
+ .sessions-list {
998
+ width: 80%;
999
+ margin: 20px auto;
1000
+ }
1001
+
1002
+ .sessions-list h2 {
1003
+ color: #333;
1004
+ margin-bottom: 15px;
1005
+ }
1006
+
1007
+ #sessions-table {
1008
+ width: 100%;
1009
+ background: white;
1010
+ border-collapse: collapse;
1011
+ border-radius: 12px;
1012
+ overflow: hidden;
1013
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
1014
+ }
1015
+
1016
+ #sessions-table th {
1017
+ background: #007BFF;
1018
+ color: white;
1019
+ padding: 15px;
1020
+ text-align: left;
1021
+ font-weight: 600;
1022
+ }
1023
+
1024
+ #sessions-table td {
1025
+ padding: 12px 15px;
1026
+ border-bottom: 1px solid #eee;
1027
+ }
1028
+
1029
+ #sessions-table tr:last-child td {
1030
+ border-bottom: none;
1031
+ }
1032
+
1033
+ #sessions-table tbody tr:hover {
1034
+ background: #f8f9fa;
1035
+ }
1036
+
1037
+ .btn-view {
1038
+ padding: 6px 18px;
1039
+ background: #007BFF;
1040
+ color: white;
1041
+ border: none;
1042
+ border-radius: 999px;
1043
+ cursor: pointer;
1044
+ font-family: 'Nunito', sans-serif;
1045
+ font-size: 12px;
1046
+ font-weight: 700;
1047
+ transition: background 0.2s;
1048
+ }
1049
+
1050
+ .btn-view:hover {
1051
+ background: #0056b3;
1052
+ }
1053
+
1054
+ .records-detail-modal {
1055
+ width: min(960px, 92vw);
1056
+ max-width: 960px;
1057
+ max-height: 86vh;
1058
+ overflow-y: auto;
1059
+ padding: 30px;
1060
+ box-sizing: border-box;
1061
+ }
1062
+
1063
+ .records-detail-header {
1064
+ display: flex;
1065
+ justify-content: space-between;
1066
+ align-items: flex-start;
1067
+ gap: 20px;
1068
+ margin-bottom: 24px;
1069
+ }
1070
+
1071
+ .records-detail-kicker {
1072
+ color: #007BFF;
1073
+ font-size: 12px;
1074
+ font-weight: 800;
1075
+ letter-spacing: 0.08em;
1076
+ text-transform: uppercase;
1077
+ }
1078
+
1079
+ .records-detail-header h2 {
1080
+ margin: 10px 0 8px;
1081
+ color: #333;
1082
+ text-align: left;
1083
+ }
1084
+
1085
+ .records-detail-subtitle {
1086
+ margin: 0;
1087
+ color: #667281;
1088
+ line-height: 1.6;
1089
+ }
1090
+
1091
+ .records-detail-close {
1092
+ border: 1px solid #d6e6fa;
1093
+ background: #f4f9ff;
1094
+ color: #3569a8;
1095
+ border-radius: 999px;
1096
+ padding: 10px 18px;
1097
+ font-family: 'Nunito', sans-serif;
1098
+ font-weight: 700;
1099
+ cursor: pointer;
1100
+ }
1101
+
1102
+ .records-detail-close:hover {
1103
+ border-color: #bfd9f7;
1104
+ background: #e9f4ff;
1105
+ }
1106
+
1107
+ .records-detail-feedback {
1108
+ padding: 18px 20px;
1109
+ border-radius: 14px;
1110
+ background: #f7f9fc;
1111
+ color: #516173;
1112
+ font-weight: 700;
1113
+ }
1114
+
1115
+ .records-detail-feedback-error {
1116
+ background: #fff1ee;
1117
+ color: #b54028;
1118
+ }
1119
+
1120
+ .records-detail-summary {
1121
+ display: grid;
1122
+ grid-template-columns: repeat(4, minmax(0, 1fr));
1123
+ gap: 14px;
1124
+ margin-bottom: 18px;
1125
+ }
1126
+
1127
+ .records-detail-stat {
1128
+ padding: 18px;
1129
+ border-radius: 14px;
1130
+ background: #f8fbff;
1131
+ border: 1px solid #d9eaff;
1132
+ }
1133
+
1134
+ .records-detail-stat.excellent {
1135
+ background: #eef9f0;
1136
+ border-color: #cdebd3;
1137
+ }
1138
+
1139
+ .records-detail-stat.good {
1140
+ background: #fff9eb;
1141
+ border-color: #f8e3a8;
1142
+ }
1143
+
1144
+ .records-detail-stat.fair {
1145
+ background: #fff4eb;
1146
+ border-color: #ffd6af;
1147
+ }
1148
+
1149
+ .records-detail-stat.low {
1150
+ background: #fff0f0;
1151
+ border-color: #f3c7c7;
1152
+ }
1153
+
1154
+ .records-detail-stat-label {
1155
+ display: block;
1156
+ margin-bottom: 8px;
1157
+ color: #667281;
1158
+ font-size: 13px;
1159
+ font-weight: 700;
1160
+ text-transform: uppercase;
1161
+ letter-spacing: 0.04em;
1162
+ }
1163
+
1164
+ .records-detail-stat-value {
1165
+ display: block;
1166
+ color: #1f2d3d;
1167
+ font-size: 28px;
1168
+ line-height: 1.1;
1169
+ }
1170
+
1171
+ .records-detail-grid {
1172
+ display: grid;
1173
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1174
+ gap: 16px;
1175
+ margin-bottom: 16px;
1176
+ }
1177
+
1178
+ .records-detail-card {
1179
+ background: white;
1180
+ border: 1px solid #e8eef5;
1181
+ border-radius: 16px;
1182
+ padding: 20px;
1183
+ box-shadow: 0 8px 24px rgba(20, 44, 74, 0.06);
1184
+ margin-bottom: 16px;
1185
+ }
1186
+
1187
+ .records-detail-card:last-child {
1188
+ margin-bottom: 0;
1189
+ }
1190
+
1191
+ .records-detail-card h3 {
1192
+ margin: 0 0 16px;
1193
+ color: #333;
1194
+ font-size: 18px;
1195
+ }
1196
+
1197
+ .records-detail-list {
1198
+ display: grid;
1199
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1200
+ gap: 14px 18px;
1201
+ }
1202
+
1203
+ .records-detail-item {
1204
+ display: flex;
1205
+ flex-direction: column;
1206
+ gap: 6px;
1207
+ }
1208
+
1209
+ .records-detail-item-label {
1210
+ color: #7a8795;
1211
+ font-size: 12px;
1212
+ font-weight: 700;
1213
+ text-transform: uppercase;
1214
+ letter-spacing: 0.05em;
1215
+ }
1216
+
1217
+ .records-detail-item-value {
1218
+ color: #263445;
1219
+ font-size: 15px;
1220
+ font-weight: 700;
1221
+ line-height: 1.5;
1222
+ }
1223
+
1224
+ .records-detail-section-head {
1225
+ display: flex;
1226
+ align-items: center;
1227
+ justify-content: space-between;
1228
+ gap: 12px;
1229
+ margin-bottom: 16px;
1230
+ }
1231
+
1232
+ .records-detail-section-head span {
1233
+ color: #7a8795;
1234
+ font-size: 13px;
1235
+ font-weight: 700;
1236
+ }
1237
+
1238
+ .records-detail-timeline {
1239
+ display: grid;
1240
+ grid-template-columns: repeat(auto-fit, minmax(10px, 1fr));
1241
+ gap: 5px;
1242
+ }
1243
+
1244
+ .records-detail-segment {
1245
+ height: 48px;
1246
+ border-radius: 999px;
1247
+ }
1248
+
1249
+ .records-detail-segment.focused {
1250
+ background: linear-gradient(180deg, #3ab86a 0%, #23a057 100%);
1251
+ }
1252
+
1253
+ .records-detail-segment.mixed {
1254
+ background: linear-gradient(180deg, #f1b447 0%, #df9a1e 100%);
1255
+ }
1256
+
1257
+ .records-detail-segment.distracted {
1258
+ background: linear-gradient(180deg, #ec7d7d 0%, #d9534f 100%);
1259
+ }
1260
+
1261
+ .records-detail-legend {
1262
+ display: flex;
1263
+ flex-wrap: wrap;
1264
+ gap: 16px;
1265
+ margin-top: 14px;
1266
+ color: #667281;
1267
+ font-size: 13px;
1268
+ font-weight: 700;
1269
+ }
1270
+
1271
+ .records-detail-legend span {
1272
+ display: inline-flex;
1273
+ align-items: center;
1274
+ gap: 8px;
1275
+ }
1276
+
1277
+ .records-detail-dot {
1278
+ width: 10px;
1279
+ height: 10px;
1280
+ border-radius: 50%;
1281
+ display: inline-block;
1282
+ }
1283
+
1284
+ .records-detail-dot.focused {
1285
+ background: #23a057;
1286
+ }
1287
+
1288
+ .records-detail-dot.mixed {
1289
+ background: #df9a1e;
1290
+ }
1291
+
1292
+ .records-detail-dot.distracted {
1293
+ background: #d9534f;
1294
+ }
1295
+
1296
+ .records-detail-events {
1297
+ display: grid;
1298
+ gap: 10px;
1299
+ max-height: 280px;
1300
+ overflow-y: auto;
1301
+ }
1302
+
1303
+ .records-detail-event {
1304
+ display: grid;
1305
+ grid-template-columns: auto 1fr auto;
1306
+ align-items: center;
1307
+ gap: 12px;
1308
+ padding: 12px 14px;
1309
+ background: #f8fbff;
1310
+ border: 1px solid #e1edf9;
1311
+ border-radius: 14px;
1312
+ }
1313
+
1314
+ .records-detail-event-time {
1315
+ min-width: 52px;
1316
+ color: #3569a8;
1317
+ font-size: 13px;
1318
+ font-weight: 800;
1319
+ }
1320
+
1321
+ .records-detail-event-copy {
1322
+ min-width: 0;
1323
+ }
1324
+
1325
+ .records-detail-event-status {
1326
+ color: #243345;
1327
+ font-size: 14px;
1328
+ font-weight: 800;
1329
+ }
1330
+
1331
+ .records-detail-event-meta {
1332
+ margin-top: 4px;
1333
+ color: #6f7d8c;
1334
+ font-size: 12px;
1335
+ line-height: 1.5;
1336
+ }
1337
+
1338
+ .records-detail-event-badge {
1339
+ padding: 7px 12px;
1340
+ border-radius: 999px;
1341
+ font-size: 11px;
1342
+ font-weight: 800;
1343
+ letter-spacing: 0.04em;
1344
+ text-transform: uppercase;
1345
+ }
1346
+
1347
+ .records-detail-event-badge.focused {
1348
+ background: #eaf8ef;
1349
+ color: #1f8a4c;
1350
+ }
1351
+
1352
+ .records-detail-event-badge.distracted {
1353
+ background: #fff1f1;
1354
+ color: #c24c49;
1355
+ }
1356
+
1357
+ .records-detail-empty {
1358
+ padding: 16px 18px;
1359
+ border-radius: 14px;
1360
+ background: #f7f9fc;
1361
+ color: #708090;
1362
+ font-weight: 700;
1363
+ }
1364
+
1365
+ /* ================ SETTINGS PAGE ================ */
1366
+
1367
+ .settings-container {
1368
+ width: 60%;
1369
+ max-width: 800px;
1370
+ margin: 20px auto;
1371
+ }
1372
+
1373
+ .setting-group {
1374
+ background: white;
1375
+ padding: 30px;
1376
+ border-radius: 12px;
1377
+ margin-bottom: 20px;
1378
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
1379
+ }
1380
+
1381
+ .setting-group h2 {
1382
+ margin-top: 0;
1383
+ color: #333;
1384
+ font-size: 20px;
1385
+ margin-bottom: 20px;
1386
+ border-bottom: 2px solid #007BFF;
1387
+ padding-bottom: 10px;
1388
+ }
1389
+
1390
+ .setting-item {
1391
+ margin-bottom: 25px;
1392
+ }
1393
+
1394
+ .setting-item:last-child {
1395
+ margin-bottom: 0;
1396
+ }
1397
+
1398
+ .setting-item label {
1399
+ display: block;
1400
+ margin-bottom: 8px;
1401
+ color: #333;
1402
+ font-weight: 600;
1403
+ }
1404
+
1405
+ .slider-group {
1406
+ display: flex;
1407
+ align-items: center;
1408
+ gap: 15px;
1409
+ }
1410
+
1411
+ .slider-group input[type="range"] {
1412
+ flex: 1;
1413
+ }
1414
+
1415
+ .slider-group span {
1416
+ min-width: 40px;
1417
+ text-align: center;
1418
+ font-weight: bold;
1419
+ color: #007BFF;
1420
+ font-size: 18px;
1421
+ }
1422
+
1423
+ .setting-description {
1424
+ font-size: 14px;
1425
+ color: #666;
1426
+ margin-top: 5px;
1427
+ font-style: italic;
1428
+ }
1429
+
1430
+ input[type="checkbox"] {
1431
+ margin-right: 10px;
1432
+ cursor: pointer;
1433
+ }
1434
+
1435
+ input[type="number"] {
1436
+ width: 100px;
1437
+ padding: 8px;
1438
+ border: 1px solid #ccc;
1439
+ border-radius: 5px;
1440
+ font-family: 'Nunito', sans-serif;
1441
+ }
1442
+
1443
+ /* Center the settings buttons and give them more width. */
1444
+ .setting-group .action-btn {
1445
+ display: inline-block; /* Allow buttons to sit side by side. */
1446
+ width: 48%; /* Roughly half-width each, with a small gutter. */
1447
+ margin: 15px 1%; /* Vertical spacing plus horizontal separation. */
1448
+ text-align: center; /* Center the label text. */
1449
+ box-sizing: border-box; /* Prevent borders from forcing an early wrap. */
1450
+ }
1451
+
1452
+ #save-settings {
1453
+ display: block;
1454
+ margin: 20px auto;
1455
+ }
1456
+
1457
+ /* ================ HELP PAGE ================ */
1458
+
1459
+ .help-container {
1460
+ width: 70%;
1461
+ max-width: 900px;
1462
+ margin: 20px auto;
1463
+ }
1464
+
1465
+ /* Fake ad block (Help page) */
1466
+ .fake-ad {
1467
+ position: relative;
1468
+ display: block;
1469
+ width: min(600px, 90%);
1470
+ margin: 10px auto 30px auto;
1471
+ border: 1px solid #e5e5e5;
1472
+ border-radius: 12px;
1473
+ overflow: hidden;
1474
+ background: #fff;
1475
+ text-decoration: none;
1476
+ box-shadow: 0 8px 24px rgba(0,0,0,0.12);
1477
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
1478
+ }
1479
+
1480
+ .fake-ad:hover {
1481
+ transform: translateY(-2px);
1482
+ box-shadow: 0 12px 30px rgba(0,0,0,0.16);
1483
+ }
1484
+
1485
+ .fake-ad img {
1486
+ display: block;
1487
+ width: 100%;
1488
+ height: auto;
1489
+ }
1490
+
1491
+ .fake-ad-badge {
1492
+ position: absolute;
1493
+ top: 12px;
1494
+ left: 12px;
1495
+ background: rgba(0,0,0,0.75);
1496
+ color: #fff;
1497
+ font-size: 12px;
1498
+ padding: 4px 8px;
1499
+ border-radius: 6px;
1500
+ letter-spacing: 0.5px;
1501
+ }
1502
+
1503
+ .fake-ad-cta {
1504
+ position: absolute;
1505
+ right: 12px;
1506
+ bottom: 12px;
1507
+ background: #111;
1508
+ color: #fff;
1509
+ font-size: 14px;
1510
+ padding: 8px 12px;
1511
+ border-radius: 8px;
1512
+ }
1513
+
1514
+ .help-section {
1515
+ background: white;
1516
+ padding: 30px;
1517
+ border-radius: 12px;
1518
+ margin-bottom: 20px;
1519
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
1520
+ }
1521
+
1522
+ .help-section h2 {
1523
+ color: #007BFF;
1524
+ margin-top: 0;
1525
+ margin-bottom: 15px;
1526
+ }
1527
+
1528
+ .help-section ol,
1529
+ .help-section ul {
1530
+ line-height: 1.8;
1531
+ color: #333;
1532
+ }
1533
+
1534
+ .help-section p {
1535
+ line-height: 1.6;
1536
+ color: #333;
1537
+ }
1538
+
1539
+ details {
1540
+ margin: 15px 0;
1541
+ cursor: pointer;
1542
+ padding: 10px;
1543
+ background: #f8f9fa;
1544
+ border-radius: 5px;
1545
+ }
1546
+
1547
+ summary {
1548
+ font-weight: bold;
1549
+ padding: 5px;
1550
+ color: #007BFF;
1551
+ }
1552
+
1553
+ details[open] summary {
1554
+ margin-bottom: 10px;
1555
+ border-bottom: 1px solid #ddd;
1556
+ padding-bottom: 10px;
1557
+ }
1558
+
1559
+ details p {
1560
+ margin: 10px 0 0 0;
1561
+ }
1562
+
1563
+ /* ================ SESSION SUMMARY MODAL ================ */
1564
+ /* These modal styles can be reused for future overlays. */
1565
+ .modal-overlay {
1566
+ position: fixed;
1567
+ top: 0;
1568
+ left: 0;
1569
+ width: 100%;
1570
+ height: 100%;
1571
+ background: rgba(0, 0, 0, 0.7);
1572
+ display: flex;
1573
+ align-items: center;
1574
+ justify-content: center;
1575
+ z-index: 2000;
1576
+ }
1577
+
1578
+ .modal-content {
1579
+ background: white;
1580
+ padding: 40px;
1581
+ border-radius: 16px;
1582
+ box-shadow: 0 10px 40px rgba(0,0,0,0.3);
1583
+ max-width: 500px;
1584
+ width: 90%;
1585
+ }
1586
+
1587
+ .modal-content h2 {
1588
+ margin-top: 0;
1589
+ color: #333;
1590
+ text-align: center;
1591
+ margin-bottom: 30px;
1592
+ }
1593
+
1594
+ .summary-stats {
1595
+ margin-bottom: 30px;
1596
+ }
1597
+
1598
+ .summary-item {
1599
+ display: flex;
1600
+ justify-content: space-between;
1601
+ padding: 15px 0;
1602
+ border-bottom: 1px solid #eee;
1603
+ }
1604
+
1605
+ .summary-item:last-child {
1606
+ border-bottom: none;
1607
+ }
1608
+
1609
+ .summary-label {
1610
+ font-weight: 600;
1611
+ color: #666;
1612
+ }
1613
+
1614
+ .summary-value {
1615
+ font-weight: bold;
1616
+ color: #007BFF;
1617
+ font-size: 18px;
1618
+ }
1619
+
1620
+ .modal-content .btn-main {
1621
+ display: block;
1622
+ margin: 0 auto;
1623
+ padding: 12px 40px;
1624
+ }
1625
+
1626
+ /* ================ TIMELINE BLOCKS ================ */
1627
+
1628
+ .timeline-block {
1629
+ transition: opacity 0.2s;
1630
+ border-radius: 2px;
1631
+ }
1632
+
1633
+ .timeline-block:hover {
1634
+ opacity: 0.7;
1635
+ }
1636
+
1637
+ /* ================ RESPONSIVE DESIGN ================ */
1638
+
1639
+ @media (max-width: 1200px) {
1640
+ .stats-grid {
1641
+ grid-template-columns: repeat(2, 1fr);
1642
+ }
1643
+
1644
+ .badges-grid {
1645
+ grid-template-columns: repeat(2, 1fr);
1646
+ }
1647
+ }
1648
+
1649
+ @media (max-width: 768px) {
1650
+ .stats-grid,
1651
+ .badges-grid {
1652
+ grid-template-columns: 1fr;
1653
+ width: 90%;
1654
+ }
1655
+
1656
+ .settings-container,
1657
+ .help-container,
1658
+ .chart-container,
1659
+ .sessions-list,
1660
+ .records-controls {
1661
+ width: 90%;
1662
+ }
1663
+
1664
+ #control-panel {
1665
+ width: 90%;
1666
+ flex-wrap: wrap;
1667
+ }
1668
+
1669
+ #display-area {
1670
+ width: 90%;
1671
+ }
1672
+
1673
+ #timeline-area {
1674
+ width: 90%;
1675
+ }
1676
+
1677
+ #frame-control {
1678
+ width: 90%;
1679
+ flex-direction: column;
1680
+ }
1681
+
1682
+ .focus-inline-error-standalone {
1683
+ width: 90%;
1684
+ }
1685
+
1686
+ .focus-flow-overlay {
1687
+ top: 70px;
1688
+ right: 10px;
1689
+ bottom: 10px;
1690
+ left: 10px;
1691
+ }
1692
+
1693
+ .focus-flow-card {
1694
+ padding: 22px 20px;
1695
+ }
1696
+
1697
+ .focus-flow-header {
1698
+ flex-direction: column;
1699
+ align-items: flex-start;
1700
+ }
1701
+
1702
+ .focus-flow-icon {
1703
+ width: 92px;
1704
+ height: 92px;
1705
+ }
1706
+
1707
+ .focus-flow-grid {
1708
+ grid-template-columns: 1fr;
1709
+ }
1710
+
1711
+ .focus-flow-steps {
1712
+ grid-template-columns: 1fr;
1713
+ }
1714
+
1715
+ .focus-flow-footer {
1716
+ flex-direction: column;
1717
+ align-items: stretch;
1718
+ }
1719
+
1720
+ .focus-flow-button,
1721
+ .focus-flow-secondary {
1722
+ width: 100%;
1723
+ }
1724
+
1725
+ .records-detail-modal {
1726
+ width: 94vw;
1727
+ padding: 22px 18px;
1728
+ }
1729
+
1730
+ .records-detail-header,
1731
+ .records-detail-section-head {
1732
+ flex-direction: column;
1733
+ align-items: flex-start;
1734
+ }
1735
+
1736
+ .records-detail-summary,
1737
+ .records-detail-grid,
1738
+ .records-detail-list {
1739
+ grid-template-columns: 1fr;
1740
+ }
1741
+
1742
+ .records-detail-event {
1743
+ grid-template-columns: 1fr;
1744
+ align-items: flex-start;
1745
+ }
1746
+ }
1747
+ /* =========================================
1748
+ SESSION RESULT OVERLAY
1749
+ ========================================= */
1750
+
1751
+ .session-result-overlay {
1752
+ position: absolute;
1753
+ top: 0;
1754
+ left: 0;
1755
+ width: 100%;
1756
+ height: 100%;
1757
+ background-color: rgba(0, 0, 0, 0.85); /* Dark semi-transparent backdrop. */
1758
+ display: flex;
1759
+ flex-direction: column;
1760
+ justify-content: center;
1761
+ align-items: center;
1762
+ color: white;
1763
+ z-index: 10;
1764
+ animation: fadeIn 0.5s ease;
1765
+ backdrop-filter: blur(5px); /* Optional background blur. */
1766
+ }
1767
+
1768
+ .session-result-overlay h3 {
1769
+ font-size: 32px;
1770
+ margin-bottom: 30px;
1771
+ color: #4cd137; /* Green title accent. */
1772
+ text-transform: uppercase;
1773
+ letter-spacing: 2px;
1774
+ }
1775
+
1776
+ .session-result-overlay .result-item {
1777
+ display: flex;
1778
+ justify-content: space-between;
1779
+ width: 200px; /* Keep the stat row compact. */
1780
+ margin-bottom: 15px;
1781
+ font-size: 20px;
1782
+ border-bottom: 1px solid rgba(255,255,255,0.2);
1783
+ padding-bottom: 5px;
1784
+ }
1785
+
1786
+ .session-result-overlay .label {
1787
+ color: #ccc;
1788
+ font-weight: normal;
1789
+ }
1790
+
1791
+ .session-result-overlay .value {
1792
+ color: #fff;
1793
+ font-weight: bold;
1794
+ font-family: 'Courier New', monospace; /* Give the values a data-like look. */
1795
+ }
1796
+
1797
+ @keyframes fadeIn {
1798
+ from { opacity: 0; transform: scale(0.95); }
1799
+ to { opacity: 1; transform: scale(1); }
1800
+ }
1801
+
1802
+ /* ================= Welcome modal styles ================= */
1803
+ .welcome-modal-overlay {
1804
+ position: fixed;
1805
+ top: 0; left: 0; right: 0; bottom: 0;
1806
+ background-color: rgba(0, 0, 0, 0.7);
1807
+ display: flex;
1808
+ justify-content: center;
1809
+ align-items: center;
1810
+ z-index: 9999;
1811
+ }
1812
+
1813
+ .welcome-modal {
1814
+ background-color: #1e1e24;
1815
+ padding: 40px;
1816
+ border-radius: 15px;
1817
+ text-align: center;
1818
+ box-shadow: 0 10px 30px rgba(0,0,0,0.5);
1819
+ border: 1px solid #333;
1820
+ }
1821
+
1822
+ .welcome-modal h2 { margin-top: 0; color: #fff; }
1823
+ .welcome-modal p { margin-bottom: 30px; color: #ccc; }
1824
+ .welcome-buttons { display: flex; gap: 20px; justify-content: center; }
1825
+
1826
+ /* ================= Top-left avatar styles ================= */
1827
+ .avatar-container {
1828
+ position: absolute;
1829
+ left: 20px;
1830
+ cursor: pointer;
1831
+ z-index: 1;
1832
+ }
1833
+
1834
+ .avatar-circle {
1835
+ width: 40px;
1836
+ height: 40px;
1837
+ border-radius: 50%;
1838
+ display: flex;
1839
+ justify-content: center;
1840
+ align-items: center;
1841
+ font-weight: bold;
1842
+ font-size: 1.2rem;
1843
+ color: white;
1844
+ transition: all 0.3s ease;
1845
+ border: 2px solid transparent;
1846
+ }
1847
+
1848
+ .avatar-circle.user { background-color: #555; }
1849
+ .avatar-circle.admin { background-color: #ffaa00; border-color: #fff; box-shadow: 0 0 10px rgba(255, 170, 0, 0.5); }
1850
+
1851
+ /* ================ CALIBRATION OVERLAY ================ */
1852
+
1853
+ .cal-overlay {
1854
+ position: fixed;
1855
+ top: 0;
1856
+ left: 0;
1857
+ width: 100vw;
1858
+ height: 100vh;
1859
+ background: rgba(8, 15, 28, 0.94);
1860
+ backdrop-filter: blur(6px);
1861
+ z-index: 10000;
1862
+ display: flex;
1863
+ align-items: center;
1864
+ justify-content: center;
1865
+ font-family: 'Nunito', sans-serif;
1866
+ }
1867
+
1868
+ /* ---- header / instructions ---- */
1869
+ .cal-header {
1870
+ position: absolute;
1871
+ top: 36px;
1872
+ left: 50%;
1873
+ transform: translateX(-50%);
1874
+ text-align: center;
1875
+ pointer-events: none;
1876
+ }
1877
+
1878
+ .cal-eyebrow {
1879
+ display: inline-block;
1880
+ padding: 6px 14px;
1881
+ border-radius: 999px;
1882
+ font-size: 0.82rem;
1883
+ font-weight: 800;
1884
+ letter-spacing: 0.04em;
1885
+ text-transform: uppercase;
1886
+ }
1887
+
1888
+ .cal-eyebrow-collect {
1889
+ background: rgba(40, 167, 69, 0.18);
1890
+ color: #5ee882;
1891
+ }
1892
+
1893
+ .cal-eyebrow-verify {
1894
+ background: rgba(0, 123, 255, 0.18);
1895
+ color: #6bb8ff;
1896
+ }
1897
+
1898
+ .cal-instruction {
1899
+ margin: 10px 0 0;
1900
+ color: rgba(255, 255, 255, 0.7);
1901
+ font-size: 0.95rem;
1902
+ line-height: 1.5;
1903
+ }
1904
+
1905
+ /* ---- target dot + ring ---- */
1906
+ .cal-target {
1907
+ position: absolute;
1908
+ transform: translate(-50%, -50%);
1909
+ }
1910
+
1911
+ .cal-ring {
1912
+ position: absolute;
1913
+ left: -30px;
1914
+ top: -30px;
1915
+ }
1916
+
1917
+ .cal-dot {
1918
+ width: 20px;
1919
+ height: 20px;
1920
+ border-radius: 50%;
1921
+ transition: box-shadow 0.3s ease;
1922
+ }
1923
+
1924
+ /* ---- cancel button (matches focus-flow-secondary) ---- */
1925
+ .cal-cancel {
1926
+ position: absolute;
1927
+ bottom: 40px;
1928
+ left: 50%;
1929
+ transform: translateX(-50%);
1930
+ border: 1px solid rgba(255, 255, 255, 0.25);
1931
+ border-radius: 999px;
1932
+ padding: 12px 28px;
1933
+ background: rgba(255, 255, 255, 0.08);
1934
+ color: rgba(255, 255, 255, 0.85);
1935
+ font-family: 'Nunito', sans-serif;
1936
+ font-size: 0.95rem;
1937
+ font-weight: 700;
1938
+ cursor: pointer;
1939
+ transition: background 0.2s ease, border-color 0.2s ease;
1940
+ }
1941
+
1942
+ .cal-cancel:hover {
1943
+ background: rgba(255, 255, 255, 0.14);
1944
+ border-color: rgba(255, 255, 255, 0.4);
1945
+ }
1946
+
1947
+ /* ---- done card (matches focus-flow-card style) ---- */
1948
+ .cal-done-card {
1949
+ text-align: center;
1950
+ padding: 36px 44px;
1951
+ border-radius: 20px;
1952
+ border: 1px solid rgba(255, 255, 255, 0.08);
1953
+ box-shadow: 0 28px 80px rgba(0, 0, 0, 0.4);
1954
+ animation: fadeIn 0.4s ease;
1955
+ }
1956
+
1957
+ .cal-done-success {
1958
+ background: linear-gradient(168deg, rgba(40, 167, 69, 0.15) 0%, rgba(20, 30, 48, 0.95) 60%);
1959
+ border-color: rgba(40, 167, 69, 0.3);
1960
+ }
1961
+
1962
+ .cal-done-fail {
1963
+ background: linear-gradient(168deg, rgba(220, 53, 69, 0.15) 0%, rgba(20, 30, 48, 0.95) 60%);
1964
+ border-color: rgba(220, 53, 69, 0.3);
1965
+ }
1966
+
1967
+ .cal-done-eyebrow {
1968
+ display: inline-block;
1969
+ padding: 6px 14px;
1970
+ border-radius: 999px;
1971
+ font-size: 0.78rem;
1972
+ font-weight: 800;
1973
+ letter-spacing: 0.06em;
1974
+ text-transform: uppercase;
1975
+ margin-bottom: 14px;
1976
+ }
1977
+
1978
+ .cal-done-success .cal-done-eyebrow {
1979
+ background: rgba(40, 167, 69, 0.2);
1980
+ color: #5ee882;
1981
+ }
1982
+
1983
+ .cal-done-fail .cal-done-eyebrow {
1984
+ background: rgba(220, 53, 69, 0.2);
1985
+ color: #f87171;
1986
+ }
1987
+
1988
+ .cal-done-title {
1989
+ margin: 0 0 8px;
1990
+ font-size: 1.6rem;
1991
+ color: #fff;
1992
+ }
1993
+
1994
+ .cal-done-subtitle {
1995
+ margin: 0;
1996
+ color: rgba(255, 255, 255, 0.6);
1997
+ font-size: 0.95rem;
1998
+ line-height: 1.5;
1999
+ }
2000
+ /* ================= Home page 2x2 responsive button grid ================= */
2001
+ .home-button-grid {
2002
+ display: flex;
2003
+ justify-content: center;
2004
+ width: 100%;
2005
+ max-width: 360px;
2006
+ margin: 40px auto 0;
2007
+ }
2008
+
2009
+ .home-button-grid .btn-main {
2010
+ width: 100%;
2011
+ height: 60px; /* Keep all tiles at the same height. */
2012
+ margin: 0; /* Remove default outer spacing. */
2013
+ padding: 10px;
2014
+ font-size: 1rem;
2015
+ display: flex;
2016
+ justify-content: center;
2017
+ align-items: center;
2018
+ text-align: center;
2019
+ box-sizing: border-box; /* Prevent padding and borders from breaking the grid. */
2020
+ }
2021
+
2022
+ /* Mobile-only scaling for screens below 600px. */
2023
+ @media (max-width: 600px) {
2024
+ #top-menu {
2025
+ justify-content: flex-start;
2026
+ padding: 0 12px 0 68px;
2027
+ }
2028
+
2029
+ .menu-btn {
2030
+ padding: 10px 14px;
2031
+ font-size: 0.92rem;
2032
+ }
2033
+
2034
+ .separator {
2035
+ margin: 0 2px;
2036
+ }
2037
+
2038
+ .home-button-grid {
2039
+ gap: 15px;
2040
+ max-width: 90%;
2041
+ }
2042
+
2043
+ .home-button-grid .btn-main {
2044
+ height: 50px;
2045
+ font-size: 0.85rem;
2046
+ }
2047
+ }
src/src/App.jsx ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import './App.css';
3
+ import { VideoManagerLocal } from './utils/VideoManagerLocal';
4
+
5
+ import Home from './components/Home';
6
+ import FocusPageLocal from './components/FocusPageLocal';
7
+ import Achievement from './components/Achievement';
8
+ import Records from './components/Records';
9
+ import Help from './components/Help';
10
+
11
+ function App() {
12
+ const [activeTab, setActiveTab] = useState('home');
13
+ const videoManagerRef = useRef(null);
14
+ const [isSessionActive, setIsSessionActive] = useState(false);
15
+ const [sessionResult, setSessionResult] = useState(null);
16
+ const [isTutorialActive, setIsTutorialActive] = useState(false);
17
+ const [hasSeenTutorial, setHasSeenTutorial] = useState(false);
18
+
19
+ useEffect(() => {
20
+ fetch('/api/history', { method: 'DELETE' })
21
+ .then(() => {
22
+ const backup = localStorage.getItem('focus_magic_backup');
23
+ if (backup) {
24
+ try {
25
+ const sessions = JSON.parse(backup);
26
+ fetch('/api/import', {
27
+ method: 'POST',
28
+ headers: { 'Content-Type': 'application/json' },
29
+ body: JSON.stringify(sessions)
30
+ });
31
+ } catch (err) {
32
+ console.error(err);
33
+ }
34
+ }
35
+ })
36
+ .catch(err => console.error(err));
37
+
38
+ const callbacks = {
39
+ onSessionStart: () => {
40
+ setIsSessionActive(true);
41
+ setSessionResult(null);
42
+ },
43
+ onSessionEnd: (summary) => {
44
+ setIsSessionActive(false);
45
+ if (summary) setSessionResult(summary);
46
+
47
+ fetch('/api/sessions?filter=all')
48
+ .then(res => res.json())
49
+ .then(data => {
50
+ if (data && Array.isArray(data)) {
51
+ localStorage.setItem('focus_magic_backup', JSON.stringify(data));
52
+ }
53
+ })
54
+ .catch(err => console.error(err));
55
+ }
56
+ };
57
+ videoManagerRef.current = new VideoManagerLocal(callbacks);
58
+
59
+ return () => {
60
+ if (videoManagerRef.current) videoManagerRef.current.stopStreaming();
61
+ };
62
+ }, []);
63
+
64
+ const handleStartFocus = () => {
65
+ if (!hasSeenTutorial) {
66
+ setIsTutorialActive(true);
67
+ }
68
+ setActiveTab('focus');
69
+ };
70
+
71
+ const handleStartTutorial = () => {
72
+ setIsTutorialActive(true);
73
+ setActiveTab('focus');
74
+ };
75
+
76
+ return (
77
+ <div className="app-container">
78
+ <nav id="top-menu">
79
+ <button
80
+ className={`menu-btn ${activeTab === 'home' ? 'active' : ''}`}
81
+ onClick={() => setActiveTab('home')}
82
+ >
83
+ Home
84
+ </button>
85
+ <div className="separator"></div>
86
+
87
+ <button className={`menu-btn ${activeTab === 'focus' ? 'active' : ''}`} onClick={handleStartFocus}>
88
+ Start Focus {isSessionActive && <span style={{ marginLeft: '8px', color: '#00FF00' }}>●</span>}
89
+ </button>
90
+ <div className="separator"></div>
91
+
92
+ <button className={`menu-btn ${activeTab === 'achievement' ? 'active' : ''}`} onClick={() => setActiveTab('achievement')}>
93
+ My Achievement
94
+ </button>
95
+ <div className="separator"></div>
96
+
97
+ <button className={`menu-btn ${activeTab === 'records' ? 'active' : ''}`} onClick={() => setActiveTab('records')}>
98
+ My Records
99
+ </button>
100
+ <div className="separator"></div>
101
+
102
+ <button className={`menu-btn ${activeTab === 'help' ? 'active' : ''}`} onClick={() => setActiveTab('help')}>
103
+ Help
104
+ </button>
105
+ </nav>
106
+
107
+ {activeTab === 'home' && <Home onStartFocus={handleStartFocus} onStartTutorial={handleStartTutorial} />}
108
+
109
+ <FocusPageLocal
110
+ videoManager={videoManagerRef.current}
111
+ sessionResult={sessionResult}
112
+ setSessionResult={setSessionResult}
113
+ isActive={activeTab === 'focus'}
114
+ isTutorialActive={isTutorialActive}
115
+ setIsTutorialActive={setIsTutorialActive}
116
+ setHasSeenTutorial={setHasSeenTutorial}
117
+ />
118
+ {activeTab === 'achievement' && <Achievement />}
119
+ {activeTab === 'records' && <Records />}
120
+ {activeTab === 'help' && <Help />}
121
+ </div>
122
+ );
123
+ }
124
+
125
+ export default App;