@inventure71/paddockjs 0.1.0

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.
Files changed (44) hide show
  1. package/AGENTS.md +86 -0
  2. package/CHANGELOG.md +5 -0
  3. package/LICENSE +176 -0
  4. package/README.md +165 -0
  5. package/assets/f1-broadcast-panel-surface.png +0 -0
  6. package/assets/f1-car-sprite-game.png +0 -0
  7. package/assets/f1-driver-helmet.png +0 -0
  8. package/assets/f1-safety-car-sprite.png +0 -0
  9. package/assets/f1-texture-asphalt.png +0 -0
  10. package/assets/f1Logo.png +0 -0
  11. package/docs/architecture.md +209 -0
  12. package/docs/concepts.md +178 -0
  13. package/docs/data_contract.md +360 -0
  14. package/docs/data_model.md +167 -0
  15. package/docs/index.md +15 -0
  16. package/docs/learnings.md +47 -0
  17. package/docs/rules.md +181 -0
  18. package/docs/system_specs.md +211 -0
  19. package/package.json +85 -0
  20. package/src/api/PaddockSimulatorController.js +233 -0
  21. package/src/app/F1SimulatorApp.js +1293 -0
  22. package/src/app/domBindings.js +64 -0
  23. package/src/config/defaultAssets.js +29 -0
  24. package/src/config/defaultOptions.js +184 -0
  25. package/src/data/championship.js +225 -0
  26. package/src/data/customFields.js +14 -0
  27. package/src/data/demoDrivers.js +134 -0
  28. package/src/data/driverData.js +71 -0
  29. package/src/data/normalizeDrivers.js +21 -0
  30. package/src/data/vehicleData.js +81 -0
  31. package/src/index.d.ts +399 -0
  32. package/src/index.js +116 -0
  33. package/src/rendering/proceduralTrackAsset.js +517 -0
  34. package/src/rendering/renderSnapshot.js +23 -0
  35. package/src/simulation/driverController.js +253 -0
  36. package/src/simulation/raceSimulation.js +933 -0
  37. package/src/simulation/simMath.js +34 -0
  38. package/src/simulation/trackModel.js +607 -0
  39. package/src/simulation/units.js +30 -0
  40. package/src/simulation/vehiclePhysics.js +104 -0
  41. package/src/standalone.js +15 -0
  42. package/src/styles.css +1818 -0
  43. package/src/ui/componentTemplates.js +229 -0
  44. package/src/ui/shellTemplate.js +43 -0
package/src/styles.css ADDED
@@ -0,0 +1,1818 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@85,500;100,700;110,900&family=IBM+Plex+Mono:wght@500;600;700&display=swap');
2
+
3
+ .f1-sim-component {
4
+ color-scheme: dark;
5
+ --surface: #08090b;
6
+ --surface-raised: #111318;
7
+ --surface-panel: #171a20;
8
+ --line: rgba(255, 255, 255, 0.13);
9
+ --line-strong: rgba(255, 255, 255, 0.28);
10
+ --text: #f4f7fb;
11
+ --muted: #8d97a7;
12
+ --red: var(--paddock-accent-color, #e10600);
13
+ --green: var(--paddock-green-color, #14c784);
14
+ --yellow: var(--paddock-yellow-color, #ffd166);
15
+ --blue: #39a7ff;
16
+ --track: #262a31;
17
+ --track-edge: #f4f7fb;
18
+ --font-display: 'Archivo', sans-serif;
19
+ --font-mono: 'IBM Plex Mono', monospace;
20
+ --timing-columns: 1.9rem 2.1rem minmax(4.6rem, 1fr) 4.55rem 1.6rem;
21
+ --paddock-entry-count: 10;
22
+ --timing-board-max-width: var(--paddock-timing-tower-max-width, 390px);
23
+ --timing-board-min-height: calc(10.8rem + (var(--paddock-entry-count) * 2.25rem));
24
+ margin: 0;
25
+ min-height: 100%;
26
+ background: var(--surface);
27
+ color: var(--text);
28
+ font-family: var(--font-display);
29
+ }
30
+
31
+ .f1-sim-component,
32
+ .f1-sim-component * {
33
+ box-sizing: border-box;
34
+ }
35
+
36
+ .f1-sim-component [hidden] {
37
+ display: none !important;
38
+ }
39
+
40
+ .f1-sim-component button,
41
+ .f1-sim-component a {
42
+ font: inherit;
43
+ }
44
+
45
+ .sim-shell {
46
+ min-height: 100svh;
47
+ padding: clamp(0.85rem, 2vw, 1.4rem);
48
+ background: #000;
49
+ }
50
+
51
+ .sim-workspace {
52
+ min-height: calc(100svh - clamp(1.7rem, 4vw, 2.8rem));
53
+ display: flex;
54
+ flex-direction: column;
55
+ gap: 0.9rem;
56
+ }
57
+
58
+ .sim-topbar {
59
+ position: relative;
60
+ display: grid;
61
+ grid-template-columns: auto minmax(0, 1fr) auto;
62
+ align-items: center;
63
+ gap: 1rem;
64
+ min-height: 72px;
65
+ border-bottom: 2px solid rgba(225, 6, 0, 0.76);
66
+ box-shadow: 0 18px 34px rgba(0, 0, 0, 0.24);
67
+ }
68
+
69
+ .sim-backlink,
70
+ .sim-control {
71
+ border: 1px solid var(--line-strong);
72
+ color: var(--text);
73
+ background: rgba(255, 255, 255, 0.05);
74
+ text-decoration: none;
75
+ text-transform: uppercase;
76
+ letter-spacing: 0.08em;
77
+ font-size: 0.76rem;
78
+ font-weight: 800;
79
+ padding: 0.75rem 0.9rem;
80
+ cursor: pointer;
81
+ }
82
+
83
+ .sim-backlink:hover,
84
+ .sim-control:hover {
85
+ border-color: var(--text);
86
+ background: rgba(255, 255, 255, 0.1);
87
+ }
88
+
89
+ .sim-control--safety.is-active {
90
+ color: #0a0b0d;
91
+ background: var(--yellow);
92
+ border-color: var(--yellow);
93
+ }
94
+
95
+ .camera-controls button.is-active {
96
+ color: #08090b;
97
+ background: var(--text);
98
+ border-color: var(--text);
99
+ }
100
+
101
+ .sim-title-block {
102
+ min-width: 0;
103
+ }
104
+
105
+ .sim-kicker {
106
+ margin: 0 0 0.2rem;
107
+ color: var(--red);
108
+ font-family: var(--font-mono);
109
+ font-size: 0.72rem;
110
+ font-weight: 700;
111
+ letter-spacing: 0.16em;
112
+ text-transform: uppercase;
113
+ }
114
+
115
+ .f1-sim-component h1 {
116
+ margin: 0;
117
+ font-size: clamp(1.8rem, 4vw, 4.6rem);
118
+ line-height: 0.88;
119
+ text-transform: uppercase;
120
+ letter-spacing: 0;
121
+ }
122
+
123
+ .sim-controls {
124
+ display: flex;
125
+ gap: 0.6rem;
126
+ justify-content: flex-end;
127
+ }
128
+
129
+ .sim-external-camera-controls {
130
+ display: flex;
131
+ justify-content: flex-end;
132
+ }
133
+
134
+ .sim-grid {
135
+ flex: 1;
136
+ min-height: 0;
137
+ position: relative;
138
+ display: grid;
139
+ grid-template-columns: minmax(255px, 0.78fr) minmax(500px, 3fr) minmax(270px, 0.9fr);
140
+ gap: 0.9rem;
141
+ }
142
+
143
+ .sim-shell--left-tower-overlay .sim-grid,
144
+ .sim-shell--left-tower-overlay.sim-grid {
145
+ --timing-board-width: max(255px, calc((100cqw - 1.8rem) * 0.78 / 4.68));
146
+ --race-data-safe-left: calc(2rem + var(--timing-board-width));
147
+ --race-data-right-gutter: 1rem;
148
+ --race-data-available-width: calc(100% - var(--race-data-safe-left) - var(--race-data-right-gutter));
149
+ container-type: inline-size;
150
+ position: relative;
151
+ grid-template-columns: minmax(620px, 1fr) minmax(270px, 0.9fr);
152
+ }
153
+
154
+ .sim-shell--left-tower-overlay .sim-canvas-panel {
155
+ grid-column: 1;
156
+ }
157
+
158
+ .sim-canvas-panel--with-timing-tower {
159
+ --timing-board-width: min(var(--timing-board-max-width), max(255px, calc((100cqw - 1.8rem) * 0.78 / 4.68)));
160
+ --race-data-safe-left: calc(2rem + var(--timing-board-width));
161
+ --race-data-right-gutter: 1rem;
162
+ --race-data-available-width: calc(100% - var(--race-data-safe-left) - var(--race-data-right-gutter));
163
+ container-type: inline-size;
164
+ }
165
+
166
+ .sim-shell--left-tower-overlay.sim-shell--timing-expand-race-view .sim-canvas-panel {
167
+ min-height: max(var(--paddock-race-view-min-height, 620px), var(--timing-board-min-height));
168
+ }
169
+
170
+ .sim-canvas-panel--with-timing-tower.sim-canvas-panel--timing-expand-race-view {
171
+ min-height: max(var(--paddock-race-view-min-height, 620px), var(--timing-board-min-height));
172
+ }
173
+
174
+ .sim-shell--left-tower-overlay .sim-timing {
175
+ position: absolute;
176
+ z-index: 5;
177
+ top: 1rem;
178
+ bottom: 1rem;
179
+ left: 1rem;
180
+ width: var(--timing-board-width);
181
+ min-height: 0;
182
+ background: transparent;
183
+ border: 0;
184
+ border-radius: 1.25rem;
185
+ clip-path: inset(0 round 1.25rem);
186
+ pointer-events: auto;
187
+ }
188
+
189
+ .sim-canvas-panel--with-timing-tower > .sim-timing {
190
+ position: absolute;
191
+ z-index: 5;
192
+ top: 1rem;
193
+ bottom: 1rem;
194
+ left: 1rem;
195
+ width: var(--timing-board-width);
196
+ max-width: var(--timing-board-width);
197
+ min-height: 0;
198
+ background: transparent;
199
+ border: 0;
200
+ border-radius: 1.25rem;
201
+ clip-path: inset(0 round 1.25rem);
202
+ pointer-events: auto;
203
+ }
204
+
205
+ .sim-shell--left-tower-overlay.sim-shell--timing-scroll .sim-timing {
206
+ overflow: hidden;
207
+ }
208
+
209
+ .sim-canvas-panel--timing-scroll .sim-timing {
210
+ overflow: hidden;
211
+ }
212
+
213
+ .sim-shell--left-tower-overlay .sim-canvas-panel > .camera-controls {
214
+ left: calc(2rem + var(--timing-board-width));
215
+ max-width: calc(100% - (2rem + var(--timing-board-width)) - 1rem);
216
+ }
217
+
218
+ .sim-canvas-panel--with-timing-tower > .camera-controls {
219
+ left: calc(2rem + var(--timing-board-width));
220
+ max-width: calc(100% - (2rem + var(--timing-board-width)) - 1rem);
221
+ }
222
+
223
+ .sim-shell--left-tower-overlay .start-lights {
224
+ left: calc((2rem + var(--timing-board-width)) + (100% - (2rem + var(--timing-board-width))) / 2);
225
+ }
226
+
227
+ .sim-canvas-panel--with-timing-tower > .start-lights {
228
+ left: calc((2rem + var(--timing-board-width)) + (100% - (2rem + var(--timing-board-width))) / 2);
229
+ }
230
+
231
+ .sim-shell--left-tower-overlay .race-data-panel {
232
+ z-index: 8;
233
+ grid-template-columns: clamp(4.6rem, 7.5cqw, 7rem) minmax(0, 1fr) auto;
234
+ }
235
+
236
+ .sim-canvas-panel--with-timing-tower .race-data-panel {
237
+ z-index: 8;
238
+ grid-template-columns: clamp(4.6rem, 7.5cqw, 7rem) minmax(0, 1fr) auto;
239
+ }
240
+
241
+ @container (min-width: 980px) {
242
+ .sim-shell--left-tower-overlay .race-data-panel--auto,
243
+ .sim-canvas-panel--with-timing-tower .race-data-panel--auto {
244
+ --race-data-banner-left: calc(var(--race-data-safe-left) + (var(--race-data-available-width) / 2));
245
+ --race-data-banner-width: min(860px, calc(var(--race-data-available-width) - 0.5rem));
246
+ --race-data-banner-translate-x: -50%;
247
+ }
248
+ }
249
+
250
+ .sim-shell--left-tower-overlay .race-data-copy {
251
+ padding-inline: 0.45rem 0.8rem;
252
+ }
253
+
254
+ .sim-canvas-panel--with-timing-tower .race-data-copy {
255
+ padding-inline: 0.45rem 0.8rem;
256
+ }
257
+
258
+ .sim-shell--left-tower-overlay .race-data-number {
259
+ padding-inline: 0.45rem;
260
+ font-size: clamp(3.2rem, 6cqw, 5.3rem);
261
+ }
262
+
263
+ .sim-canvas-panel--with-timing-tower .race-data-number {
264
+ padding-inline: 0.45rem;
265
+ font-size: clamp(3.2rem, 6cqw, 5.3rem);
266
+ }
267
+
268
+ .sim-shell--left-tower-overlay .race-data-link {
269
+ min-width: clamp(104px, 10cqw, 140px);
270
+ margin-right: 0.55rem;
271
+ padding-inline: 0.75rem;
272
+ font-size: 0.64rem;
273
+ }
274
+
275
+ .sim-canvas-panel--with-timing-tower .race-data-link {
276
+ min-width: clamp(104px, 10cqw, 140px);
277
+ margin-right: 0.55rem;
278
+ padding-inline: 0.75rem;
279
+ font-size: 0.64rem;
280
+ }
281
+
282
+ .sim-timing,
283
+ .sim-telemetry,
284
+ .sim-canvas-panel {
285
+ min-height: 0;
286
+ background: color-mix(in srgb, var(--surface-raised) 92%, transparent);
287
+ border: 1px solid var(--line);
288
+ }
289
+
290
+ .sim-timing,
291
+ .sim-telemetry {
292
+ position: relative;
293
+ padding: 0.9rem;
294
+ overflow: hidden;
295
+ }
296
+
297
+ .sim-timing.broadcast-tower {
298
+ position: relative;
299
+ width: min(100%, var(--timing-board-max-width));
300
+ max-width: var(--timing-board-max-width);
301
+ height: 100%;
302
+ padding: 0;
303
+ background: transparent;
304
+ border: 0;
305
+ overflow: hidden;
306
+ }
307
+
308
+ .sim-shell--left-tower-overlay .sim-timing.broadcast-tower,
309
+ .sim-canvas-panel--with-timing-tower > .sim-timing.broadcast-tower {
310
+ position: absolute;
311
+ width: var(--timing-board-width);
312
+ max-width: var(--timing-board-width);
313
+ height: auto;
314
+ }
315
+
316
+ .broadcast-tower-frame {
317
+ position: relative;
318
+ height: 100%;
319
+ min-height: 0;
320
+ display: flex;
321
+ flex-direction: column;
322
+ padding: 0.65rem 0.5rem 0.75rem;
323
+ overflow: hidden;
324
+ background:
325
+ linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.015)),
326
+ linear-gradient(160deg, rgba(26, 44, 74, 0.9) 0%, rgba(15, 31, 53, 0.94) 42%, rgba(10, 21, 39, 0.98) 100%);
327
+ border: 1px solid rgba(255, 255, 255, 0.2);
328
+ border-radius: 1.25rem;
329
+ box-shadow:
330
+ inset 0 1px 0 rgba(255, 255, 255, 0.18),
331
+ inset 0 -24px 42px rgba(0, 0, 0, 0.34),
332
+ 0 24px 70px rgba(0, 0, 0, 0.42);
333
+ }
334
+
335
+ .broadcast-tower-frame::before {
336
+ content: '';
337
+ position: absolute;
338
+ inset: 0;
339
+ pointer-events: none;
340
+ background:
341
+ linear-gradient(90deg, rgba(255, 255, 255, 0.12), transparent 18%, transparent 82%, rgba(225, 6, 0, 0.18)),
342
+ linear-gradient(180deg, rgba(255, 255, 255, 0.08), transparent 18%);
343
+ mix-blend-mode: screen;
344
+ opacity: 0.7;
345
+ }
346
+
347
+ .broadcast-brand,
348
+ .broadcast-lap,
349
+ .broadcast-safety-banner,
350
+ .broadcast-column-head,
351
+ .timing-list {
352
+ position: relative;
353
+ z-index: 1;
354
+ }
355
+
356
+ .broadcast-brand {
357
+ display: flex;
358
+ align-items: center;
359
+ justify-content: center;
360
+ min-height: 52px;
361
+ padding: 0.35rem 0.55rem 0.55rem;
362
+ color: #f7f8fb;
363
+ text-transform: uppercase;
364
+ }
365
+
366
+ .broadcast-f1-logo {
367
+ display: block;
368
+ width: 6.9rem;
369
+ max-width: 74%;
370
+ height: auto;
371
+ object-fit: contain;
372
+ }
373
+
374
+ .broadcast-lap {
375
+ display: flex;
376
+ align-items: baseline;
377
+ justify-content: center;
378
+ gap: 0.36rem;
379
+ padding: 0.58rem 0.5rem 0.7rem;
380
+ border-top: 1px solid rgba(255, 255, 255, 0.14);
381
+ border-bottom: 1px solid rgba(255, 255, 255, 0.14);
382
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(0, 0, 0, 0.2));
383
+ color: rgba(244, 247, 251, 0.88);
384
+ font-family: var(--font-display);
385
+ font-size: 0.96rem;
386
+ font-weight: 600;
387
+ letter-spacing: 0.04em;
388
+ text-transform: uppercase;
389
+ }
390
+
391
+ .broadcast-lap strong {
392
+ color: #fff;
393
+ font-size: 1.62rem;
394
+ font-weight: 900;
395
+ letter-spacing: -0.04em;
396
+ }
397
+
398
+ .broadcast-safety-banner {
399
+ display: grid;
400
+ grid-template-columns: 3.4rem minmax(0, 1fr);
401
+ align-items: center;
402
+ margin: 0;
403
+ background: #e0ce00;
404
+ color: #0a0b0d;
405
+ text-transform: uppercase;
406
+ }
407
+
408
+ .broadcast-safety-banner[hidden] {
409
+ display: none;
410
+ }
411
+
412
+ .broadcast-safety-banner span {
413
+ display: grid;
414
+ place-items: center;
415
+ min-height: 2.65rem;
416
+ border-right: 2px solid rgba(0, 0, 0, 0.28);
417
+ font-family: var(--font-display);
418
+ font-size: 1rem;
419
+ font-weight: 900;
420
+ letter-spacing: -0.06em;
421
+ }
422
+
423
+ .broadcast-safety-banner strong {
424
+ padding: 0 0.65rem;
425
+ font-size: 1.1rem;
426
+ font-weight: 900;
427
+ line-height: 0.9;
428
+ }
429
+
430
+ .broadcast-gap-mode {
431
+ display: grid;
432
+ grid-template-columns: repeat(2, minmax(0, 1fr));
433
+ gap: 0.35rem;
434
+ padding: 0.45rem 0.2rem 0.2rem;
435
+ }
436
+
437
+ .broadcast-gap-mode button {
438
+ min-width: 0;
439
+ min-height: 1.75rem;
440
+ color: rgba(244, 247, 251, 0.58);
441
+ background: rgba(255, 255, 255, 0.055);
442
+ border: 1px solid rgba(255, 255, 255, 0.12);
443
+ font-family: var(--font-mono);
444
+ font-size: 0.6rem;
445
+ font-weight: 900;
446
+ letter-spacing: 0.08em;
447
+ text-transform: uppercase;
448
+ cursor: pointer;
449
+ }
450
+
451
+ .broadcast-gap-mode button.is-active,
452
+ .broadcast-gap-mode button[aria-pressed='true'] {
453
+ color: #08090b;
454
+ background: #f5f6f8;
455
+ border-color: #f5f6f8;
456
+ }
457
+
458
+ .broadcast-column-head {
459
+ display: grid;
460
+ grid-template-columns: var(--timing-columns);
461
+ gap: 0;
462
+ padding: 0.42rem 0 0.35rem;
463
+ color: rgba(244, 247, 251, 0.44);
464
+ font-family: var(--font-mono);
465
+ font-size: 0.52rem;
466
+ font-weight: 800;
467
+ letter-spacing: 0.09em;
468
+ text-transform: uppercase;
469
+ }
470
+
471
+ .broadcast-column-head span:nth-child(1),
472
+ .broadcast-column-head span:nth-child(2),
473
+ .broadcast-column-head span:nth-child(5) {
474
+ text-align: center;
475
+ }
476
+
477
+ .broadcast-column-head span:nth-child(1),
478
+ .timing-position {
479
+ grid-column: 1;
480
+ }
481
+
482
+ .broadcast-column-head span:nth-child(2),
483
+ .timing-icon {
484
+ grid-column: 2;
485
+ }
486
+
487
+ .broadcast-column-head span:nth-child(3),
488
+ .timing-name {
489
+ grid-column: 3;
490
+ }
491
+
492
+ .broadcast-column-head span:nth-child(4),
493
+ .timing-gap {
494
+ grid-column: 4;
495
+ }
496
+
497
+ .broadcast-column-head span:nth-child(5),
498
+ .timing-tire {
499
+ grid-column: 5;
500
+ }
501
+
502
+ .broadcast-column-head span:nth-child(3) {
503
+ padding-inline: 0.45rem;
504
+ }
505
+
506
+ .broadcast-column-head span:nth-child(4) {
507
+ padding-right: 0.25rem;
508
+ text-align: right;
509
+ }
510
+
511
+ .timing-header,
512
+ .telemetry-header {
513
+ display: flex;
514
+ align-items: center;
515
+ justify-content: space-between;
516
+ gap: 0.75rem;
517
+ padding-bottom: 0.75rem;
518
+ border-bottom: 1px solid var(--line);
519
+ text-transform: uppercase;
520
+ }
521
+
522
+ .timing-header span,
523
+ .telemetry-header span {
524
+ color: var(--muted);
525
+ font-family: var(--font-mono);
526
+ font-size: 0.72rem;
527
+ letter-spacing: 0.12em;
528
+ }
529
+
530
+ .timing-header strong {
531
+ color: var(--green);
532
+ font-family: var(--font-mono);
533
+ font-size: 0.74rem;
534
+ }
535
+
536
+ .timing-list {
537
+ flex: 1 1 auto;
538
+ list-style: none;
539
+ padding: 0;
540
+ margin: 0;
541
+ display: grid;
542
+ grid-auto-rows: minmax(33px, max-content);
543
+ align-content: start;
544
+ justify-content: stretch;
545
+ gap: 1px;
546
+ min-height: 0;
547
+ overflow: auto;
548
+ scrollbar-width: thin;
549
+ }
550
+
551
+ .sim-shell--left-tower-overlay .timing-list {
552
+ overflow-x: hidden;
553
+ overflow-y: auto;
554
+ }
555
+
556
+ .sim-shell--left-tower-overlay .broadcast-column-head,
557
+ .sim-shell--left-tower-overlay .timing-row {
558
+ grid-template-columns: 1.7rem 1.8rem minmax(0, 1fr) minmax(2.7rem, 3.45rem) 1.25rem;
559
+ }
560
+
561
+ .sim-shell--left-tower-overlay .broadcast-column-head {
562
+ overflow: hidden;
563
+ }
564
+
565
+ .sim-shell--left-tower-overlay .broadcast-column-head span {
566
+ min-width: 0;
567
+ overflow: hidden;
568
+ text-overflow: ellipsis;
569
+ }
570
+
571
+ .timing-row {
572
+ display: grid;
573
+ grid-template-columns: var(--timing-columns);
574
+ gap: 0;
575
+ align-items: center;
576
+ width: 100%;
577
+ min-height: 33px;
578
+ padding: 0;
579
+ border: 0;
580
+ color: var(--text);
581
+ background:
582
+ linear-gradient(90deg, color-mix(in srgb, var(--driver-color, var(--red)) 10%, transparent), transparent 42%),
583
+ rgba(10, 12, 17, 0.78);
584
+ cursor: pointer;
585
+ }
586
+
587
+ .broadcast-column-head,
588
+ .timing-row {
589
+ min-width: 0;
590
+ }
591
+
592
+ .sim-shell--left-tower-overlay .timing-row {
593
+ min-width: 0;
594
+ }
595
+
596
+ .timing-row:hover {
597
+ background:
598
+ linear-gradient(90deg, color-mix(in srgb, var(--driver-color, var(--red)) 22%, transparent), transparent 52%),
599
+ rgba(28, 31, 38, 0.86);
600
+ }
601
+
602
+ .timing-row.is-selected {
603
+ color: #08090b;
604
+ outline: 0;
605
+ background: #f5f6f8;
606
+ box-shadow:
607
+ inset 4px 0 0 var(--driver-color, var(--red)),
608
+ 0 0 0 1px rgba(255, 255, 255, 0.68);
609
+ }
610
+
611
+ .timing-position,
612
+ .timing-icon,
613
+ .timing-tire,
614
+ .timing-gap {
615
+ font-family: var(--font-mono);
616
+ font-weight: 700;
617
+ }
618
+
619
+ .timing-position {
620
+ align-self: stretch;
621
+ display: grid;
622
+ place-items: center;
623
+ color: #f5f6f8;
624
+ background: rgba(2, 3, 7, 0.72);
625
+ font-size: 0.78rem;
626
+ }
627
+
628
+ .timing-row:first-child .timing-position {
629
+ background: var(--red);
630
+ }
631
+
632
+ .timing-row.is-selected .timing-position {
633
+ color: #fff;
634
+ background: var(--red);
635
+ }
636
+
637
+ .timing-icon {
638
+ display: grid;
639
+ place-items: center;
640
+ justify-self: center;
641
+ width: 1.3rem;
642
+ height: 1.3rem;
643
+ color: #08090b;
644
+ background: var(--driver-color, var(--red));
645
+ border-radius: 0.24rem;
646
+ font-size: 0.48rem;
647
+ letter-spacing: -0.04em;
648
+ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.32);
649
+ }
650
+
651
+ .timing-team-icon {
652
+ background: var(--team-color, var(--driver-color, var(--red)));
653
+ }
654
+
655
+ .timing-name {
656
+ min-width: 0;
657
+ display: block;
658
+ overflow: hidden;
659
+ padding-inline: 0.45rem;
660
+ font-size: 0.76rem;
661
+ font-weight: 900;
662
+ letter-spacing: 0.015em;
663
+ text-align: left;
664
+ text-overflow: ellipsis;
665
+ white-space: nowrap;
666
+ text-transform: uppercase;
667
+ }
668
+
669
+ .timing-gap {
670
+ color: rgba(244, 247, 251, 0.76);
671
+ font-size: 0.66rem;
672
+ padding-right: 0.25rem;
673
+ text-align: right;
674
+ }
675
+
676
+ .timing-row.is-selected .timing-gap {
677
+ color: #08090b;
678
+ }
679
+
680
+ .timing-tire {
681
+ justify-self: center;
682
+ color: #f3e35f;
683
+ font-size: 0.72rem;
684
+ text-align: center;
685
+ }
686
+
687
+ .timing-tire--s {
688
+ color: #ff3b30;
689
+ }
690
+
691
+ .timing-tire--m {
692
+ color: #f3e35f;
693
+ }
694
+
695
+ .timing-tire--h {
696
+ color: #e9eef5;
697
+ }
698
+
699
+ .timing-row.is-selected .timing-tire--h,
700
+ .timing-row.is-selected .timing-tire--m,
701
+ .timing-row.is-selected .timing-tire--s {
702
+ color: #08090b;
703
+ }
704
+
705
+ .sim-canvas-panel {
706
+ position: relative;
707
+ min-height: var(--paddock-race-view-min-height, 620px);
708
+ overflow: hidden;
709
+ box-shadow:
710
+ inset 0 0 90px rgba(0, 0, 0, 0.42),
711
+ 0 24px 70px rgba(0, 0, 0, 0.32);
712
+ }
713
+
714
+ .track-canvas {
715
+ position: absolute;
716
+ inset: 0;
717
+ }
718
+
719
+ .track-canvas canvas {
720
+ width: 100% !important;
721
+ height: 100% !important;
722
+ display: block;
723
+ }
724
+
725
+ .camera-controls {
726
+ position: absolute;
727
+ top: 1rem;
728
+ left: 1rem;
729
+ display: flex;
730
+ flex-wrap: wrap;
731
+ gap: 0.35rem;
732
+ max-width: calc(100% - 2rem);
733
+ padding: 0.35rem;
734
+ background: rgba(8, 9, 11, 0.72);
735
+ border: 1px solid var(--line);
736
+ backdrop-filter: blur(14px);
737
+ }
738
+
739
+ .camera-controls--external {
740
+ position: relative;
741
+ max-width: 100%;
742
+ justify-content: flex-end;
743
+ background: rgba(8, 9, 11, 0.84);
744
+ }
745
+
746
+ .camera-controls button {
747
+ border: 1px solid rgba(255, 255, 255, 0.22);
748
+ color: var(--text);
749
+ background: rgba(255, 255, 255, 0.06);
750
+ font-family: var(--font-mono);
751
+ font-size: 0.66rem;
752
+ font-weight: 800;
753
+ letter-spacing: 0.08em;
754
+ text-transform: uppercase;
755
+ padding: 0.48rem 0.58rem;
756
+ cursor: pointer;
757
+ }
758
+
759
+ .camera-controls button:hover {
760
+ border-color: var(--text);
761
+ }
762
+
763
+ .fps-counter {
764
+ position: absolute;
765
+ top: 1rem;
766
+ right: 1rem;
767
+ z-index: 3;
768
+ display: inline-flex;
769
+ align-items: baseline;
770
+ gap: 0.4rem;
771
+ padding: 0.38rem 0.55rem;
772
+ color: rgba(244, 247, 251, 0.88);
773
+ background: rgba(8, 9, 11, 0.68);
774
+ border: 1px solid rgba(255, 255, 255, 0.16);
775
+ font-family: var(--font-mono);
776
+ font-size: 0.62rem;
777
+ font-weight: 800;
778
+ letter-spacing: 0.08em;
779
+ text-transform: uppercase;
780
+ pointer-events: none;
781
+ backdrop-filter: blur(10px);
782
+ }
783
+
784
+ .fps-counter strong {
785
+ color: #fff;
786
+ font-size: 0.74rem;
787
+ }
788
+
789
+ .race-finish-panel {
790
+ position: absolute;
791
+ z-index: 9;
792
+ left: 50%;
793
+ bottom: 1.25rem;
794
+ width: min(620px, calc(100% - 2rem));
795
+ transform: translateX(-50%);
796
+ display: grid;
797
+ grid-template-columns: minmax(0, 1fr) auto;
798
+ align-items: center;
799
+ gap: 0.6rem 1rem;
800
+ padding: 0.9rem 1rem;
801
+ color: var(--text);
802
+ background:
803
+ linear-gradient(90deg, color-mix(in srgb, var(--driver-color, var(--red)) 28%, transparent), transparent 52%),
804
+ rgba(8, 9, 11, 0.9);
805
+ border: 1px solid color-mix(in srgb, var(--driver-color, var(--red)) 58%, rgba(255, 255, 255, 0.18));
806
+ border-left: 6px solid var(--driver-color, var(--red));
807
+ box-shadow: 0 18px 42px rgba(0, 0, 0, 0.34);
808
+ backdrop-filter: blur(14px);
809
+ text-transform: uppercase;
810
+ }
811
+
812
+ .race-finish-panel span {
813
+ color: var(--muted);
814
+ font-family: var(--font-mono);
815
+ font-size: 0.66rem;
816
+ font-weight: 800;
817
+ letter-spacing: 0.12em;
818
+ }
819
+
820
+ .race-finish-panel > strong {
821
+ grid-column: 1;
822
+ font-size: clamp(1.45rem, 3vw, 2.4rem);
823
+ font-weight: 900;
824
+ line-height: 0.92;
825
+ }
826
+
827
+ .race-finish-panel ol {
828
+ grid-column: 2;
829
+ grid-row: 1 / span 2;
830
+ display: grid;
831
+ gap: 0.18rem;
832
+ min-width: 7.5rem;
833
+ margin: 0;
834
+ padding: 0;
835
+ list-style: none;
836
+ }
837
+
838
+ .race-finish-panel li {
839
+ display: grid;
840
+ grid-template-columns: 2.2rem minmax(0, 1fr);
841
+ gap: 0.45rem;
842
+ align-items: center;
843
+ font-family: var(--font-mono);
844
+ font-size: 0.72rem;
845
+ }
846
+
847
+ .race-finish-panel li strong {
848
+ min-width: 0;
849
+ overflow: hidden;
850
+ text-overflow: ellipsis;
851
+ white-space: nowrap;
852
+ }
853
+
854
+ .standalone-control {
855
+ display: inline-flex;
856
+ align-items: center;
857
+ justify-content: center;
858
+ }
859
+
860
+ .start-lights {
861
+ position: absolute;
862
+ top: 4.15rem;
863
+ left: 50%;
864
+ z-index: 4;
865
+ transform: translateX(-50%);
866
+ display: grid;
867
+ gap: 0.36rem;
868
+ justify-items: center;
869
+ padding: 0.58rem 0.72rem 0.68rem;
870
+ color: #f7f8fb;
871
+ background:
872
+ linear-gradient(180deg, rgba(255, 255, 255, 0.1), transparent),
873
+ rgba(4, 5, 8, 0.82);
874
+ border: 1px solid rgba(255, 255, 255, 0.2);
875
+ box-shadow: 0 18px 42px rgba(0, 0, 0, 0.36);
876
+ font-family: var(--font-mono);
877
+ text-transform: uppercase;
878
+ backdrop-filter: blur(14px);
879
+ }
880
+
881
+ .start-lights[hidden] {
882
+ display: none;
883
+ }
884
+
885
+ .start-lights__label {
886
+ color: rgba(244, 247, 251, 0.78);
887
+ font-size: 0.62rem;
888
+ font-weight: 900;
889
+ letter-spacing: 0.16em;
890
+ }
891
+
892
+ .start-lights__gantry {
893
+ display: grid;
894
+ grid-template-columns: repeat(5, 1.35rem);
895
+ gap: 0.34rem;
896
+ }
897
+
898
+ .start-lights__gantry span {
899
+ width: 1.35rem;
900
+ height: 1.35rem;
901
+ border-radius: 50%;
902
+ background: #15171d;
903
+ border: 2px solid rgba(255, 255, 255, 0.18);
904
+ box-shadow:
905
+ inset 0 0 12px rgba(0, 0, 0, 0.88),
906
+ 0 0 0 rgba(225, 6, 0, 0);
907
+ transition: background 80ms linear, box-shadow 80ms linear, border-color 80ms linear;
908
+ }
909
+
910
+ .start-lights__gantry span.is-lit {
911
+ background: #e10600;
912
+ border-color: rgba(255, 210, 210, 0.86);
913
+ box-shadow:
914
+ inset 0 0 8px rgba(255, 255, 255, 0.18),
915
+ 0 0 18px rgba(225, 6, 0, 0.72);
916
+ }
917
+
918
+ .start-lights.is-lights-out .start-lights__label {
919
+ color: #fff;
920
+ }
921
+
922
+ .start-lights.is-lights-out .start-lights__gantry span {
923
+ background: #08090b;
924
+ border-color: rgba(255, 255, 255, 0.12);
925
+ box-shadow: inset 0 0 16px rgba(0, 0, 0, 0.9);
926
+ }
927
+
928
+ .paddock-loading {
929
+ position: absolute;
930
+ inset: 0;
931
+ z-index: 30;
932
+ display: grid;
933
+ place-content: center;
934
+ justify-items: center;
935
+ gap: 0.52rem;
936
+ color: rgba(244, 247, 251, 0.82);
937
+ background:
938
+ radial-gradient(circle at 50% 42%, rgba(225, 6, 0, 0.2), transparent 34%),
939
+ rgba(4, 5, 8, 0.78);
940
+ font-family: var(--font-mono);
941
+ font-size: 0.62rem;
942
+ font-weight: 900;
943
+ letter-spacing: 0.16em;
944
+ text-transform: uppercase;
945
+ pointer-events: none;
946
+ backdrop-filter: blur(10px);
947
+ }
948
+
949
+ .paddock-loading__lights {
950
+ display: grid;
951
+ grid-template-columns: repeat(5, 1rem);
952
+ gap: 0.28rem;
953
+ }
954
+
955
+ .paddock-loading__lights span {
956
+ width: 1rem;
957
+ height: 1rem;
958
+ border-radius: 50%;
959
+ background: #15171d;
960
+ border: 2px solid rgba(255, 255, 255, 0.16);
961
+ box-shadow:
962
+ inset 0 0 10px rgba(0, 0, 0, 0.88),
963
+ 0 0 0 rgba(225, 6, 0, 0);
964
+ animation: paddock-loading-pulse 900ms ease-in-out infinite;
965
+ }
966
+
967
+ .paddock-loading__lights span:nth-child(2) {
968
+ animation-delay: 90ms;
969
+ }
970
+
971
+ .paddock-loading__lights span:nth-child(3) {
972
+ animation-delay: 180ms;
973
+ }
974
+
975
+ .paddock-loading__lights span:nth-child(4) {
976
+ animation-delay: 270ms;
977
+ }
978
+
979
+ .paddock-loading__lights span:nth-child(5) {
980
+ animation-delay: 360ms;
981
+ }
982
+
983
+ .paddock-loading__label {
984
+ text-shadow: 0 0 16px rgba(225, 6, 0, 0.48);
985
+ }
986
+
987
+ [data-paddock-component].is-loaded > .paddock-loading {
988
+ opacity: 0;
989
+ }
990
+
991
+ @keyframes paddock-loading-pulse {
992
+ 0%,
993
+ 100% {
994
+ background: #15171d;
995
+ border-color: rgba(255, 255, 255, 0.16);
996
+ box-shadow:
997
+ inset 0 0 10px rgba(0, 0, 0, 0.88),
998
+ 0 0 0 rgba(225, 6, 0, 0);
999
+ }
1000
+
1001
+ 45%,
1002
+ 62% {
1003
+ background: #e10600;
1004
+ border-color: rgba(255, 220, 220, 0.88);
1005
+ box-shadow:
1006
+ inset 0 0 8px rgba(255, 255, 255, 0.18),
1007
+ 0 0 18px rgba(225, 6, 0, 0.72);
1008
+ }
1009
+ }
1010
+
1011
+ .race-data-panel {
1012
+ --race-data-banner-left: 50%;
1013
+ --race-data-banner-width: min(1080px, calc(100% - 1.5rem));
1014
+ --race-data-banner-translate-x: -50%;
1015
+ position: absolute;
1016
+ left: var(--race-data-banner-left);
1017
+ bottom: 1.2rem;
1018
+ transform: translateX(var(--race-data-banner-translate-x));
1019
+ z-index: 8;
1020
+ display: grid;
1021
+ grid-template-columns: clamp(6.5rem, 12vw, 9.6rem) minmax(280px, 1fr) auto;
1022
+ align-items: center;
1023
+ width: var(--race-data-banner-width);
1024
+ min-height: 104px;
1025
+ color: var(--text);
1026
+ background:
1027
+ linear-gradient(104deg, rgba(10, 13, 22, 0.98) 0 58%, rgba(33, 39, 51, 0.9) 58.2% 68%, rgba(8, 10, 16, 0.98) 68.2% 100%),
1028
+ repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.055) 0 1px, transparent 1px 82px);
1029
+ border-left: 6px solid var(--driver-color, var(--red));
1030
+ border-bottom: 3px solid var(--driver-color, var(--red));
1031
+ clip-path: polygon(0 0, calc(100% - 18px) 0, 100% 18px, 100% 100%, 18px 100%, 0 calc(100% - 18px));
1032
+ box-shadow: 0 18px 52px rgba(0, 0, 0, 0.42), inset 0 1px rgba(255, 255, 255, 0.12);
1033
+ overflow: hidden;
1034
+ transition: opacity 180ms ease, transform 180ms ease, width 180ms ease, min-height 180ms ease, background-color 180ms ease;
1035
+ }
1036
+
1037
+ .race-data-panel.is-hidden {
1038
+ opacity: 0;
1039
+ pointer-events: none;
1040
+ transform: translate(var(--race-data-banner-translate-x), 18px);
1041
+ }
1042
+
1043
+ .race-data-panel--custom {
1044
+ --race-data-banner-left: 50%;
1045
+ --race-data-banner-width: min(1080px, calc(100% - 1.5rem));
1046
+ --race-data-banner-translate-x: -50%;
1047
+ }
1048
+
1049
+ .race-data-panel::before {
1050
+ content: "";
1051
+ position: absolute;
1052
+ inset: 0;
1053
+ background:
1054
+ linear-gradient(90deg, color-mix(in srgb, var(--driver-color, var(--red)) 70%, transparent) 0, transparent 42%),
1055
+ linear-gradient(180deg, rgba(255, 255, 255, 0.12), transparent 42%);
1056
+ opacity: 0.2;
1057
+ pointer-events: none;
1058
+ }
1059
+
1060
+ .race-data-panel::after {
1061
+ content: "";
1062
+ position: absolute;
1063
+ top: 0;
1064
+ left: 0;
1065
+ width: min(42%, 430px);
1066
+ height: 4px;
1067
+ background: linear-gradient(90deg, var(--driver-color, var(--red)), transparent);
1068
+ pointer-events: none;
1069
+ }
1070
+
1071
+ .race-data-copy,
1072
+ .race-data-number,
1073
+ .race-data-link {
1074
+ position: relative;
1075
+ z-index: 1;
1076
+ }
1077
+
1078
+ .race-data-copy {
1079
+ grid-column: 2;
1080
+ grid-row: 1;
1081
+ min-width: 0;
1082
+ padding: 0.92rem 1.45rem 0.98rem 0.55rem;
1083
+ }
1084
+
1085
+ .race-data-kicker {
1086
+ display: block;
1087
+ margin-bottom: 0.22rem;
1088
+ color: var(--driver-color, var(--red));
1089
+ font-family: var(--font-mono);
1090
+ font-size: 0.66rem;
1091
+ font-weight: 800;
1092
+ letter-spacing: 0.14em;
1093
+ text-transform: uppercase;
1094
+ }
1095
+
1096
+ .race-data-copy strong {
1097
+ display: block;
1098
+ overflow: hidden;
1099
+ text-overflow: ellipsis;
1100
+ white-space: nowrap;
1101
+ font-size: clamp(1.85rem, 3.5vw, 2.9rem);
1102
+ line-height: 0.92;
1103
+ text-transform: uppercase;
1104
+ text-shadow: 0 2px 0 rgba(0, 0, 0, 0.45), 0 0 24px color-mix(in srgb, var(--driver-color, var(--red)) 28%, transparent);
1105
+ }
1106
+
1107
+ .race-data-subtitle {
1108
+ display: block;
1109
+ margin-top: 0.28rem;
1110
+ color: rgba(244, 247, 251, 0.72);
1111
+ font-family: var(--font-mono);
1112
+ font-size: 0.68rem;
1113
+ font-weight: 800;
1114
+ letter-spacing: 0.08em;
1115
+ text-transform: uppercase;
1116
+ }
1117
+
1118
+ .race-data-number {
1119
+ grid-column: 1;
1120
+ grid-row: 1;
1121
+ display: grid;
1122
+ place-items: center;
1123
+ justify-self: stretch;
1124
+ min-width: 0;
1125
+ height: 100%;
1126
+ padding-inline: 1rem;
1127
+ color: rgba(244, 247, 251, 0.2);
1128
+ font-family: var(--font-display);
1129
+ font-size: clamp(4.1rem, 9vw, 6.6rem);
1130
+ font-style: italic;
1131
+ font-weight: 900;
1132
+ letter-spacing: -0.14em;
1133
+ line-height: 0.8;
1134
+ text-align: center;
1135
+ font-variant-numeric: tabular-nums;
1136
+ -webkit-text-stroke: 1px rgba(244, 247, 251, 0.54);
1137
+ transition: opacity 160ms ease, transform 160ms ease;
1138
+ }
1139
+
1140
+ .race-data-panel.is-project-mode .race-data-number {
1141
+ transform: translateX(-8px);
1142
+ }
1143
+
1144
+ .race-data-panel.is-radio-mode {
1145
+ grid-template-columns: minmax(280px, 1fr);
1146
+ }
1147
+
1148
+ .race-data-panel.is-radio-mode .race-data-copy {
1149
+ grid-column: 1;
1150
+ padding-left: 1.45rem;
1151
+ }
1152
+
1153
+ .race-data-panel.is-radio-mode .race-data-copy strong {
1154
+ color: #f8fafc;
1155
+ font-size: clamp(1.6rem, 3.2vw, 2.35rem);
1156
+ }
1157
+
1158
+ .race-data-panel[data-idle-mode="quote"] .race-data-copy {
1159
+ padding-top: 0.8rem;
1160
+ padding-bottom: 0.88rem;
1161
+ }
1162
+
1163
+ .race-data-panel[data-idle-mode="quote"] .race-data-copy strong {
1164
+ color: rgba(244, 247, 251, 0.78);
1165
+ font-size: clamp(0.95rem, 1.55vw, 1.2rem);
1166
+ letter-spacing: 0.05em;
1167
+ line-height: 1;
1168
+ }
1169
+
1170
+ .race-data-panel[data-idle-mode="quote"] .race-data-subtitle {
1171
+ max-width: 100%;
1172
+ margin-top: 0.34rem;
1173
+ color: #fff;
1174
+ font-family: var(--font-display);
1175
+ font-size: clamp(1.35rem, 2.9vw, 2.25rem);
1176
+ font-weight: 900;
1177
+ letter-spacing: -0.02em;
1178
+ line-height: 1;
1179
+ text-shadow: 0 2px 0 rgba(0, 0, 0, 0.52), 0 0 22px color-mix(in srgb, var(--driver-color, var(--red)) 30%, transparent);
1180
+ }
1181
+
1182
+ .race-data-panel.is-radio-mode .race-data-number {
1183
+ display: none;
1184
+ }
1185
+
1186
+ .race-data-panel.is-radio-mode .race-data-link {
1187
+ display: none;
1188
+ }
1189
+
1190
+ .race-data-link {
1191
+ grid-column: 3;
1192
+ grid-row: 1;
1193
+ display: grid;
1194
+ place-items: center;
1195
+ align-self: center;
1196
+ min-width: clamp(132px, 13vw, 176px);
1197
+ min-height: 3.1rem;
1198
+ margin-right: 0.85rem;
1199
+ padding: 0 1.05rem;
1200
+ color: #f6f8fb;
1201
+ background: color-mix(in srgb, var(--driver-color, var(--red)) 88%, #111318);
1202
+ border: 1px solid color-mix(in srgb, var(--driver-color, var(--red)) 72%, #ffffff);
1203
+ font-family: var(--font-mono);
1204
+ font-size: 0.72rem;
1205
+ font-weight: 900;
1206
+ letter-spacing: 0.08em;
1207
+ text-align: center;
1208
+ text-decoration: none;
1209
+ text-transform: uppercase;
1210
+ }
1211
+
1212
+ .race-data-link:hover {
1213
+ color: #fff;
1214
+ filter: brightness(1.12);
1215
+ }
1216
+
1217
+ .telemetry-grid dt {
1218
+ display: block;
1219
+ margin-bottom: 0.22rem;
1220
+ color: var(--muted);
1221
+ font-family: var(--font-mono);
1222
+ font-size: 0.68rem;
1223
+ font-weight: 700;
1224
+ letter-spacing: 0.12em;
1225
+ text-transform: uppercase;
1226
+ }
1227
+
1228
+ .telemetry-grid dd {
1229
+ margin: 0;
1230
+ font-family: var(--font-mono);
1231
+ font-size: clamp(0.86rem, 1.6vw, 1.15rem);
1232
+ }
1233
+
1234
+ .telemetry-header {
1235
+ align-items: flex-start;
1236
+ }
1237
+
1238
+ .telemetry-header strong {
1239
+ min-width: 0;
1240
+ text-align: right;
1241
+ font-size: 0.92rem;
1242
+ text-transform: uppercase;
1243
+ }
1244
+
1245
+ .telemetry-grid {
1246
+ margin: 1rem 0 0;
1247
+ display: grid;
1248
+ grid-template-columns: 1fr;
1249
+ gap: 1px;
1250
+ background: var(--line);
1251
+ }
1252
+
1253
+ .telemetry-grid > div {
1254
+ display: flex;
1255
+ justify-content: space-between;
1256
+ gap: 1rem;
1257
+ padding: 0.82rem 0.7rem;
1258
+ background: var(--surface-panel);
1259
+ }
1260
+
1261
+ .telemetry-grid dd {
1262
+ color: var(--text);
1263
+ text-align: right;
1264
+ }
1265
+
1266
+ .car-overview {
1267
+ position: relative;
1268
+ margin-top: 1rem;
1269
+ padding-top: 0.85rem;
1270
+ border-top: 1px solid var(--line);
1271
+ }
1272
+
1273
+ .car-overview-header {
1274
+ display: flex;
1275
+ align-items: center;
1276
+ justify-content: space-between;
1277
+ gap: 0.75rem;
1278
+ margin-bottom: 0.8rem;
1279
+ text-transform: uppercase;
1280
+ }
1281
+
1282
+ .car-overview-header span {
1283
+ color: var(--muted);
1284
+ font-family: var(--font-mono);
1285
+ font-size: 0.64rem;
1286
+ font-weight: 800;
1287
+ letter-spacing: 0.12em;
1288
+ }
1289
+
1290
+ .car-overview-header strong {
1291
+ color: var(--driver-color, var(--red));
1292
+ font-family: var(--font-mono);
1293
+ font-size: 0.72rem;
1294
+ letter-spacing: 0.08em;
1295
+ }
1296
+
1297
+ .car-overview-toggle {
1298
+ display: grid;
1299
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1300
+ gap: 0.35rem;
1301
+ margin-bottom: 0.7rem;
1302
+ }
1303
+
1304
+ .car-overview-toggle button {
1305
+ min-width: 0;
1306
+ min-height: 2.15rem;
1307
+ color: var(--muted);
1308
+ font-family: var(--font-mono);
1309
+ font-size: 0.68rem;
1310
+ font-weight: 900;
1311
+ letter-spacing: 0.08em;
1312
+ text-transform: uppercase;
1313
+ background: rgba(255, 255, 255, 0.055);
1314
+ border: 1px solid rgba(255, 255, 255, 0.12);
1315
+ cursor: pointer;
1316
+ }
1317
+
1318
+ .car-overview-toggle button.is-active,
1319
+ .car-overview-toggle button[aria-pressed='true'] {
1320
+ color: #fff;
1321
+ background: color-mix(in srgb, var(--driver-color, var(--red)) 30%, rgba(255, 255, 255, 0.075));
1322
+ border-color: color-mix(in srgb, var(--driver-color, var(--red)) 72%, rgba(255, 255, 255, 0.18));
1323
+ }
1324
+
1325
+ .car-overview-diagram {
1326
+ --arrow-line: color-mix(in srgb, var(--driver-color, var(--red)) 72%, rgba(255, 255, 255, 0.36));
1327
+ position: relative;
1328
+ display: grid;
1329
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1330
+ grid-template-rows: auto auto 5.7rem auto auto;
1331
+ gap: 0.5rem 0.5rem;
1332
+ min-height: 15.25rem;
1333
+ padding: 0.82rem 0.62rem;
1334
+ overflow: hidden;
1335
+ background:
1336
+ radial-gradient(circle at 50% 48%, color-mix(in srgb, var(--driver-color, var(--red)) 24%, transparent) 0 18%, transparent 42%),
1337
+ linear-gradient(135deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.012));
1338
+ border: 1px solid rgba(255, 255, 255, 0.12);
1339
+ }
1340
+
1341
+ .car-overview-diagram::before {
1342
+ content: '';
1343
+ position: absolute;
1344
+ inset: 0.55rem;
1345
+ pointer-events: none;
1346
+ background:
1347
+ linear-gradient(var(--arrow-line), var(--arrow-line)) 50% 18% / 1px 22% no-repeat,
1348
+ linear-gradient(var(--arrow-line), var(--arrow-line)) 50% 61% / 1px 17% no-repeat,
1349
+ linear-gradient(90deg, var(--arrow-line), var(--arrow-line)) 25% 48% / 24% 1px no-repeat,
1350
+ linear-gradient(90deg, var(--arrow-line), var(--arrow-line)) 75% 48% / 24% 1px no-repeat;
1351
+ opacity: 0.62;
1352
+ }
1353
+
1354
+ .car-overview-diagram::after {
1355
+ content: '';
1356
+ position: absolute;
1357
+ inset: 0;
1358
+ pointer-events: none;
1359
+ background: repeating-linear-gradient(
1360
+ 90deg,
1361
+ rgba(255, 255, 255, 0.04) 0 1px,
1362
+ transparent 1px 36px
1363
+ );
1364
+ opacity: 0.44;
1365
+ }
1366
+
1367
+ .car-overview-car {
1368
+ position: relative;
1369
+ z-index: 1;
1370
+ grid-column: 1 / -1;
1371
+ grid-row: 3;
1372
+ align-self: center;
1373
+ justify-self: center;
1374
+ display: grid;
1375
+ place-items: center;
1376
+ width: 5.15rem;
1377
+ height: 3.15rem;
1378
+ color: #08090b;
1379
+ transform: skewX(-10deg);
1380
+ }
1381
+
1382
+ .car-overview-car::before {
1383
+ content: '';
1384
+ position: absolute;
1385
+ inset: 0;
1386
+ background:
1387
+ linear-gradient(90deg, rgba(255, 255, 255, 0.74), transparent 44%),
1388
+ var(--driver-color, var(--red));
1389
+ clip-path: polygon(12% 7%, 82% 7%, 100% 50%, 82% 93%, 12% 93%, 0 50%);
1390
+ opacity: 0.28;
1391
+ box-shadow:
1392
+ inset 0 0 0 2px rgba(255, 255, 255, 0.34),
1393
+ 0 0 28px color-mix(in srgb, var(--driver-color, var(--red)) 44%, transparent);
1394
+ }
1395
+
1396
+ .car-overview-car::after {
1397
+ content: '';
1398
+ position: absolute;
1399
+ inset: 0.58rem 0.86rem;
1400
+ border-top: 3px solid rgba(8, 9, 11, 0.74);
1401
+ border-bottom: 3px solid rgba(8, 9, 11, 0.74);
1402
+ transform: skewX(10deg);
1403
+ z-index: 1;
1404
+ opacity: 0.34;
1405
+ }
1406
+
1407
+ .car-overview-car-image {
1408
+ position: absolute;
1409
+ z-index: 2;
1410
+ inset: 0.25rem 0.2rem;
1411
+ width: calc(100% - 0.4rem);
1412
+ height: calc(100% - 0.5rem);
1413
+ object-fit: contain;
1414
+ filter:
1415
+ drop-shadow(0 0 10px color-mix(in srgb, var(--driver-color, var(--red)) 72%, transparent))
1416
+ saturate(1.15)
1417
+ brightness(1.08);
1418
+ transform: skewX(10deg);
1419
+ }
1420
+
1421
+ .car-overview-icon,
1422
+ .car-overview-number,
1423
+ .car-overview-core-stat {
1424
+ position: relative;
1425
+ z-index: 3;
1426
+ transform: skewX(10deg);
1427
+ font-family: var(--font-mono);
1428
+ font-weight: 900;
1429
+ }
1430
+
1431
+ .car-overview-icon {
1432
+ font-size: 0.86rem;
1433
+ letter-spacing: -0.07em;
1434
+ }
1435
+
1436
+ .car-overview-number {
1437
+ position: absolute;
1438
+ right: 0.42rem;
1439
+ bottom: 0.18rem;
1440
+ color: rgba(244, 247, 251, 0.68);
1441
+ font-size: 0.54rem;
1442
+ }
1443
+
1444
+ .car-overview-core-stat {
1445
+ position: absolute;
1446
+ left: 50%;
1447
+ bottom: -1.05rem;
1448
+ color: color-mix(in srgb, var(--driver-color, var(--red)) 62%, #ffffff);
1449
+ font-size: 0.58rem;
1450
+ letter-spacing: 0.05em;
1451
+ text-transform: uppercase;
1452
+ transform: translateX(-50%) skewX(10deg);
1453
+ }
1454
+
1455
+ .car-overview-cell {
1456
+ position: relative;
1457
+ z-index: 1;
1458
+ min-width: 0;
1459
+ padding: 0.5rem 0.48rem;
1460
+ background: rgba(8, 9, 11, 0.76);
1461
+ border: 1px solid rgba(255, 255, 255, 0.12);
1462
+ box-shadow: inset 3px 0 0 color-mix(in srgb, var(--driver-color, var(--red)) 78%, transparent);
1463
+ }
1464
+
1465
+ .car-overview-cell::after {
1466
+ content: '';
1467
+ position: absolute;
1468
+ width: 0.42rem;
1469
+ height: 0.42rem;
1470
+ background: var(--arrow-line);
1471
+ transform: rotate(45deg);
1472
+ }
1473
+
1474
+ .car-overview-cell--slot-1 {
1475
+ grid-column: 1;
1476
+ grid-row: 1;
1477
+ justify-self: stretch;
1478
+ width: auto;
1479
+ }
1480
+
1481
+ .car-overview-cell--slot-1::after,
1482
+ .car-overview-cell--slot-2::after {
1483
+ right: 50%;
1484
+ bottom: -0.25rem;
1485
+ transform: translateX(50%) rotate(45deg);
1486
+ }
1487
+
1488
+ .car-overview-cell--slot-2 {
1489
+ grid-column: 2;
1490
+ grid-row: 1;
1491
+ justify-self: stretch;
1492
+ width: auto;
1493
+ }
1494
+
1495
+ .car-overview-cell--slot-3 {
1496
+ grid-column: 1;
1497
+ grid-row: 2;
1498
+ justify-self: stretch;
1499
+ width: auto;
1500
+ }
1501
+
1502
+ .car-overview-cell--slot-4 {
1503
+ grid-column: 2;
1504
+ grid-row: 2;
1505
+ justify-self: stretch;
1506
+ width: auto;
1507
+ }
1508
+
1509
+ .car-overview-cell--slot-3::after,
1510
+ .car-overview-cell--slot-4::after {
1511
+ top: 50%;
1512
+ transform: translateY(-50%) rotate(45deg);
1513
+ }
1514
+
1515
+ .car-overview-cell--slot-3::after {
1516
+ right: -0.25rem;
1517
+ }
1518
+
1519
+ .car-overview-cell--slot-4::after {
1520
+ left: -0.25rem;
1521
+ }
1522
+
1523
+ .car-overview-cell--slot-5,
1524
+ .car-overview-cell--slot-6 {
1525
+ grid-row: 4;
1526
+ }
1527
+
1528
+ .car-overview-cell--slot-5 {
1529
+ grid-column: 1;
1530
+ }
1531
+
1532
+ .car-overview-cell--slot-6 {
1533
+ grid-column: 2;
1534
+ }
1535
+
1536
+ .car-overview-cell--slot-5::after,
1537
+ .car-overview-cell--slot-6::after {
1538
+ right: 50%;
1539
+ top: -0.25rem;
1540
+ transform: translateX(50%) rotate(45deg);
1541
+ }
1542
+
1543
+ .car-overview-cell--slot-7 {
1544
+ grid-column: 1 / -1;
1545
+ grid-row: 5;
1546
+ justify-self: stretch;
1547
+ display: grid;
1548
+ grid-template-columns: minmax(0, auto) minmax(0, 1fr);
1549
+ align-items: end;
1550
+ gap: 0.5rem;
1551
+ width: auto;
1552
+ }
1553
+
1554
+ .car-overview-cell--slot-7::after {
1555
+ left: 50%;
1556
+ top: -0.25rem;
1557
+ transform: translateX(-50%) rotate(45deg);
1558
+ }
1559
+
1560
+ .car-overview-cell--slot-7 > span {
1561
+ margin-bottom: 0;
1562
+ }
1563
+
1564
+ .car-overview-cell--slot-7 strong {
1565
+ text-align: right;
1566
+ }
1567
+
1568
+ .car-overview-cell > span {
1569
+ display: block;
1570
+ margin-bottom: 0.18rem;
1571
+ color: var(--muted);
1572
+ font-family: var(--font-mono);
1573
+ font-size: 0.56rem;
1574
+ font-weight: 800;
1575
+ letter-spacing: 0.08em;
1576
+ text-transform: uppercase;
1577
+ }
1578
+
1579
+ .car-overview-cell strong {
1580
+ display: block;
1581
+ overflow: hidden;
1582
+ color: #fff;
1583
+ font-family: var(--font-mono);
1584
+ font-size: 0.7rem;
1585
+ font-weight: 900;
1586
+ letter-spacing: -0.03em;
1587
+ text-overflow: ellipsis;
1588
+ white-space: nowrap;
1589
+ }
1590
+
1591
+ .car-overview-cell strong span {
1592
+ display: inline;
1593
+ margin: 0;
1594
+ color: inherit;
1595
+ font: inherit;
1596
+ letter-spacing: inherit;
1597
+ text-transform: none;
1598
+ }
1599
+
1600
+ @media (max-width: 1120px) {
1601
+ .sim-grid,
1602
+ .sim-shell--left-tower-overlay .sim-grid,
1603
+ .sim-shell--left-tower-overlay.sim-grid {
1604
+ grid-template-columns: 1fr;
1605
+ }
1606
+
1607
+ .sim-canvas-panel,
1608
+ .sim-shell--left-tower-overlay .sim-canvas-panel {
1609
+ min-height: 62svh;
1610
+ grid-column: auto;
1611
+ order: -1;
1612
+ }
1613
+
1614
+ .sim-shell--left-tower-overlay.sim-shell--timing-expand-race-view .sim-canvas-panel {
1615
+ min-height: 62svh;
1616
+ }
1617
+
1618
+ .sim-shell--left-tower-overlay .sim-timing {
1619
+ position: static;
1620
+ width: auto;
1621
+ max-width: 390px;
1622
+ clip-path: none;
1623
+ }
1624
+
1625
+ .sim-shell--left-tower-overlay .sim-canvas-panel > .camera-controls {
1626
+ left: 1rem;
1627
+ max-width: calc(100% - 2rem);
1628
+ }
1629
+
1630
+ .sim-shell--left-tower-overlay .start-lights {
1631
+ left: 50%;
1632
+ }
1633
+
1634
+ .sim-shell--left-tower-overlay .race-data-panel {
1635
+ --race-data-banner-left: 50%;
1636
+ --race-data-banner-width: min(1080px, calc(100% - 1.5rem));
1637
+ left: 50%;
1638
+ }
1639
+
1640
+ .sim-timing,
1641
+ .sim-telemetry {
1642
+ min-height: auto;
1643
+ }
1644
+
1645
+ .sim-telemetry {
1646
+ display: grid;
1647
+ grid-template-columns: minmax(0, 0.9fr) minmax(280px, 1.1fr);
1648
+ gap: 1rem;
1649
+ }
1650
+
1651
+ .telemetry-header {
1652
+ grid-column: 1 / -1;
1653
+ }
1654
+
1655
+ .telemetry-grid {
1656
+ margin-top: 0;
1657
+ }
1658
+
1659
+ .car-overview {
1660
+ margin-top: 0;
1661
+ padding-top: 0;
1662
+ border-top: 0;
1663
+ }
1664
+ }
1665
+
1666
+ @media (max-width: 760px) {
1667
+ .sim-shell {
1668
+ padding: 0.75rem;
1669
+ }
1670
+
1671
+ .sim-grid,
1672
+ .sim-shell--left-tower-overlay .sim-grid,
1673
+ .sim-shell--left-tower-overlay.sim-grid {
1674
+ grid-template-columns: minmax(0, 1fr);
1675
+ }
1676
+
1677
+ .sim-shell--left-tower-overlay .sim-timing,
1678
+ .sim-canvas-panel--with-timing-tower > .sim-timing {
1679
+ width: min(72vw, var(--timing-board-max-width));
1680
+ }
1681
+
1682
+ .sim-topbar {
1683
+ grid-template-columns: 1fr;
1684
+ align-items: stretch;
1685
+ }
1686
+
1687
+ .sim-controls,
1688
+ .sim-backlink {
1689
+ justify-content: stretch;
1690
+ }
1691
+
1692
+ .sim-controls {
1693
+ display: grid;
1694
+ grid-template-columns: 1fr 1fr;
1695
+ }
1696
+
1697
+ .sim-control,
1698
+ .sim-backlink {
1699
+ text-align: center;
1700
+ }
1701
+
1702
+ .sim-canvas-panel {
1703
+ min-height: 58svh;
1704
+ }
1705
+
1706
+ .camera-controls {
1707
+ max-width: calc(100% - 5.4rem);
1708
+ }
1709
+
1710
+ .race-data-panel {
1711
+ left: 50%;
1712
+ bottom: 0.75rem;
1713
+ grid-template-columns: minmax(0, 1fr) auto;
1714
+ width: calc(100% - 1.5rem);
1715
+ min-height: 88px;
1716
+ }
1717
+
1718
+ .race-data-panel.is-radio-mode {
1719
+ grid-template-columns: minmax(0, 1fr);
1720
+ }
1721
+
1722
+ .race-data-copy {
1723
+ grid-column: 2;
1724
+ padding: 0.78rem 0.95rem 0.85rem;
1725
+ }
1726
+
1727
+ .race-data-panel.is-radio-mode .race-data-copy {
1728
+ grid-column: 1;
1729
+ padding-left: 0.95rem;
1730
+ }
1731
+
1732
+ .race-data-number {
1733
+ grid-column: 1;
1734
+ min-width: 4.8rem;
1735
+ height: auto;
1736
+ font-size: 3.4rem;
1737
+ }
1738
+
1739
+ .race-data-link {
1740
+ grid-column: 1 / -1;
1741
+ margin: 0;
1742
+ min-height: 48px;
1743
+ }
1744
+
1745
+ .sim-telemetry {
1746
+ display: block;
1747
+ }
1748
+
1749
+ .telemetry-grid {
1750
+ margin-top: 1rem;
1751
+ }
1752
+
1753
+ .car-overview {
1754
+ margin-top: 1rem;
1755
+ padding-top: 0.85rem;
1756
+ border-top: 1px solid var(--line);
1757
+ }
1758
+
1759
+ .car-overview-diagram {
1760
+ grid-template-columns: 1fr;
1761
+ grid-template-rows: repeat(2, auto) 5.3rem repeat(4, auto);
1762
+ }
1763
+
1764
+ .car-overview-diagram::before {
1765
+ background:
1766
+ linear-gradient(var(--arrow-line), var(--arrow-line)) 50% 18% / 1px 16% no-repeat,
1767
+ linear-gradient(var(--arrow-line), var(--arrow-line)) 50% 82% / 1px 16% no-repeat;
1768
+ }
1769
+
1770
+ .car-overview-cell,
1771
+ .car-overview-car {
1772
+ grid-column: 1;
1773
+ justify-self: stretch;
1774
+ width: auto;
1775
+ }
1776
+
1777
+ .car-overview-cell--slot-1 {
1778
+ grid-row: 1;
1779
+ }
1780
+
1781
+ .car-overview-cell--slot-2 {
1782
+ grid-row: 2;
1783
+ }
1784
+
1785
+ .car-overview-car {
1786
+ grid-row: 3;
1787
+ justify-self: center;
1788
+ }
1789
+
1790
+ .car-overview-cell--slot-3 {
1791
+ grid-row: 4;
1792
+ }
1793
+
1794
+ .car-overview-cell--slot-4 {
1795
+ grid-row: 5;
1796
+ }
1797
+
1798
+ .car-overview-cell--slot-5 {
1799
+ grid-row: 6;
1800
+ }
1801
+
1802
+ .car-overview-cell--slot-6 {
1803
+ grid-row: 7;
1804
+ }
1805
+
1806
+ .car-overview-cell--slot-7 {
1807
+ grid-row: 8;
1808
+ display: block;
1809
+ }
1810
+
1811
+ .car-overview-cell--slot-7 strong {
1812
+ text-align: left;
1813
+ }
1814
+
1815
+ .car-overview-cell::after {
1816
+ display: none;
1817
+ }
1818
+ }