{"project":{"id":"NCteVWe","userId":"davidyarham@gmail.com","username":null,"userPicture":null,"name":"Uma Racer","thumbnail":"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","visible":true,"contributors":"","githubRepo":null,"forkedFrom":null,"tags":"","files":{"folder":"","files":[{"name":"index.html","content":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Untitled</title>\n  <link rel=\"stylesheet\" href=\"style.css\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\"></script>\n</head>\n<body>\n<div id=\"game-container\">\n\t<canvas id=\"gameCanvas\"></canvas>\n\t<div id=\"scanlines\"></div>\n\n\t<!-- Title Screen -->\n\t<div id=\"title-screen\" class=\"screen active\">\n\t\t<div class=\"title-content\">\n\t\t\t<div class=\"retro-badge\">★ RACING EDITION ★</div>\n\t\t\t<h1 class=\"game-title\">UMA RACER</h1>\n\t\t\t<p class=\"game-subtitle\">KART RACING</p>\n\t\t\t<div class=\"controls-hint\">USE WASD OR ARROW KEYS</div>\n\t\t\t<div class=\"menu-buttons\">\n\t\t\t\t<button id=\"btn-start\" class=\"menu-btn\">▶ START RACE</button>\n\t\t\t\t<button id=\"btn-controls\" class=\"menu-btn menu-btn--secondary\">⚙ CONTROLS</button>\n\t\t\t</div>\n\t\t\t<div id=\"controls-info\" class=\"controls-info hidden\">\n\t\t\t\t<p><kbd>W</kbd> / <kbd>↑</kbd> Accelerate</p>\n\t\t\t\t<p><kbd>S</kbd> / <kbd>↓</kbd> Brake / Reverse</p>\n\t\t\t\t<p><kbd>A</kbd> / <kbd>←</kbd> Steer Left</p>\n\t\t\t\t<p><kbd>D</kbd> / <kbd>→</kbd> Steer Right</p>\n\t\t\t\t<p><kbd>Space</kbd> Drift / Hop</p>\n\t\t\t\t<p><kbd>Space</kbd> at GO! = Turbo Start!</p>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- Mobile Controls -->\n\t<div id=\"tilt-indicator\" class=\"tilt-indicator hidden\">\n\t\t<span class=\"tilt-indicator__label\">TILT</span>\n\t\t<div class=\"tilt-indicator__bar\">\n\t\t\t<div class=\"tilt-indicator__dot\" id=\"tilt-dot\"></div>\n\t\t</div>\n\t</div>\n\t<div id=\"mobile-controls\" class=\"mobile-controls hidden\">\n\t\t<div class=\"mobile-controls__left\">\n\t\t\t<button class=\"mobile-btn mobile-btn--steer\" data-key=\"KeyA\">◄</button>\n\t\t\t<button class=\"mobile-btn mobile-btn--steer\" data-key=\"KeyD\">►</button>\n\t\t</div>\n\t\t<div class=\"mobile-controls__center\">\n\t\t\t<button class=\"mobile-btn mobile-btn--tilt\" id=\"btn-tilt\">📱<span class=\"mobile-btn__label\">TILT</span></button>\n\t\t</div>\n\t\t<div class=\"mobile-controls__right\">\n\t\t\t<button class=\"mobile-btn mobile-btn--accel\" data-key=\"KeyW\">▲<span class=\"mobile-btn__label\">GAS</span></button>\n\t\t\t<button class=\"mobile-btn mobile-btn--brake\" data-key=\"KeyS\">▼<span class=\"mobile-btn__label\">BRK</span></button>\n\t\t</div>\n\t</div>\n\n\t<!-- HUD -->\n\t<div id=\"hud\" class=\"hud hidden\">\n\t\t<div class=\"hud__top\">\n\t\t\t<button id=\"btn-reset-track\" class=\"hud__reset-btn\" title=\"Reset on Track\">↺ RESET</button>\n\t\t\t<div class=\"hud__position\">\n\t\t\t\t<span id=\"hud-position\">1</span><span class=\"hud__position-suffix\" id=\"hud-suffix\">st</span>\n\t\t\t\t<span class=\"hud__position-label\">/ 6</span>\n\t\t\t</div>\n\t\t\t<div class=\"hud__timer\" id=\"hud-timer\">0:00.0</div>\n\t\t\t<div class=\"hud__lap\">\n\t\t\t\t<span class=\"hud__lap-label\">LAP</span>\n\t\t\t\t<span id=\"hud-lap\">1</span><span class=\"hud__lap-total\"> / 3</span>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"hud__boost-indicator hidden\" id=\"boost-indicator\">⚡ BOOST! ⚡</div>\n\t\t<div class=\"hud__lap-popup hidden\" id=\"lap-popup\">LAP 2</div>\n\t\t<div class=\"hud__turbo-popup hidden\" id=\"turbo-popup\">TURBO START!</div>\n\t\t<div class=\"hud__wrong-way hidden\" id=\"wrong-way\">⚠ WRONG WAY! ⚠</div>\n\t\t<div class=\"hud__bottom\">\n\t\t\t<div class=\"hud__left-panel\">\n\t\t\t\t<div class=\"hud__speed\">\n\t\t\t\t\t<span id=\"hud-speed\">0</span>\n\t\t\t\t\t<span class=\"hud__speed-unit\">km/h</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"hud__speed-bar\">\n\t\t\t\t\t<div class=\"hud__speed-bar-fill\" id=\"speed-bar-fill\"></div>\n\t\t\t\t\t<div class=\"hud__speed-bar-boost\" id=\"speed-bar-boost\"></div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"hud__drift-meter\">\n\t\t\t\t\t<span class=\"hud__drift-label\">DRIFT</span>\n\t\t\t\t\t<div class=\"hud__drift-bar\">\n\t\t\t\t\t\t<div class=\"hud__drift-bar-fill\" id=\"drift-bar-fill\"></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"hud__fuel-meter\">\n\t\t\t\t\t<span class=\"hud__fuel-label\">⛽ FUEL</span>\n\t\t\t\t\t<div class=\"hud__fuel-bar\">\n\t\t\t\t\t\t<div class=\"hud__fuel-bar-fill\" id=\"fuel-bar-fill\"></div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span class=\"hud__fuel-pct\" id=\"fuel-pct\">100%</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"hud__fuel-warning hidden\" id=\"fuel-warning\">⛽ LOW FUEL! ⛽</div>\n\t\t\t\t<div class=\"hud__coins\">\n\t\t\t\t\t<span class=\"hud__coin-icon\">⛽</span>\n\t\t\t\t\t<span id=\"hud-coins\">0</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"hud__minimap\">\n\t\t\t\t<canvas id=\"minimapCanvas\" width=\"150\" height=\"150\"></canvas>\n\t\t\t</div>\n\t\t</div>\n\t\t<div id=\"countdown\" class=\"countdown hidden\"></div>\n\t</div>\n\n\t<!-- Race Complete -->\n\t<div id=\"finish-screen\" class=\"screen\">\n\t\t<div class=\"finish-content\">\n\t\t\t<div class=\"finish-flag\">🏁</div>\n\t\t\t<h2 class=\"finish-title\">FINISH!</h2>\n\t\t\t<div class=\"finish-position\" id=\"finish-position\">1st</div>\n\t\t\t<div class=\"finish-time\" id=\"finish-time\">Time: 0:00.00</div>\n\t\t\t<div class=\"finish-stats\" id=\"finish-stats\"></div>\n\t\t\t<div class=\"finish-buttons\">\n\t\t\t\t<button id=\"btn-restart\" class=\"menu-btn\">▶ RACE AGAIN</button>\n\t\t\t\t<button id=\"btn-menu\" class=\"menu-btn menu-btn--secondary\">⌂ MAIN MENU</button>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n  <script type=\"module\" src=\"main.js\"></script>\n</body>\n</html>"},{"name":"main.js","content":"// ===== SIMPLE RACER - MARIO KART RETRO EDITION (ENHANCED v4) =====\n\nconst {\n\tScene,\n\tPerspectiveCamera,\n\tWebGLRenderer,\n\tMesh,\n\tMeshStandardMaterial,\n\tMeshBasicMaterial,\n\tMeshPhongMaterial,\n\tBoxGeometry,\n\tSphereGeometry,\n\tCylinderGeometry,\n\tPlaneGeometry,\n\tTorusGeometry,\n\tRingGeometry,\n\tCircleGeometry,\n\tConeGeometry,\n\tLatheGeometry,\n\tDirectionalLight,\n\tAmbientLight,\n\tHemisphereLight,\n\tPointLight,\n\tSpotLight,\n\tVector3,\n\tVector2,\n\tColor,\n\tGroup,\n\tFogExp2,\n\tFog,\n\tCatmullRomCurve3,\n\tRepeatWrapping,\n\tMathUtils,\n\tDoubleSide,\n\tAdditiveBlending,\n\tBackSide,\n\tFrontSide,\n\tShape,\n\tExtrudeGeometry\n} = THREE;\n\n// ===== AUDIO =====\nconst AudioCtx = window.AudioContext || window.webkitAudioContext;\nlet audioCtx = null,\n\taudioStarted = false;\n\nfunction ensureAudio() {\n\tif (!audioCtx) audioCtx = new AudioCtx();\n\tif (audioCtx.state === 'suspended') audioCtx.resume();\n\taudioStarted = true;\n}\n\nfunction playTone(f, dur, type = 'square', vol = 0.08) {\n\tif (!audioStarted) return;\n\ttry {\n\t\tconst o = audioCtx.createOscillator(),\n\t\t\tg = audioCtx.createGain();\n\t\to.type = type;\n\t\to.frequency.value = f;\n\t\tg.gain.setValueAtTime(vol, audioCtx.currentTime);\n\t\tg.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + dur);\n\t\to.connect(g);\n\t\tg.connect(audioCtx.destination);\n\t\to.start();\n\t\to.stop(audioCtx.currentTime + dur);\n\t} catch (e) {}\n}\n\nfunction playNoise(dur, vol = 0.03) {\n\tif (!audioStarted) return;\n\ttry {\n\t\tconst bs = Math.floor(audioCtx.sampleRate * dur);\n\t\tconst buf = audioCtx.createBuffer(1, bs, audioCtx.sampleRate);\n\t\tconst d = buf.getChannelData(0);\n\t\tfor (let i = 0; i < bs; i++) d[i] = Math.random() * 2 - 1;\n\t\tconst s = audioCtx.createBufferSource();\n\t\ts.buffer = buf;\n\t\tconst g = audioCtx.createGain();\n\t\tg.gain.setValueAtTime(vol, audioCtx.currentTime);\n\t\tg.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + dur);\n\t\tconst fl = audioCtx.createBiquadFilter();\n\t\tfl.type = 'lowpass';\n\t\tfl.frequency.value = 800;\n\t\ts.connect(fl);\n\t\tfl.connect(g);\n\t\tg.connect(audioCtx.destination);\n\t\ts.start();\n\t} catch (e) {}\n}\n\nfunction playEngine(speed) {\n\tplayTone(55 + Math.abs(speed) * 3.5, 0.06, 'sawtooth', 0.01 + Math.abs(speed) * 0.0003);\n}\n\nfunction playCountBeep(go) {\n\tif (go) {\n\t\tplayTone(880, 0.3, 'square', 0.12);\n\t\tsetTimeout(() => playTone(1320, 0.4, 'square', 0.12), 50);\n\t} else playTone(440, 0.2, 'square', 0.1);\n}\n\nfunction playBoost() {\n\tplayTone(200, 0.1, 'square', 0.12);\n\tsetTimeout(() => playTone(400, 0.1, 'square', 0.1), 40);\n\tsetTimeout(() => playTone(800, 0.15, 'square', 0.08), 80);\n\tplayNoise(0.2, 0.06);\n}\n\nfunction playLap() {\n\t[523, 659, 784, 1047].forEach((n, i) => setTimeout(() => playTone(n, 0.12, 'square', 0.1), i * 70));\n}\n\nfunction playDrift() {\n\tplayNoise(0.06, 0.02);\n}\n\nfunction playFinish() {\n\t[523, 523, 659, 784, 659, 784, 1047, 1047, 1319].forEach((n, i) => setTimeout(() => playTone(n, 0.2, 'square', 0.1), i * 110));\n}\n\nfunction playSelect() {\n\tplayTone(660, 0.08, 'square', 0.1);\n\tsetTimeout(() => playTone(880, 0.1, 'square', 0.08), 50);\n}\n\nfunction playCoin() {\n\tplayTone(988, 0.08, 'square', 0.1);\n\tsetTimeout(() => playTone(1319, 0.1, 'square', 0.08), 60);\n}\n\nfunction playBump() {\n\tplayTone(120, 0.12, 'sawtooth', 0.15);\n\tplayNoise(0.1, 0.08);\n}\n\nfunction playWallHit() {\n\tplayTone(80, 0.15, 'sawtooth', 0.12);\n\tplayNoise(0.15, 0.1);\n}\n\nfunction playTurboStart() {\n\tplayTone(330, 0.08, 'square', 0.12);\n\tsetTimeout(() => playTone(660, 0.08, 'square', 0.1), 50);\n\tsetTimeout(() => playTone(990, 0.1, 'square', 0.1), 100);\n\tsetTimeout(() => playTone(1320, 0.15, 'square', 0.08), 150);\n\tplayNoise(0.3, 0.08);\n}\n\nfunction playDriftBoost() {\n\tplayTone(440, 0.06, 'square', 0.1);\n\tsetTimeout(() => playTone(660, 0.08, 'square', 0.08), 40);\n\tsetTimeout(() => playTone(880, 0.1, 'square', 0.06), 80);\n}\n\nlet engineTimer = 0,\n\tdriftTimer = 0,\n\tbumpCooldown = 0;\n\n// Accelerometer tilt steering\nlet tiltEnabled = false,\n\ttiltGamma = 0,\n\ttiltCalibration = 0,\n\ttiltCalibrated = false;\n\nfunction enableTilt() {\n\tif (typeof DeviceOrientationEvent !== 'undefined' && typeof DeviceOrientationEvent.requestPermission === 'function') {\n\t\t// iOS 13+ requires permission\n\t\tDeviceOrientationEvent.requestPermission().then(response => {\n\t\t\tif (response === 'granted') {\n\t\t\t\tstartTiltListening();\n\t\t\t} else {\n\t\t\t\talert('Permission denied. Tilt steering requires motion sensor access.');\n\t\t\t\ttiltEnabled = false;\n\t\t\t\tupdateTiltUI();\n\t\t\t}\n\t\t}).catch(e => {\n\t\t\tconsole.warn('DeviceOrientation permission error:', e);\n\t\t\ttiltEnabled = false;\n\t\t\tupdateTiltUI();\n\t\t});\n\t} else if ('DeviceOrientationEvent' in window) {\n\t\tstartTiltListening();\n\t} else {\n\t\talert('Tilt steering is not supported on this device.');\n\t\ttiltEnabled = false;\n\t\tupdateTiltUI();\n\t}\n}\n\nfunction startTiltListening() {\n\ttiltEnabled = true;\n\ttiltCalibrated = false;\n\tupdateTiltUI();\n\twindow.addEventListener('deviceorientation', handleTilt, true);\n}\n\nfunction disableTilt() {\n\ttiltEnabled = false;\n\ttiltGamma = 0;\n\ttiltCalibrated = false;\n\tupdateTiltUI();\n\twindow.removeEventListener('deviceorientation', handleTilt, true);\n\tkeys.TiltLeft = false;\n\tkeys.TiltRight = false;\n}\n\nfunction handleTilt(e) {\n\tif (!tiltEnabled) return;\n\tlet gamma = e.gamma || 0; // -90 to 90 (left-right tilt)\n\t// Calibrate on first reading\n\tif (!tiltCalibrated) {\n\t\ttiltCalibration = gamma;\n\t\ttiltCalibrated = true;\n\t}\n\t// Apply calibration offset\n\tgamma -= tiltCalibration;\n\t// Clamp to usable range\n\tgamma = Math.max(-45, Math.min(45, gamma));\n\ttiltGamma = gamma;\n\t// Dead zone of 4 degrees\n\tconst deadZone = 4;\n\tif (Math.abs(gamma) < deadZone) {\n\t\tkeys.TiltLeft = false;\n\t\tkeys.TiltRight = false;\n\t} else {\n\t\tconst steerAmount = (Math.abs(gamma) - deadZone) / (30 - deadZone);\n\t\tif (gamma < -deadZone) {\n\t\t\tkeys.TiltLeft = true;\n\t\t\tkeys.TiltRight = false;\n\t\t\tkeys.TiltStrength = Math.min(1, steerAmount);\n\t\t} else if (gamma > deadZone) {\n\t\t\tkeys.TiltRight = true;\n\t\t\tkeys.TiltLeft = false;\n\t\t\tkeys.TiltStrength = Math.min(1, steerAmount);\n\t\t}\n\t}\n\t// Update tilt indicator\n\tconst dot = document.getElementById('tilt-dot');\n\tif (dot) {\n\t\tconst pct = 50 + (gamma / 45) * 50;\n\t\tdot.style.left = Math.max(5, Math.min(95, pct)) + '%';\n\t}\n}\n\nfunction updateTiltUI() {\n\tconst btn = document.getElementById('btn-tilt');\n\tconst indicator = document.getElementById('tilt-indicator');\n\tif (btn) {\n\t\tif (tiltEnabled) {\n\t\t\tbtn.classList.add('tilt-active');\n\t\t} else {\n\t\t\tbtn.classList.remove('tilt-active');\n\t\t}\n\t}\n\tif (indicator) {\n\t\tif (tiltEnabled && gameState === 'racing') {\n\t\t\tindicator.classList.remove('hidden');\n\t\t} else {\n\t\t\tindicator.classList.add('hidden');\n\t\t}\n\t}\n}\n\nfunction recalibrateTilt() {\n\ttiltCalibrated = false;\n}\n\nconst trackPoints = [\n\tnew Vector3(0, 0, 0), new Vector3(45, 0, -45), new Vector3(100, 0, -70),\n\tnew Vector3(155, 0, -65), new Vector3(195, 1, -30), new Vector3(210, 2, 20),\n\tnew Vector3(200, 3, 75), new Vector3(175, 5, 130), new Vector3(140, 7, 175),\n\tnew Vector3(90, 8, 210), new Vector3(35, 7, 220), new Vector3(-20, 6, 200),\n\tnew Vector3(-65, 5, 165), new Vector3(-95, 3, 120), new Vector3(-115, 2, 70),\n\tnew Vector3(-120, 1, 20), new Vector3(-105, 0, -25), new Vector3(-75, 0, -55),\n\tnew Vector3(-40, 0, -35),\n];\n\nconst TW = 18,\n\tLAPS = 3,\n\tNCPU = 5;\nconst CPU_COL = [0x4488FF, 0xFF8822, 0xBB55DD, 0x22CC88, 0xFF3333];\nconst P_COL = 0xEE3322;\nconst BOOST_T = [0.08, 0.2, 0.33, 0.46, 0.58, 0.72, 0.85, 0.94];\nconst BOOST_STR = 28,\n\tBOOST_DUR = 0.9;\nconst ITEM_T = [0.05, 0.15, 0.28, 0.4, 0.52, 0.65, 0.78, 0.9];\nconst RS = 1.0;\n\nlet scene, camera, renderer;\nlet playerKart, cpuKarts = [],\n\ttrackCurve;\nlet boostMeshes = [],\n\titemMeshes = [];\nlet keys = {},\n\tgameState = 'menu',\n\traceTime = 0,\n\tplayerLap = 1;\nlet playerBoostTimer = 0,\n\tdustParticles = [];\nlet coinCount = 0,\n\tdriftCharge = 0,\n\tfuel = 1.0,\n\tfuelWarning = false;\nlet turboStartWindow = false;\nlet bestLapTime = Infinity,\n\tlapStartTime = 0,\n\tlapTimes = [];\nlet sparkParticles = [],\n\texhaustParticles = [],\n\tspeedLineParticles = [];\nlet wrongWayTimer = 0;\nlet colliders = [],\n\tpipeColliders = [],\n\trailColliders = [];\nlet clouds = [];\nlet sunMesh, sunGlowMesh, waterMesh, skyDome;\nlet sunGlows = [];\n\nconst pp = {\n\tpos: new Vector3(0, 0.5, 0),\n\tvel: new Vector3(),\n\trot: 0,\n\tspeed: 0,\n\tdrift: false,\n\ttrackT: 0,\n\tlap: 1,\n\tprevT: 0,\n\tdone: false,\n\tspinTimer: 0\n};\n\nfunction init() {\n\tscene = new Scene();\n\tscene.background = new Color(0x8DC5E8);\n\tscene.fog = new Fog(0x8DC5E8, 100, 650);\n\tcamera = new PerspectiveCamera(62, innerWidth / innerHeight, 0.5, 800);\n\trenderer = new WebGLRenderer({\n\t\tcanvas: document.getElementById('gameCanvas'),\n\t\tantialias: true,\n\t\tpowerPreference: 'high-performance',\n\t\talpha: false,\n\t\tstencil: false\n\t});\n\tconst dpr = Math.min(window.devicePixelRatio || 1, 2);\n\trenderer.setPixelRatio(dpr);\n\trenderer.setSize(innerWidth, innerHeight, false);\n\trenderer.shadowMap.enabled = true;\n\trenderer.shadowMap.type = THREE.PCFSoftShadowMap;\n\trenderer.toneMapping = THREE.ACESFilmicToneMapping;\n\trenderer.toneMappingExposure = 1.0;\n\trenderer.outputEncoding = THREE.sRGBEncoding;\n\trenderer.gammaFactor = 2.2;\n\trenderer.physicallyCorrectLights = true;\n\tconst c = document.getElementById('gameCanvas');\n\tc.style.width = '100%';\n\tc.style.height = '100%';\n\tc.style.imageRendering = 'auto';\n\n\tsetupLights();\n\tcreateSky();\n\tcreateWater();\n\tcreateTrack();\n\tcreateBoosts();\n\tcreateItemBoxes();\n\tcreateEnvironment();\n\tcreatePlayerKart();\n\tcreateCPUs();\n\tcreateStartArch();\n\tcreateDustSystem();\n\tcreateSparkSystem();\n\tcreateExhaustSystem();\n\tcreateSpeedLines();\n\tsetupInput();\n\tsetupUI();\n\twindow.addEventListener('resize', onResize);\n\tanimate();\n}\n\nfunction setupLights() {\n\tscene.add(new HemisphereLight(0x99CCFF, 0x557744, 0.7));\n\tscene.add(new AmbientLight(0xfff4e0, 0.25));\n\tconst sun = new DirectionalLight(0xFFEACC, 1.6);\n\tsun.position.set(80, 150, 50);\n\tsun.castShadow = true;\n\tsun.shadow.mapSize.set(4096, 4096);\n\tsun.shadow.camera.near = 1;\n\tsun.shadow.camera.far = 600;\n\tsun.shadow.camera.left = -280;\n\tsun.shadow.camera.right = 280;\n\tsun.shadow.camera.top = 280;\n\tsun.shadow.camera.bottom = -280;\n\tsun.shadow.bias = -0.0005;\n\tsun.shadow.normalBias = 0.03;\n\tsun.shadow.radius = 2;\n\tscene.add(sun);\n\tconst rimLight = new DirectionalLight(0xFF9955, 0.35);\n\trimLight.position.set(-60, 40, -80);\n\tscene.add(rimLight);\n\tconst fillLight = new DirectionalLight(0x6688CC, 0.2);\n\tfillLight.position.set(-40, 80, 100);\n\tscene.add(fillLight);\n\tconst bounceLight = new DirectionalLight(0x88AA66, 0.12);\n\tbounceLight.position.set(0, 5, 0);\n\tscene.add(bounceLight);\n}\n\nfunction createSky() {\n\tconst skyGeo = new SphereGeometry(700, 64, 48);\n\tconst skyC = document.createElement('canvas');\n\tskyC.width = 512;\n\tskyC.height = 1024;\n\tconst skx = skyC.getContext('2d');\n\tconst grad = skx.createLinearGradient(0, 0, 0, 1024);\n\tgrad.addColorStop(0, '#0a1833');\n\tgrad.addColorStop(0.08, '#0d2147');\n\tgrad.addColorStop(0.18, '#1a3a6e');\n\tgrad.addColorStop(0.3, '#3070aa');\n\tgrad.addColorStop(0.42, '#5599cc');\n\tgrad.addColorStop(0.55, '#7BBDE5');\n\tgrad.addColorStop(0.65, '#97D1F0');\n\tgrad.addColorStop(0.75, '#B8E0F8');\n\tgrad.addColorStop(0.82, '#D6ECFA');\n\tgrad.addColorStop(0.88, '#FFE8C8');\n\tgrad.addColorStop(0.93, '#FFCC88');\n\tgrad.addColorStop(0.97, '#FFB070');\n\tgrad.addColorStop(1, '#FF8855');\n\tskx.fillStyle = grad;\n\tskx.fillRect(0, 0, 512, 1024);\n\t// Add subtle cloud wisps to sky texture\n\tskx.globalAlpha = 0.04;\n\tfor (let i = 0; i < 20; i++) {\n\t\tconst cy = 400 + Math.random() * 300;\n\t\tconst cx2 = Math.random() * 512;\n\t\tconst rw = 60 + Math.random() * 150;\n\t\tconst rh = 5 + Math.random() * 15;\n\t\tskx.fillStyle = '#ffffff';\n\t\tskx.beginPath();\n\t\tskx.ellipse(cx2, cy, rw, rh, 0, 0, Math.PI * 2);\n\t\tskx.fill();\n\t}\n\tskx.globalAlpha = 1;\n\tconst skyTex = new THREE.CanvasTexture(skyC);\n\tskyTex.magFilter = THREE.LinearFilter;\n\tskyTex.minFilter = THREE.LinearFilter;\n\tskyDome = new Mesh(skyGeo, new MeshBasicMaterial({\n\t\tmap: skyTex,\n\t\tside: BackSide,\n\t\tfog: false\n\t}));\n\tscene.add(skyDome);\n\t// Sun disc\n\tsunMesh = new Mesh(new CircleGeometry(15, 32), new MeshBasicMaterial({\n\t\tcolor: 0xFFEEAA,\n\t\tfog: false\n\t}));\n\tsunMesh.position.set(80, 150, 50);\n\tsunMesh.lookAt(0, 0, 0);\n\tscene.add(sunMesh);\n\t// Multiple glow layers for sun\n\tconst glowSizes = [35, 55, 90];\n\tconst glowOpacities = [0.12, 0.05, 0.02];\n\tconst glowColors = [0xFFEE88, 0xFFDD66, 0xFFCC44];\n\tsunGlows = [];\n\tglowSizes.forEach((s, i) => {\n\t\tconst glow = new Mesh(new CircleGeometry(s, 32), new MeshBasicMaterial({\n\t\t\tcolor: glowColors[i],\n\t\t\ttransparent: true,\n\t\t\topacity: glowOpacities[i],\n\t\t\tfog: false,\n\t\t\tblending: AdditiveBlending,\n\t\t\tdepthWrite: false\n\t\t}));\n\t\tglow.position.copy(sunMesh.position);\n\t\tglow.lookAt(0, 0, 0);\n\t\tscene.add(glow);\n\t\tsunGlows.push(glow);\n\t\tif (i === 0) sunGlowMesh = glow;\n\t});\n}\n\nfunction createWater() {\n\tconst wC = document.createElement('canvas');\n\twC.width = 256;\n\twC.height = 256;\n\tconst wx = wC.getContext('2d');\n\t// Create a more detailed water texture with caustics pattern\n\twx.fillStyle = '#1a5588';\n\twx.fillRect(0, 0, 256, 256);\n\tfor (let y = 0; y < 256; y++) {\n\t\tfor (let x = 0; x < 256; x++) {\n\t\t\tconst v1 = Math.sin(x * 0.05) * Math.cos(y * 0.05) * 0.5 + 0.5;\n\t\t\tconst v2 = Math.sin((x + y) * 0.03) * 0.5 + 0.5;\n\t\t\tconst v = (v1 + v2) * 0.5;\n\t\t\tconst r = Math.floor(20 + v * 40);\n\t\t\tconst g = Math.floor(80 + v * 70);\n\t\t\tconst b2 = Math.floor(140 + v * 60);\n\t\t\twx.fillStyle = `rgb(${r},${g},${b2})`;\n\t\t\twx.fillRect(x, y, 1, 1);\n\t\t}\n\t}\n\tconst wTex = new THREE.CanvasTexture(wC);\n\twTex.wrapS = wTex.wrapT = RepeatWrapping;\n\twTex.repeat.set(25, 25);\n\twTex.magFilter = THREE.LinearFilter;\n\twTex.minFilter = THREE.LinearMipmapLinearFilter;\n\twaterMesh = new Mesh(new PlaneGeometry(1000, 1000, 80, 80), new MeshStandardMaterial({\n\t\tmap: wTex,\n\t\troughness: 0.05,\n\t\tmetalness: 0.65,\n\t\tcolor: 0x4499CC,\n\t\ttransparent: true,\n\t\topacity: 0.92,\n\t\tflatShading: false,\n\t\tenvMapIntensity: 1.5\n\t}));\n\twaterMesh.rotation.x = -Math.PI / 2;\n\twaterMesh.position.y = -3;\n\twaterMesh.receiveShadow = true;\n\tscene.add(waterMesh);\n}\n\nfunction createTrack() {\n\ttrackCurve = new CatmullRomCurve3(trackPoints, true, 'catmullrom', 0.5);\n\tconst seg = 400,\n\t\tverts = [],\n\t\tidx = [],\n\t\tuvs = [];\n\tfor (let i = 0; i <= seg; i++) {\n\t\tconst t = i / seg,\n\t\t\tp = trackCurve.getPoint(t),\n\t\t\ttan = trackCurve.getTangent(t).normalize();\n\t\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t\tconst L = p.clone().add(r.clone().multiplyScalar(-TW / 2));\n\t\tconst R = p.clone().add(r.clone().multiplyScalar(TW / 2));\n\t\tverts.push(L.x, L.y + 0.05, L.z, R.x, R.y + 0.05, R.z);\n\t\tuvs.push(0, t * 20, 1, t * 20);\n\t\tif (i < seg) {\n\t\t\tconst b = i * 2;\n\t\t\tidx.push(b, b + 1, b + 2, b + 1, b + 3, b + 2);\n\t\t}\n\t}\n\tconst geo = new THREE.BufferGeometry();\n\tgeo.setAttribute('position', new THREE.Float32BufferAttribute(verts, 3));\n\tgeo.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));\n\tgeo.setIndex(idx);\n\tgeo.computeVertexNormals();\n\tconst tc = document.createElement('canvas');\n\ttc.width = 256;\n\ttc.height = 512;\n\tconst tx = tc.getContext('2d');\n\ttx.imageSmoothingEnabled = true;\n\t// High quality asphalt base\n\tfor (let y = 0; y < 512; y++) {\n\t\tfor (let x = 0; x < 256; x++) {\n\t\t\tconst noise = (Math.random() - 0.5) * 12;\n\t\t\tconst base = 82;\n\t\t\tconst edgeFade = Math.min(x, 255 - x) / 30;\n\t\t\tconst ef = Math.min(1, edgeFade);\n\t\t\tconst v = Math.floor(base + noise + (1 - ef) * 10);\n\t\t\ttx.fillStyle = `rgb(${v},${v},${v+2})`;\n\t\t\ttx.fillRect(x, y, 1, 1);\n\t\t}\n\t}\n\t// Center dashed line\n\ttx.fillStyle = '#DDBB22';\n\tfor (let y = 0; y < 512; y += 48) {\n\t\ttx.beginPath();\n\t\ttx.roundRect ? tx.roundRect(122, y, 12, 30, 3) : tx.fillRect(122, y, 12, 30);\n\t\ttx.fill();\n\t}\n\t// Edge lines with anti-aliasing\n\ttx.fillStyle = '#E8E8E8';\n\ttx.fillRect(2, 0, 8, 512);\n\ttx.fillRect(246, 0, 8, 512);\n\t// Subtle tire marks\n\ttx.globalAlpha = 0.03;\n\ttx.fillStyle = '#222';\n\tfor (let y = 0; y < 512; y += 3) {\n\t\ttx.fillRect(60 + Math.sin(y * 0.02) * 5, y, 14, 2);\n\t\ttx.fillRect(175 + Math.sin(y * 0.015 + 1) * 5, y, 14, 2);\n\t}\n\ttx.globalAlpha = 1;\n\t// Subtle edge gradient shadows\n\tconst edgeGrad = tx.createLinearGradient(0, 0, 30, 0);\n\tedgeGrad.addColorStop(0, 'rgba(0,0,0,0.12)');\n\tedgeGrad.addColorStop(1, 'rgba(0,0,0,0)');\n\ttx.fillStyle = edgeGrad;\n\ttx.fillRect(0, 0, 30, 512);\n\tconst edgeGrad2 = tx.createLinearGradient(226, 0, 256, 0);\n\tedgeGrad2.addColorStop(0, 'rgba(0,0,0,0)');\n\tedgeGrad2.addColorStop(1, 'rgba(0,0,0,0.12)');\n\ttx.fillStyle = edgeGrad2;\n\ttx.fillRect(226, 0, 30, 512);\n\tconst tex = new THREE.CanvasTexture(tc);\n\ttex.wrapS = tex.wrapT = RepeatWrapping;\n\ttex.magFilter = THREE.LinearFilter;\n\ttex.minFilter = THREE.LinearMipmapLinearFilter;\n\ttex.anisotropy = Math.min(renderer.capabilities.getMaxAnisotropy(), 16);\n\tconst mesh = new Mesh(geo, new MeshStandardMaterial({\n\t\tmap: tex,\n\t\troughness: 0.75,\n\t\tmetalness: 0.05,\n\t\tflatShading: false\n\t}));\n\tmesh.receiveShadow = true;\n\tscene.add(mesh);\n\tcreateBorders(seg);\n\tcreateStartLine();\n\tcreateGuardrails(seg);\n}\n\nfunction createGuardrails(seg) {\n\tfor (let side = -1; side <= 1; side += 2) {\n\t\tfor (let i = 0; i < seg; i += 4) {\n\t\t\tconst t = i / seg,\n\t\t\t\tp = trackCurve.getPoint(t),\n\t\t\t\ttan = trackCurve.getTangent(t).normalize();\n\t\t\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t\t\tconst pos = p.clone().add(r.clone().multiplyScalar(side * (TW / 2 + 2)));\n\t\t\t// Post\n\t\t\tconst post = new Mesh(new CylinderGeometry(0.12, 0.12, 1.5, 8), new MeshStandardMaterial({\n\t\t\t\tcolor: 0xCCCCCC,\n\t\t\t\tmetalness: 0.5,\n\t\t\t\troughness: 0.35,\n\t\t\t\tflatShading: false\n\t\t\t}));\n\t\t\tpost.position.copy(pos);\n\t\t\tpost.position.y += 0.75;\n\t\t\tpost.castShadow = true;\n\t\t\tscene.add(post);\n\t\t\t// Add collision for rail post\n\t\t\trailColliders.push({\n\t\t\t\tpos: new Vector3(pos.x, 0, pos.z),\n\t\t\t\tradius: 0.4\n\t\t\t});\n\t\t}\n\t\t// Rails (horizontal bars connecting posts)\n\t\tconst railVerts = [],\n\t\t\trailIdx = [];\n\t\tfor (let i = 0; i <= seg; i += 2) {\n\t\t\tconst t = i / seg,\n\t\t\t\tp = trackCurve.getPoint(t),\n\t\t\t\ttan = trackCurve.getTangent(t).normalize();\n\t\t\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t\t\tconst pos = p.clone().add(r.clone().multiplyScalar(side * (TW / 2 + 2)));\n\t\t\trailVerts.push(pos.x, pos.y + 1.3, pos.z, pos.x, pos.y + 1.5, pos.z);\n\t\t\tif (i < seg) {\n\t\t\t\tconst b = (i / 2) * 2;\n\t\t\t\trailIdx.push(b, b + 1, b + 2, b + 1, b + 3, b + 2);\n\t\t\t}\n\t\t}\n\t\tconst rg = new THREE.BufferGeometry();\n\t\trg.setAttribute('position', new THREE.Float32BufferAttribute(railVerts, 3));\n\t\trg.setIndex(railIdx);\n\t\trg.computeVertexNormals();\n\t\tconst rm = new Mesh(rg, new MeshStandardMaterial({\n\t\t\tcolor: 0xDDDDDD,\n\t\t\tmetalness: 0.5,\n\t\t\troughness: 0.3,\n\t\t\tflatShading: false,\n\t\t\tside: DoubleSide\n\t\t}));\n\t\tscene.add(rm);\n\t}\n}\n\nfunction createBorders(seg) {\n\tfor (let side = -1; side <= 1; side += 2) {\n\t\tconst v = [],\n\t\t\tidx = [],\n\t\t\tcols = [];\n\t\tfor (let i = 0; i <= seg; i++) {\n\t\t\tconst t = i / seg,\n\t\t\t\tp = trackCurve.getPoint(t),\n\t\t\t\ttan = trackCurve.getTangent(t).normalize();\n\t\t\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t\t\tconst inner = p.clone().add(r.clone().multiplyScalar(side * TW / 2));\n\t\t\tconst outer = p.clone().add(r.clone().multiplyScalar(side * (TW / 2 + 1.8)));\n\t\t\tv.push(inner.x, inner.y + 0.1, inner.z, outer.x, outer.y + 0.5, outer.z);\n\t\t\tconst c = Math.floor(i / 3) % 2 === 0 ? [1, 0.1, 0.05] : [1, 1, 1];\n\t\t\tcols.push(...c, ...c);\n\t\t\tif (i < seg) {\n\t\t\t\tconst b = i * 2;\n\t\t\t\tidx.push(b, b + 1, b + 2, b + 1, b + 3, b + 2);\n\t\t\t}\n\t\t}\n\t\tconst g = new THREE.BufferGeometry();\n\t\tg.setAttribute('position', new THREE.Float32BufferAttribute(v, 3));\n\t\tg.setAttribute('color', new THREE.Float32BufferAttribute(cols, 3));\n\t\tg.setIndex(idx);\n\t\tg.computeVertexNormals();\n\t\tscene.add(new Mesh(g, new MeshStandardMaterial({\n\t\t\tvertexColors: true,\n\t\t\troughness: 0.7,\n\t\t\tflatShading: true\n\t\t})));\n\t}\n\tpipeColliders = [];\n\tfor (let i = 0; i < 30; i++) {\n\t\tconst t = (i / 40 + 0.005) % 1;\n\t\tconst p = trackCurve.getPoint(t),\n\t\t\ttan = trackCurve.getTangent(t).normalize();\n\t\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t\tconst side = i % 2 === 0 ? 1 : -1;\n\t\tconst pos = p.clone().add(r.clone().multiplyScalar(side * (TW / 2 + 3.5)));\n\t\t// Mario-style green pipe\n\t\tconst pipe = new Mesh(new CylinderGeometry(0.7, 0.7, 2.2, 16), new MeshStandardMaterial({\n\t\t\tcolor: 0x228822,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.2,\n\t\t\troughness: 0.4\n\t\t}));\n\t\tpipe.position.copy(pos);\n\t\tpipe.position.y += 1.1;\n\t\tpipe.castShadow = true;\n\t\tscene.add(pipe);\n\t\t// Pipe rim (wider ring at top)\n\t\tconst rim = new Mesh(new CylinderGeometry(0.85, 0.85, 0.35, 16), new MeshStandardMaterial({\n\t\t\tcolor: 0x22AA22,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.25,\n\t\t\troughness: 0.35\n\t\t}));\n\t\trim.position.copy(pos);\n\t\trim.position.y += 2.35;\n\t\tscene.add(rim);\n\t\t// Pipe inner dark\n\t\tconst inner = new Mesh(new CylinderGeometry(0.55, 0.55, 0.1, 12), new MeshStandardMaterial({\n\t\t\tcolor: 0x111111,\n\t\t\tflatShading: false\n\t\t}));\n\t\tinner.position.copy(pos);\n\t\tinner.position.y += 2.52;\n\t\tscene.add(inner);\n\t\t// Highlight ring\n\t\tconst highlight = new Mesh(new CylinderGeometry(0.72, 0.72, 0.08, 16), new MeshStandardMaterial({\n\t\t\tcolor: 0x44DD44,\n\t\t\tflatShading: false,\n\t\t\temissive: 0x22AA22,\n\t\t\temissiveIntensity: 0.08\n\t\t}));\n\t\thighlight.position.copy(pos);\n\t\thighlight.position.y += 2.15;\n\t\tscene.add(highlight);\n\t\tpipeColliders.push({\n\t\t\tpos: new Vector3(pos.x, 0, pos.z),\n\t\t\tradius: 1.3\n\t\t});\n\t}\n}\n\nfunction createStartLine() {\n\tconst p = trackCurve.getPoint(0),\n\t\ttan = trackCurve.getTangent(0).normalize();\n\tconst slC = document.createElement('canvas');\n\tslC.width = 32;\n\tslC.height = 8;\n\tconst slx = slC.getContext('2d');\n\tslx.imageSmoothingEnabled = false;\n\tfor (let y = 0; y < 8; y += 2)\n\t\tfor (let x = 0; x < 32; x += 2) {\n\t\t\tslx.fillStyle = (x / 2 + y / 2) % 2 === 0 ? '#111' : '#fff';\n\t\t\tslx.fillRect(x, y, 2, 2);\n\t\t}\n\tconst slT = new THREE.CanvasTexture(slC);\n\tslT.magFilter = THREE.LinearFilter;\n\tslT.minFilter = THREE.LinearMipmapLinearFilter;\n\tconst sl = new Mesh(new PlaneGeometry(TW + 2, 3), new MeshStandardMaterial({\n\t\tmap: slT,\n\t\tflatShading: true\n\t}));\n\tsl.rotation.x = -Math.PI / 2;\n\tsl.position.copy(p);\n\tsl.position.y += 0.08;\n\tsl.lookAt(p.clone().add(new Vector3(0, 100, 0)));\n\tsl.rotation.z = Math.atan2(tan.x, tan.z);\n\tscene.add(sl);\n}\n\nfunction createStartArch() {\n\tconst p = trackCurve.getPoint(0),\n\t\ttan = trackCurve.getTangent(0).normalize();\n\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t// Main arch beam\n\tconst archG = new BoxGeometry(TW + 6, 1.5, 1.5, 2, 1, 1);\n\tconst arch = new Mesh(archG, new MeshStandardMaterial({\n\t\tcolor: 0xDD0000,\n\t\tflatShading: false,\n\t\tmetalness: 0.4,\n\t\troughness: 0.25\n\t}));\n\tarch.position.copy(p);\n\tarch.position.y += 8;\n\tarch.lookAt(p.clone().add(tan));\n\tscene.add(arch);\n\t// \"FINISH\" sign on arch\n\tconst signG = new BoxGeometry(TW - 2, 2, 0.3);\n\tconst signC = document.createElement('canvas');\n\tsignC.width = 128;\n\tsignC.height = 32;\n\tconst signCtx = signC.getContext('2d');\n\tsignCtx.fillStyle = '#222';\n\tsignCtx.fillRect(0, 0, 128, 32);\n\tsignCtx.fillStyle = '#fff';\n\tsignCtx.font = 'bold 20px monospace';\n\tsignCtx.textAlign = 'center';\n\tsignCtx.fillText('★ START / FINISH ★', 64, 22);\n\tconst signTex = new THREE.CanvasTexture(signC);\n\tsignTex.magFilter = THREE.LinearFilter;\n\tconst sign = new Mesh(signG, new MeshStandardMaterial({\n\t\tmap: signTex,\n\t\tflatShading: true\n\t}));\n\tsign.position.copy(p);\n\tsign.position.y += 6;\n\tsign.lookAt(p.clone().add(tan));\n\tscene.add(sign);\n\t// Poles\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\tconst poleG = new CylinderGeometry(0.4, 0.5, 10, 12);\n\t\tconst pole = new Mesh(poleG, new MeshStandardMaterial({\n\t\t\tcolor: 0xDDDDDD,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.6,\n\t\t\troughness: 0.2\n\t\t}));\n\t\tpole.position.copy(p).add(r.clone().multiplyScalar(s * (TW / 2 + 3)));\n\t\tpole.position.y += 5;\n\t\tpole.castShadow = true;\n\t\tscene.add(pole);\n\t\t// Flag sphere on top\n\t\tconst ball = new Mesh(new SphereGeometry(0.6, 10, 8), new MeshStandardMaterial({\n\t\t\tcolor: s === -1 ? 0xFF0000 : 0x0000FF,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.3,\n\t\t\troughness: 0.3\n\t\t}));\n\t\tball.position.copy(pole.position);\n\t\tball.position.y += 5.3;\n\t\tscene.add(ball);\n\t}\n\t// Checkered flags hanging\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\tconst flagC = document.createElement('canvas');\n\t\tflagC.width = 16;\n\t\tflagC.height = 16;\n\t\tconst fctx = flagC.getContext('2d');\n\t\tfor (let y = 0; y < 16; y += 4)\n\t\t\tfor (let x = 0; x < 16; x += 4) {\n\t\t\t\tfctx.fillStyle = (x / 4 + y / 4) % 2 === 0 ? '#111' : '#fff';\n\t\t\t\tfctx.fillRect(x, y, 4, 4);\n\t\t\t}\n\t\tconst flagTex = new THREE.CanvasTexture(flagC);\n\t\tflagTex.magFilter = THREE.LinearFilter;\n\t\tconst flag = new Mesh(new PlaneGeometry(1.5, 2), new MeshStandardMaterial({\n\t\t\tmap: flagTex,\n\t\t\tside: DoubleSide,\n\t\t\tflatShading: true\n\t\t}));\n\t\tflag.position.copy(p).add(r.clone().multiplyScalar(s * (TW / 2 + 3)));\n\t\tflag.position.y += 9;\n\t\tflag.lookAt(p.clone().add(tan));\n\t\tscene.add(flag);\n\t}\n}\n\nfunction createBoosts() {\n\tboostMeshes = [];\n\tBOOST_T.forEach(t => {\n\t\tconst p = trackCurve.getPoint(t),\n\t\t\ttan = trackCurve.getTangent(t).normalize();\n\t\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t\tconst a = Math.atan2(tan.x, tan.z);\n\t\t// Boost pad with arrows texture\n\t\tconst padC = document.createElement('canvas');\n\t\tpadC.width = 32;\n\t\tpadC.height = 48;\n\t\tconst px = padC.getContext('2d');\n\t\tpx.fillStyle = '#CC4400';\n\t\tpx.fillRect(0, 0, 32, 48);\n\t\tpx.fillStyle = '#FF8800';\n\t\tfor (let i = 0; i < 3; i++) {\n\t\t\tpx.beginPath();\n\t\t\tpx.moveTo(16, 4 + i * 16);\n\t\t\tpx.lineTo(8, 12 + i * 16);\n\t\t\tpx.lineTo(24, 12 + i * 16);\n\t\t\tpx.fill();\n\t\t}\n\t\tpx.fillStyle = '#FFCC00';\n\t\tpx.fillRect(0, 0, 2, 48);\n\t\tpx.fillRect(30, 0, 2, 48);\n\t\tconst padTex = new THREE.CanvasTexture(padC);\n\t\tpadTex.magFilter = THREE.LinearFilter;\n\t\tconst pad = new Mesh(new BoxGeometry(5, 0.15, 8), new MeshStandardMaterial({\n\t\t\tmap: padTex,\n\t\t\temissive: 0xFF4400,\n\t\t\temissiveIntensity: 0.4,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.35,\n\t\t\troughness: 0.3\n\t\t}));\n\t\tpad.position.copy(p);\n\t\tpad.position.y += 0.12;\n\t\tpad.rotation.y = a;\n\t\tscene.add(pad);\n\t\tboostMeshes.push(pad);\n\t\tfor (let s = -1; s <= 1; s += 2) {\n\t\t\tconst marker = new Mesh(new CylinderGeometry(0.3, 0.3, 2.5, 10), new MeshStandardMaterial({\n\t\t\t\tcolor: 0xFF8800,\n\t\t\t\tflatShading: false,\n\t\t\t\temissive: 0xFF4400,\n\t\t\t\temissiveIntensity: 0.15,\n\t\t\t\tmetalness: 0.3,\n\t\t\t\troughness: 0.3\n\t\t\t}));\n\t\t\tmarker.position.copy(p).add(r.clone().multiplyScalar(s * 4));\n\t\t\tmarker.position.y += 1.25;\n\t\t\tmarker.castShadow = true;\n\t\t\tscene.add(marker);\n\t\t\tconst top = new Mesh(new SphereGeometry(0.4, 8, 6), new MeshStandardMaterial({\n\t\t\t\tcolor: 0xFFCC00,\n\t\t\t\tflatShading: false,\n\t\t\t\temissive: 0xFF8800,\n\t\t\t\temissiveIntensity: 0.08\n\t\t\t}));\n\t\t\ttop.position.copy(marker.position);\n\t\t\ttop.position.y += 1.35;\n\t\t\tscene.add(top);\n\t\t}\n\t});\n}\n\nfunction checkBoosts(dt) {\n\tif (playerBoostTimer > 0) {\n\t\tplayerBoostTimer -= dt;\n\t\treturn;\n\t}\n\tBOOST_T.forEach((bt, i) => {\n\t\tconst bp = trackCurve.getPoint(bt);\n\t\tconst d = new Vector3(pp.pos.x, 0, pp.pos.z).distanceTo(new Vector3(bp.x, 0, bp.z));\n\t\tif (d < 5) {\n\t\t\tpp.speed += BOOST_STR;\n\t\t\tplayerBoostTimer = BOOST_DUR;\n\t\t\tplayBoost();\n\t\t\tif (boostMeshes[i]) {\n\t\t\t\tboostMeshes[i].material.emissiveIntensity = 1.5;\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (boostMeshes[i]) boostMeshes[i].material.emissiveIntensity = 0.3;\n\t\t\t\t}, 300);\n\t\t\t}\n\t\t\tconst bi = document.getElementById('boost-indicator');\n\t\t\tbi.classList.remove('hidden');\n\t\t\tsetTimeout(() => bi.classList.add('hidden'), 600);\n\t\t\tfor (let j = 0; j < 8; j++) spawnSpark(pp.pos.clone(), 0xFF6600);\n\t\t\tshakeCamera(0.15);\n\t\t}\n\t});\n}\n\nfunction createItemBoxes() {\n\titemMeshes = [];\n\tITEM_T.forEach(t => {\n\t\tconst p = trackCurve.getPoint(t);\n\t\tconst can = new Group();\n\t\t// Main canister body\n\t\tconst bodyGeo = new BoxGeometry(1.0, 1.5, 0.6, 2, 2, 1);\n\t\tconst canM = new MeshStandardMaterial({\n\t\t\tcolor: 0xCC2200,\n\t\t\troughness: 0.3,\n\t\t\tmetalness: 0.5,\n\t\t\tflatShading: false,\n\t\t\temissive: 0xFF2200,\n\t\t\temissiveIntensity: 0.08\n\t\t});\n\t\tconst body = new Mesh(bodyGeo, canM);\n\t\tcan.add(body);\n\t\t// Label on canister\n\t\tconst lblC = document.createElement('canvas');\n\t\tlblC.width = 64;\n\t\tlblC.height = 64;\n\t\tconst lx = lblC.getContext('2d');\n\t\tlx.fillStyle = '#CC2200';\n\t\tlx.fillRect(0, 0, 64, 64);\n\t\tlx.fillStyle = '#FFD700';\n\t\tlx.fillRect(4, 20, 56, 24);\n\t\tlx.fillStyle = '#111';\n\t\tlx.font = 'bold 14px sans-serif';\n\t\tlx.textAlign = 'center';\n\t\tlx.fillText('FUEL', 32, 37);\n\t\tlx.font = 'bold 10px sans-serif';\n\t\tlx.fillText('⛽', 32, 55);\n\t\tconst lblTex = new THREE.CanvasTexture(lblC);\n\t\tlblTex.magFilter = THREE.LinearFilter;\n\t\tconst labelF = new Mesh(new PlaneGeometry(0.9, 0.9), new MeshStandardMaterial({\n\t\t\tmap: lblTex,\n\t\t\tflatShading: false,\n\t\t\troughness: 0.4\n\t\t}));\n\t\tlabelF.position.set(0, 0, 0.31);\n\t\tcan.add(labelF);\n\t\tconst labelB = labelF.clone();\n\t\tlabelB.position.set(0, 0, -0.31);\n\t\tlabelB.rotation.y = Math.PI;\n\t\tcan.add(labelB);\n\t\t// Cap / nozzle on top\n\t\tconst capGeo = new CylinderGeometry(0.12, 0.12, 0.3, 8);\n\t\tconst capM = new MeshStandardMaterial({\n\t\t\tcolor: 0x333333,\n\t\t\tmetalness: 0.7,\n\t\t\troughness: 0.15,\n\t\t\tflatShading: false\n\t\t});\n\t\tconst cap = new Mesh(capGeo, capM);\n\t\tcap.position.set(0.25, 0.9, 0);\n\t\tcan.add(cap);\n\t\t// Nozzle\n\t\tconst nozzle = new Mesh(new CylinderGeometry(0.06, 0.08, 0.35, 6), capM);\n\t\tnozzle.position.set(0.25, 1.15, 0);\n\t\tnozzle.rotation.z = 0.3;\n\t\tcan.add(nozzle);\n\t\t// Handle\n\t\tconst handleM = new MeshStandardMaterial({\n\t\t\tcolor: 0x444444,\n\t\t\tmetalness: 0.6,\n\t\t\troughness: 0.2,\n\t\t\tflatShading: false\n\t\t});\n\t\tconst handle = new Mesh(new BoxGeometry(0.6, 0.08, 0.12), handleM);\n\t\thandle.position.set(0, 0.82, 0);\n\t\tcan.add(handle);\n\t\t// Metal strips on canister\n\t\tconst stripM = new MeshStandardMaterial({\n\t\t\tcolor: 0x888888,\n\t\t\tmetalness: 0.7,\n\t\t\troughness: 0.15,\n\t\t\tflatShading: false\n\t\t});\n\t\t[-0.5, 0, 0.5].forEach(yy => {\n\t\t\tconst strip = new Mesh(new BoxGeometry(1.02, 0.06, 0.62), stripM);\n\t\t\tstrip.position.set(0, yy, 0);\n\t\t\tcan.add(strip);\n\t\t});\n\t\t// Glow indicator\n\t\tconst glowRing = new Mesh(new TorusGeometry(1.0, 0.04, 8, 24), new MeshBasicMaterial({\n\t\t\tcolor: 0xFF6600,\n\t\t\ttransparent: true,\n\t\t\topacity: 0.25,\n\t\t\tblending: AdditiveBlending,\n\t\t\tdepthWrite: false\n\t\t}));\n\t\tglowRing.rotation.x = Math.PI / 2;\n\t\tglowRing.position.y = -0.5;\n\t\tcan.add(glowRing);\n\t\tcan.position.copy(p);\n\t\tcan.position.y += 2.0;\n\t\tcan.userData = {\n\t\t\ttrackT: t,\n\t\t\tactive: true,\n\t\t\trespawnTime: 0\n\t\t};\n\t\tscene.add(can);\n\t\titemMeshes.push(can);\n\t});\n}\n\nfunction checkItemBoxes(dt) {\n\titemMeshes.forEach(box => {\n\t\tif (!box.userData.active) {\n\t\t\tbox.userData.respawnTime -= dt;\n\t\t\tif (box.userData.respawnTime <= 0) {\n\t\t\t\tbox.userData.active = true;\n\t\t\t\tbox.visible = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (pp.pos.distanceTo(box.position) < 3.5) {\n\t\t\tbox.userData.active = false;\n\t\t\tbox.visible = false;\n\t\t\tbox.userData.respawnTime = 10;\n\t\t\tplayCoin();\n\t\t\tcoinCount++;\n\t\t\t// Refuel!\n\t\t\tconst prevFuel = fuel;\n\t\t\tfuel = Math.min(1, fuel + 0.3);\n\t\t\tpp.speed += 3;\n\t\t\tfor (let i = 0; i < 10; i++) spawnSpark(box.position.clone(), 0xFF6600);\n\t\t\tfor (let i = 0; i < 5; i++) spawnSpark(box.position.clone(), 0xFFCC00);\n\t\t\t// Show refuel popup\n\t\t\tconst bi = document.getElementById('boost-indicator');\n\t\t\tbi.textContent = '⛽ +' + Math.round((fuel - prevFuel) * 100) + '% FUEL';\n\t\t\tbi.style.color = '#FF8844';\n\t\t\tbi.classList.remove('hidden');\n\t\t\tsetTimeout(() => {\n\t\t\t\tbi.classList.add('hidden');\n\t\t\t\tbi.style.color = '';\n\t\t\t\tbi.textContent = '⚡ BOOST! ⚡';\n\t\t\t}, 800);\n\t\t\tshakeCamera(0.1);\n\t\t\tif (fuelWarning && fuel > 0.15) {\n\t\t\t\tfuelWarning = false;\n\t\t\t\tdocument.getElementById('fuel-warning').classList.add('hidden');\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction checkCollisions(dt) {\n\tif (pp.spinTimer > 0) return;\n\tbumpCooldown -= dt;\n\tconst p2D = new Vector3(pp.pos.x, 0, pp.pos.z),\n\t\tpR = 1.2;\n\tcpuKarts.forEach(cpu => {\n\t\tif (cpu.done) return;\n\t\tconst cp = new Vector3(cpu.mesh.position.x, 0, cpu.mesh.position.z),\n\t\t\tdist = p2D.distanceTo(cp),\n\t\t\tmD = pR + 1.2;\n\t\tif (dist < mD && dist > 0.01) {\n\t\t\tconst push = new Vector3().subVectors(p2D, cp).normalize(),\n\t\t\t\tol = mD - dist;\n\t\t\tpp.pos.x += push.x * ol * 0.7;\n\t\t\tpp.pos.z += push.z * ol * 0.7;\n\t\t\tconst rs = Math.abs(pp.speed) + Math.abs(cpu.speed);\n\t\t\tpp.speed *= -0.3;\n\t\t\tpp.speed += push.x * Math.sin(pp.rot) * 5 + push.z * Math.cos(pp.rot) * 5;\n\t\t\tcpu.mesh.position.x -= push.x * ol * 0.3;\n\t\t\tcpu.mesh.position.z -= push.z * ol * 0.3;\n\t\t\tcpu.speed *= 0.85;\n\t\t\tif (rs > 25) {\n\t\t\t\tpp.spinTimer = 0.8;\n\t\t\t\tpp.speed *= 0.3;\n\t\t\t}\n\t\t\tif (bumpCooldown <= 0) {\n\t\t\t\tplayBump();\n\t\t\t\tbumpCooldown = 0.3;\n\t\t\t}\n\t\t\tfor (let i = 0; i < 3; i++) spawnDust();\n\t\t\tfor (let i = 0; i < 6; i++) spawnSpark(pp.pos.clone(), 0xFFAA00);\n\t\t\tshakeCamera(0.3);\n\t\t}\n\t});\n\tpipeColliders.forEach(pipe => {\n\t\tconst dist = p2D.distanceTo(pipe.pos),\n\t\t\tmD = pR + pipe.radius;\n\t\tif (dist < mD && dist > 0.01) {\n\t\t\tconst push = new Vector3().subVectors(p2D, pipe.pos).normalize(),\n\t\t\t\tol = mD - dist;\n\t\t\tpp.pos.x += push.x * ol;\n\t\t\tpp.pos.z += push.z * ol;\n\t\t\tpp.speed *= -0.25;\n\t\t\tpp.speed = MathUtils.clamp(pp.speed, -15, 60);\n\t\t\tif (Math.abs(pp.speed) > 10) pp.spinTimer = 0.4;\n\t\t\tif (bumpCooldown <= 0) {\n\t\t\t\tplayWallHit();\n\t\t\t\tbumpCooldown = 0.3;\n\t\t\t}\n\t\t\tfor (let i = 0; i < 2; i++) spawnDust();\n\t\t\tshakeCamera(0.2);\n\t\t}\n\t});\n\tcolliders.forEach(col => {\n\t\tconst dist = p2D.distanceTo(col.pos),\n\t\t\tmD = pR + col.radius;\n\t\tif (dist < mD && dist > 0.01) {\n\t\t\tconst push = new Vector3().subVectors(p2D, col.pos).normalize(),\n\t\t\t\tol = mD - dist;\n\t\t\tpp.pos.x += push.x * ol;\n\t\t\tpp.pos.z += push.z * ol;\n\t\t\tpp.speed *= -0.2;\n\t\t\tif (Math.abs(pp.speed) > 15) pp.spinTimer = 0.5;\n\t\t\tif (bumpCooldown <= 0) {\n\t\t\t\tplayWallHit();\n\t\t\t\tbumpCooldown = 0.3;\n\t\t\t}\n\t\t\tfor (let i = 0; i < 2; i++) spawnDust();\n\t\t\tshakeCamera(0.15);\n\t\t}\n\t});\n\trailColliders.forEach(rail => {\n\t\tconst dist = p2D.distanceTo(rail.pos),\n\t\t\tmD = pR + rail.radius;\n\t\tif (dist < mD && dist > 0.01) {\n\t\t\tconst push = new Vector3().subVectors(p2D, rail.pos).normalize(),\n\t\t\t\tol = mD - dist;\n\t\t\tpp.pos.x += push.x * ol;\n\t\t\tpp.pos.z += push.z * ol;\n\t\t\tpp.speed *= -0.3;\n\t\t\tpp.speed = MathUtils.clamp(pp.speed, -15, 52);\n\t\t\tconst rs = Math.abs(pp.speed);\n\t\t\tif (rs > 20) pp.spinTimer = 0.6;\n\t\t\tif (bumpCooldown <= 0) {\n\t\t\t\tplayBump();\n\t\t\t\tbumpCooldown = 0.3;\n\t\t\t}\n\t\t\tfor (let i = 0; i < 3; i++) spawnDust();\n\t\t\tfor (let i = 0; i < 6; i++) spawnSpark(pp.pos.clone(), 0xFFAA00);\n\t\t\tshakeCamera(0.25);\n\t\t}\n\t});\n\tfor (let i = 0; i < cpuKarts.length; i++)\n\t\tfor (let j = i + 1; j < cpuKarts.length; j++) {\n\t\t\tconst a = cpuKarts[i],\n\t\t\t\tb = cpuKarts[j];\n\t\t\tconst ap = new Vector3(a.mesh.position.x, 0, a.mesh.position.z),\n\t\t\t\tbp = new Vector3(b.mesh.position.x, 0, b.mesh.position.z);\n\t\t\tconst dist = ap.distanceTo(bp);\n\t\t\tif (dist < 2.4 && dist > 0.01) {\n\t\t\t\tconst push = new Vector3().subVectors(ap, bp).normalize(),\n\t\t\t\t\tol = (2.4 - dist) * 0.5;\n\t\t\t\ta.mesh.position.x += push.x * ol;\n\t\t\t\ta.mesh.position.z += push.z * ol;\n\t\t\t\tb.mesh.position.x -= push.x * ol;\n\t\t\t\tb.mesh.position.z -= push.z * ol;\n\t\t\t\ta.speed *= 0.92;\n\t\t\t\tb.speed *= 0.92;\n\t\t\t}\n\t\t}\n}\n\nfunction createEnvironment() {\n\tconst gC = document.createElement('canvas');\n\tgC.width = 128;\n\tgC.height = 128;\n\tconst gx = gC.getContext('2d');\n\tfor (let y = 0; y < 128; y++) {\n\t\tfor (let x = 0; x < 128; x++) {\n\t\t\tconst r = Math.random() * 0.2;\n\t\t\tconst v2 = Math.sin(x * 0.15) * Math.cos(y * 0.15) * 0.03;\n\t\t\tgx.fillStyle = `rgb(${Math.floor(50+(r+v2)*35)},${Math.floor(105+(r+v2)*55)},${Math.floor(42+(r+v2)*25)})`;\n\t\t\tgx.fillRect(x, y, 1, 1);\n\t\t}\n\t}\n\t// Add subtle grass blade pattern\n\tgx.globalAlpha = 0.06;\n\tgx.strokeStyle = '#2a6628';\n\tgx.lineWidth = 0.5;\n\tfor (let i = 0; i < 200; i++) {\n\t\tconst bx = Math.random() * 128,\n\t\t\tby = Math.random() * 128;\n\t\tgx.beginPath();\n\t\tgx.moveTo(bx, by);\n\t\tgx.lineTo(bx + (Math.random() - 0.5) * 3, by - Math.random() * 4);\n\t\tgx.stroke();\n\t}\n\tgx.globalAlpha = 1;\n\tconst gT = new THREE.CanvasTexture(gC);\n\tgT.wrapS = gT.wrapT = RepeatWrapping;\n\tgT.repeat.set(80, 80);\n\tgT.magFilter = THREE.LinearFilter;\n\tgT.minFilter = THREE.LinearMipmapLinearFilter;\n\tconst ground = new Mesh(new PlaneGeometry(700, 700, 24, 24), new MeshStandardMaterial({\n\t\tmap: gT,\n\t\troughness: 0.88,\n\t\tmetalness: 0.02,\n\t\tflatShading: false\n\t}));\n\tground.rotation.x = -Math.PI / 2;\n\tground.position.y = -0.1;\n\tground.receiveShadow = true;\n\tscene.add(ground);\n\n\tcolliders = [];\n\tfor (let i = 0; i < 120; i++) {\n\t\tconst x = (Math.random() - 0.5) * 550,\n\t\t\tz = (Math.random() - 0.5) * 550;\n\t\tlet ok = true;\n\t\tfor (let t = 0; t < 1; t += 0.025) {\n\t\t\tconst tp = trackCurve.getPoint(t);\n\t\t\tif (Math.sqrt((x - tp.x) ** 2 + (z - tp.z) ** 2) < 26) {\n\t\t\t\tok = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!ok) continue;\n\t\tif (Math.random() > 0.35) {\n\t\t\tconst s = createMKTree(x, 0, z);\n\t\t\tcolliders.push({\n\t\t\t\tpos: new Vector3(x, 0, z),\n\t\t\t\tradius: 1.0 * s\n\t\t\t});\n\t\t} else {\n\t\t\tconst s = createBush(x, 0, z);\n\t\t\tcolliders.push({\n\t\t\t\tpos: new Vector3(x, 0, z),\n\t\t\t\tradius: 0.8 * s\n\t\t\t});\n\t\t}\n\t}\n\n\t// Hills\n\tfor (let i = 0; i < 24; i++) {\n\t\tconst a = (i / 24) * Math.PI * 2,\n\t\t\td = 180 + Math.random() * 80;\n\t\tconst hillR = 12 + Math.random() * 16;\n\t\tlet hx = Math.cos(a) * d,\n\t\t\thz = Math.sin(a) * d,\n\t\t\thillOk = true;\n\t\tfor (let ht = 0; ht < 1; ht += 0.02) {\n\t\t\tconst htp = trackCurve.getPoint(ht);\n\t\t\tif (Math.sqrt((hx - htp.x) ** 2 + (hz - htp.z) ** 2) < hillR + TW) {\n\t\t\t\thillOk = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!hillOk) continue;\n\t\tconst h = new Mesh(new SphereGeometry(hillR, 12, 8, 0, Math.PI * 2, 0, Math.PI / 2), new MeshStandardMaterial({\n\t\t\tcolor: new Color().setHSL(0.3, 0.5, 0.2 + Math.random() * 0.12),\n\t\t\tflatShading: false,\n\t\t\troughness: 0.95\n\t\t}));\n\t\th.position.set(hx, -2, hz);\n\t\th.scale.y = 0.35 + Math.random() * 0.2;\n\t\th.receiveShadow = true;\n\t\tscene.add(h);\n\t}\n\n\tfor (let i = 0; i < 18; i++) createCloud((Math.random() - 0.5) * 500, 35 + Math.random() * 30, (Math.random() - 0.5) * 500);\n\tfor (let i = 0; i < 40; i++) {\n\t\tconst x = (Math.random() - 0.5) * 500,\n\t\t\tz = (Math.random() - 0.5) * 500;\n\t\tlet ok = true;\n\t\tfor (let t = 0; t < 1; t += 0.05) {\n\t\t\tconst tp = trackCurve.getPoint(t);\n\t\t\tif (Math.sqrt((x - tp.x) ** 2 + (z - tp.z) ** 2) < 20) {\n\t\t\t\tok = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (ok) createMushroom(x, 0, z);\n\t}\n\tfor (let i = 0; i < 120; i++) {\n\t\tconst t = Math.random();\n\t\tconst p = trackCurve.getPoint(t),\n\t\t\ttan = trackCurve.getTangent(t).normalize();\n\t\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t\tconst fp = p.clone().add(r.clone().multiplyScalar((Math.random() > 0.5 ? 1 : -1) * (TW / 2 + 2 + Math.random() * 3)));\n\t\tcreateFlower(fp.x, p.y, fp.z);\n\t}\n\tfor (let i = 0; i < 25; i++) {\n\t\tconst x = (Math.random() - 0.5) * 500,\n\t\t\tz = (Math.random() - 0.5) * 500;\n\t\tlet ok = true;\n\t\tfor (let t = 0; t < 1; t += 0.03) {\n\t\t\tconst tp = trackCurve.getPoint(t);\n\t\t\tif (Math.sqrt((x - tp.x) ** 2 + (z - tp.z) ** 2) < 22) {\n\t\t\t\tok = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (ok) createRock(x, 0, z);\n\t}\n\n\t// Grandstand near start\n\tcreateGrandstand();\n}\n\nfunction createGrandstand() {\n\tconst p = trackCurve.getPoint(0),\n\t\ttan = trackCurve.getTangent(0).normalize();\n\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\tfor (let side = -1; side <= 1; side += 2) {\n\t\tconst gPos = p.clone().add(r.clone().multiplyScalar(side * (TW / 2 + 12)));\n\t\t// Tiered seating\n\t\tfor (let row = 0; row < 3; row++) {\n\t\t\tconst seat = new Mesh(new BoxGeometry(12, 0.5, 2), new MeshStandardMaterial({\n\t\t\t\tcolor: row % 2 === 0 ? 0x3355AA : 0xCC3333,\n\t\t\t\tflatShading: true\n\t\t\t}));\n\t\t\tseat.position.copy(gPos).add(r.clone().multiplyScalar(side * row * 2.2));\n\t\t\tseat.position.y = 0.5 + row * 1.5;\n\t\t\tseat.lookAt(p);\n\t\t\tseat.receiveShadow = true;\n\t\t\tscene.add(seat);\n\t\t\t// Crowd dots (simple spheres for spectators)\n\t\t\tfor (let ci = 0; ci < 8; ci++) {\n\t\t\t\tconst colors = [0xFFCC99, 0x8B5E3C, 0xFFDDBB, 0xCC9966];\n\t\t\t\tconst spec = new Group();\n\t\t\t\tconst head = new Mesh(new SphereGeometry(0.25, 4, 3), new MeshStandardMaterial({\n\t\t\t\t\tcolor: colors[Math.floor(Math.random() * 4)],\n\t\t\t\t\tflatShading: true\n\t\t\t\t}));\n\t\t\t\thead.position.y = 0.7;\n\t\t\t\tspec.add(head);\n\t\t\t\tconst body = new Mesh(new CylinderGeometry(0.2, 0.25, 0.5, 4), new MeshStandardMaterial({\n\t\t\t\t\tcolor: [0xFF0000, 0x0000FF, 0x00AA00, 0xFFAA00, 0xFF00FF, 0x00AAAA][Math.floor(Math.random() * 6)],\n\t\t\t\t\tflatShading: true\n\t\t\t\t}));\n\t\t\t\tbody.position.y = 0.35;\n\t\t\t\tspec.add(body);\n\t\t\t\tspec.position.copy(seat.position);\n\t\t\t\tspec.position.x += (ci - 3.5) * 1.2 * (Math.abs(tan.x) > 0.5 ? 1 : 0) + (Math.random() - 0.5) * 0.5;\n\t\t\t\tspec.position.z += (ci - 3.5) * 1.2 * (Math.abs(tan.z) > 0.5 ? 1 : 0) + (Math.random() - 0.5) * 0.5;\n\t\t\t\tspec.position.y += 0.3;\n\t\t\t\tspec.scale.setScalar(0.7 + Math.random() * 0.3);\n\t\t\t\tscene.add(spec);\n\t\t\t}\n\t\t}\n\t\t// Roof\n\t\tconst roof = new Mesh(new BoxGeometry(14, 0.3, 8), new MeshStandardMaterial({\n\t\t\tcolor: 0x444444,\n\t\t\tflatShading: true\n\t\t}));\n\t\troof.position.copy(gPos).add(r.clone().multiplyScalar(side * 2.2));\n\t\troof.position.y = 6;\n\t\troof.lookAt(p);\n\t\tscene.add(roof);\n\t}\n}\n\nfunction createRock(x, y, z) {\n\tconst s = 0.5 + Math.random() * 1.5;\n\tconst rock = new Mesh(new SphereGeometry(s, 8, 6), new MeshStandardMaterial({\n\t\tcolor: [0x888888, 0x777777, 0x999999][Math.floor(Math.random() * 3)],\n\t\tflatShading: false,\n\t\troughness: 0.95\n\t}));\n\trock.position.set(x, y + s * 0.3, z);\n\trock.scale.y = 0.5 + Math.random() * 0.3;\n\trock.rotation.y = Math.random() * Math.PI;\n\trock.castShadow = true;\n\tscene.add(rock);\n}\n\nfunction createMKTree(x, y, z) {\n\tconst tree = new Group();\n\t// Round trunk\n\tconst trunk = new Mesh(new CylinderGeometry(0.3, 0.5, 4, 10), new MeshStandardMaterial({\n\t\tcolor: 0x8B5E3C,\n\t\tflatShading: false,\n\t\troughness: 0.9\n\t}));\n\ttrunk.position.y = 2;\n\ttrunk.castShadow = true;\n\ttree.add(trunk);\n\t// Multi-layered foliage (cone layers like MK trees)\n\tconst fCol = [0x228822, 0x2D9930, 0x33AA38, 0x228020][Math.floor(Math.random() * 4)];\n\tconst fM = new MeshStandardMaterial({\n\t\tcolor: fCol,\n\t\tflatShading: false,\n\t\troughness: 0.85\n\t});\n\tfor (let i = 0; i < 3; i++) {\n\t\tconst radius = 2.8 - i * 0.6;\n\t\tconst cone = new Mesh(new ConeGeometry(radius, 2.5, 12), fM);\n\t\tcone.position.y = 4 + i * 1.5;\n\t\tcone.castShadow = true;\n\t\ttree.add(cone);\n\t}\n\t// Shadow blob\n\tconst shadow = new Mesh(new CircleGeometry(2.5, 12), new MeshBasicMaterial({\n\t\tcolor: 0x000000,\n\t\ttransparent: true,\n\t\topacity: 0.15,\n\t\tdepthWrite: false\n\t}));\n\tshadow.rotation.x = -Math.PI / 2;\n\tshadow.position.y = 0.05;\n\ttree.add(shadow);\n\ttree.position.set(x, y, z);\n\tconst s = 0.6 + Math.random() * 0.8;\n\ttree.scale.setScalar(s);\n\tscene.add(tree);\n\treturn s;\n}\n\nfunction createBush(x, y, z) {\n\tconst cols = [0x2D8825, 0x339930, 0x44AA40];\n\tconst bR = 1.2 + Math.random();\n\tconst g = new Group();\n\t// Main body\n\tconst b = new Mesh(new SphereGeometry(bR, 10, 8), new MeshStandardMaterial({\n\t\tcolor: cols[Math.floor(Math.random() * 3)],\n\t\tflatShading: false,\n\t\troughness: 0.85\n\t}));\n\tb.scale.y = 0.6 + Math.random() * 0.3;\n\tb.castShadow = true;\n\tg.add(b);\n\t// Berry dots\n\tfor (let i = 0; i < 4; i++) {\n\t\tconst berry = new Mesh(new SphereGeometry(0.1, 3, 2), new MeshStandardMaterial({\n\t\t\tcolor: [0xFF4444, 0xFFDD44, 0xFF88CC][Math.floor(Math.random() * 3)],\n\t\t\tflatShading: true\n\t\t}));\n\t\tconst a = Math.random() * Math.PI * 2;\n\t\tberry.position.set(Math.cos(a) * bR * 0.7, 0.2 + Math.random() * 0.3, Math.sin(a) * bR * 0.7);\n\t\tg.add(berry);\n\t}\n\tg.position.set(x, y + 0.5, z);\n\tscene.add(g);\n\treturn bR * 0.8;\n}\n\nfunction createMushroom(x, y, z) {\n\tconst g = new Group();\n\tconst stem = new Mesh(new CylinderGeometry(0.15, 0.25, 1, 6), new MeshStandardMaterial({\n\t\tcolor: 0xFFEECC,\n\t\tflatShading: true\n\t}));\n\tstem.position.y = 0.5;\n\tg.add(stem);\n\tconst capColors = [0xFF3333, 0xFF6644, 0xDD2244];\n\tconst cap = new Mesh(new SphereGeometry(0.5, 10, 8, 0, Math.PI * 2, 0, Math.PI / 2), new MeshStandardMaterial({\n\t\tcolor: capColors[Math.floor(Math.random() * 3)],\n\t\tflatShading: false,\n\t\troughness: 0.6\n\t}));\n\tcap.position.y = 1;\n\tg.add(cap);\n\tfor (let i = 0; i < 5; i++) {\n\t\tconst dot = new Mesh(new SphereGeometry(0.07, 3, 2), new MeshBasicMaterial({\n\t\t\tcolor: 0xFFFFFF\n\t\t}));\n\t\tconst a = (i / 5) * Math.PI * 2;\n\t\tdot.position.set(Math.cos(a) * 0.35, 1.1, Math.sin(a) * 0.35);\n\t\tg.add(dot);\n\t}\n\tg.position.set(x, y, z);\n\tg.scale.setScalar(0.5 + Math.random());\n\tscene.add(g);\n}\n\nfunction createFlower(x, y, z) {\n\tconst cols = [0xFF4466, 0xFFDD44, 0xFF88CC, 0x44AAFF, 0xFFFFFF, 0xEE66FF];\n\tconst col = cols[Math.floor(Math.random() * cols.length)];\n\tconst g = new Group();\n\tconst stem = new Mesh(new CylinderGeometry(0.02, 0.03, 0.4, 3), new MeshStandardMaterial({\n\t\tcolor: 0x228822,\n\t\tflatShading: true\n\t}));\n\tstem.position.y = 0.2;\n\tg.add(stem);\n\tfor (let i = 0; i < 5; i++) {\n\t\tconst a = (i / 5) * Math.PI * 2;\n\t\tconst p = new Mesh(new SphereGeometry(0.1, 3, 2), new MeshStandardMaterial({\n\t\t\tcolor: col,\n\t\t\tflatShading: true\n\t\t}));\n\t\tp.position.set(Math.cos(a) * 0.1, 0.42, Math.sin(a) * 0.1);\n\t\tg.add(p);\n\t}\n\tg.add(new Mesh(new SphereGeometry(0.05, 3, 2), new MeshStandardMaterial({\n\t\tcolor: 0xFFDD00,\n\t\tflatShading: true\n\t})).translateY(0.42));\n\tg.position.set(x, y, z);\n\tscene.add(g);\n}\n\nfunction createCloud(x, y, z) {\n\tconst cl = new Group();\n\tconst cM = new MeshStandardMaterial({\n\t\tcolor: 0xFFFFFF,\n\t\troughness: 1,\n\t\tflatShading: false,\n\t\ttransparent: true,\n\t\topacity: 0.95\n\t});\n\tfor (let i = 0; i < 7; i++) {\n\t\tconst p = new Mesh(new SphereGeometry(1.8 + Math.random() * 3.5, 12, 10), cM);\n\t\tp.position.set((Math.random() - 0.5) * 5, (Math.random() - 0.5) * 1.5, (Math.random() - 0.5) * 3);\n\t\tp.scale.y = 0.5 + Math.random() * 0.3;\n\t\tcl.add(p);\n\t}\n\tcl.position.set(x, y, z);\n\tcl.userData.speed = 0.3 + Math.random() * 1.2;\n\tscene.add(cl);\n\tclouds.push(cl);\n}\n\n// ===== PARTICLES =====\nfunction createDustSystem() {\n\tfor (let i = 0; i < 50; i++) {\n\t\tconst d = new Mesh(new SphereGeometry(0.15, 6, 5), new MeshBasicMaterial({\n\t\t\tcolor: 0xCCBB88,\n\t\t\ttransparent: true,\n\t\t\topacity: 0,\n\t\t\tdepthWrite: false\n\t\t}));\n\t\td.visible = false;\n\t\td.userData = {\n\t\t\tlife: 0,\n\t\t\tvel: new Vector3()\n\t\t};\n\t\tscene.add(d);\n\t\tdustParticles.push(d);\n\t}\n}\n\nfunction spawnDust() {\n\tconst d = dustParticles.find(p => p.userData.life <= 0);\n\tif (!d) return;\n\td.visible = true;\n\td.userData.life = 0.5;\n\td.position.copy(pp.pos);\n\td.position.x += (Math.random() - 0.5) * 1.5;\n\td.position.z += (Math.random() - 0.5) * 1.5;\n\td.position.y += 0.1;\n\td.userData.vel.set((Math.random() - 0.5) * 3, 1.5 + Math.random() * 2, (Math.random() - 0.5) * 3);\n\td.material.opacity = 0.7;\n\td.scale.setScalar(0.5 + Math.random() * 0.8);\n}\n\nfunction updateDust(dt) {\n\tdustParticles.forEach(d => {\n\t\tif (d.userData.life <= 0) {\n\t\t\td.visible = false;\n\t\t\treturn;\n\t\t}\n\t\td.userData.life -= dt;\n\t\td.position.add(d.userData.vel.clone().multiplyScalar(dt));\n\t\td.userData.vel.y -= 3 * dt;\n\t\td.material.opacity = Math.max(0, d.userData.life * 1.4);\n\t});\n}\n\nfunction createSparkSystem() {\n\tsparkParticles = [];\n\tfor (let i = 0; i < 80; i++) {\n\t\tconst s = new Mesh(new SphereGeometry(0.06, 4, 3), new MeshBasicMaterial({\n\t\t\tcolor: 0xFFDD00,\n\t\t\ttransparent: true,\n\t\t\topacity: 0,\n\t\t\tblending: AdditiveBlending,\n\t\t\tdepthWrite: false\n\t\t}));\n\t\ts.visible = false;\n\t\ts.userData = {\n\t\t\tlife: 0,\n\t\t\tvel: new Vector3()\n\t\t};\n\t\tscene.add(s);\n\t\tsparkParticles.push(s);\n\t}\n}\n\nfunction spawnSpark(pos, color) {\n\tconst s = sparkParticles.find(p => p.userData.life <= 0);\n\tif (!s) return;\n\ts.visible = true;\n\ts.userData.life = 0.4 + Math.random() * 0.3;\n\ts.material.color.setHex(color);\n\ts.position.copy(pos);\n\ts.position.y += 0.5;\n\ts.userData.vel.set((Math.random() - 0.5) * 8, 2 + Math.random() * 4, (Math.random() - 0.5) * 8);\n\ts.material.opacity = 1;\n\ts.scale.setScalar(0.1 + Math.random() * 0.2);\n}\n\nfunction updateSparks(dt) {\n\tsparkParticles.forEach(s => {\n\t\tif (s.userData.life <= 0) {\n\t\t\ts.visible = false;\n\t\t\treturn;\n\t\t}\n\t\ts.userData.life -= dt;\n\t\ts.position.add(s.userData.vel.clone().multiplyScalar(dt));\n\t\ts.userData.vel.y -= 12 * dt;\n\t\ts.material.opacity = Math.max(0, s.userData.life * 2.5);\n\t\ts.scale.multiplyScalar(0.98);\n\t});\n}\n\nfunction createExhaustSystem() {\n\texhaustParticles = [];\n\tfor (let i = 0; i < 35; i++) {\n\t\tconst e = new Mesh(new SphereGeometry(0.12, 6, 5), new MeshBasicMaterial({\n\t\t\tcolor: 0xFF4400,\n\t\t\ttransparent: true,\n\t\t\topacity: 0,\n\t\t\tdepthWrite: false\n\t\t}));\n\t\te.visible = false;\n\t\te.userData = {\n\t\t\tlife: 0,\n\t\t\tvel: new Vector3()\n\t\t};\n\t\tscene.add(e);\n\t\texhaustParticles.push(e);\n\t}\n}\n\nfunction spawnExhaust() {\n\tconst e = exhaustParticles.find(p => p.userData.life <= 0);\n\tif (!e) return;\n\te.visible = true;\n\te.userData.life = 0.25 + Math.random() * 0.15;\n\te.position.copy(pp.pos);\n\te.position.x -= Math.sin(pp.rot) * 1.8 + (Math.random() - 0.5) * 0.3;\n\te.position.z -= Math.cos(pp.rot) * 1.8 + (Math.random() - 0.5) * 0.3;\n\te.position.y += 0.35;\n\te.userData.vel.set(-Math.sin(pp.rot) * 3 + (Math.random() - 0.5) * 2, 0.5 + Math.random(), -Math.cos(pp.rot) * 3 + (Math.random() - 0.5) * 2);\n\te.material.color.setHex(playerBoostTimer > 0 ? 0x4488FF : (Math.abs(pp.speed) > 35 ? 0xFF6600 : 0x666666));\n\te.material.opacity = playerBoostTimer > 0 ? 0.6 : 0.4;\n\te.scale.setScalar(playerBoostTimer > 0 ? 0.35 : 0.15 + Math.random() * 0.15);\n}\n\nfunction updateExhaust(dt) {\n\texhaustParticles.forEach(e => {\n\t\tif (e.userData.life <= 0) {\n\t\t\te.visible = false;\n\t\t\treturn;\n\t\t}\n\t\te.userData.life -= dt;\n\t\te.position.add(e.userData.vel.clone().multiplyScalar(dt));\n\t\te.userData.vel.y += 2 * dt;\n\t\te.material.opacity = Math.max(0, e.userData.life * 3);\n\t\te.scale.multiplyScalar(1.03);\n\t});\n}\n\nfunction createSpeedLines() {\n\tspeedLineParticles = [];\n\tfor (let i = 0; i < 30; i++) {\n\t\tconst l = new Mesh(new BoxGeometry(0.015, 0.015, 2.0), new MeshBasicMaterial({\n\t\t\tcolor: 0xFFFFFF,\n\t\t\ttransparent: true,\n\t\t\topacity: 0,\n\t\t\tblending: AdditiveBlending,\n\t\t\tdepthWrite: false\n\t\t}));\n\t\tl.visible = false;\n\t\tl.userData = {\n\t\t\tlife: 0\n\t\t};\n\t\tscene.add(l);\n\t\tspeedLineParticles.push(l);\n\t}\n}\n\nfunction spawnSpeedLine() {\n\tconst l = speedLineParticles.find(p => p.userData.life <= 0);\n\tif (!l) return;\n\tl.visible = true;\n\tl.userData.life = 0.2;\n\tconst offset = new Vector3((Math.random() - 0.5) * 6, (Math.random() - 0.5) * 3 + 1.5, (Math.random() - 0.5) * 2);\n\tl.position.copy(pp.pos).add(offset);\n\tl.position.x += Math.sin(pp.rot) * 4;\n\tl.position.z += Math.cos(pp.rot) * 4;\n\tl.rotation.y = pp.rot;\n\tl.material.opacity = 0.35;\n\tl.scale.z = 1 + Math.min(Math.abs(pp.speed) / 50, 1) * 3;\n}\n\nfunction updateSpeedLines(dt) {\n\tspeedLineParticles.forEach(l => {\n\t\tif (l.userData.life <= 0) {\n\t\t\tl.visible = false;\n\t\t\treturn;\n\t\t}\n\t\tl.userData.life -= dt;\n\t\tl.position.x -= Math.sin(pp.rot) * pp.speed * dt * 0.5;\n\t\tl.position.z -= Math.cos(pp.rot) * pp.speed * dt * 0.5;\n\t\tl.material.opacity = l.userData.life * 2;\n\t});\n}\n\nfunction resetPlayerOnTrack() {\n\tconst ct = findT(pp.pos);\n\tconst tp = trackCurve.getPoint(ct);\n\tconst tan = trackCurve.getTangent(ct).normalize();\n\tpp.pos.copy(tp);\n\tpp.pos.y += 0.22;\n\tpp.rot = Math.atan2(tan.x, tan.z);\n\tpp.speed = Math.max(pp.speed * 0.3, 0);\n\tpp.spinTimer = 0;\n\tpp.drift = false;\n\tdriftCharge = 0;\n\tplayerKart.position.copy(pp.pos);\n\tplayerKart.rotation.y = pp.rot;\n\tplayerKart.rotation.z = 0;\n\tplayerKart.rotation.x = 0;\n\tplayTone(550, 0.1, 'square', 0.08);\n\tsetTimeout(() => playTone(660, 0.1, 'square', 0.06), 80);\n\tfor (let i = 0; i < 6; i++) spawnDust();\n}\n\nlet cameraShake = 0;\n\nfunction shakeCamera(intensity) {\n\tcameraShake = Math.max(cameraShake, intensity);\n}\n\n// ===== KARTS (IMPROVED) =====\nfunction createKart(color) {\n\tconst k = new Group();\n\tconst bodyCol = new Color(color);\n\tconst darkCol = bodyCol.clone().multiplyScalar(0.5);\n\tconst lightCol = bodyCol.clone().lerp(new Color(0xffffff), 0.4);\n\tconst metalCol = new Color(0xcccccc);\n\n\t// Main body - rounded shape using multiple parts\n\tconst bodyM = new MeshStandardMaterial({\n\t\tcolor,\n\t\troughness: 0.08,\n\t\tmetalness: 0.65,\n\t\tflatShading: false,\n\t\tenvMapIntensity: 1.8,\n\t\tclearcoat: 0.3,\n\t\tclearcoatRoughness: 0.15\n\t});\n\t// Lower body (wider, more segments for smoothness)\n\tconst lowerBody = new Mesh(new BoxGeometry(2, 0.5, 3.2, 4, 2, 4), bodyM);\n\tlowerBody.position.y = 0.35;\n\tlowerBody.castShadow = true;\n\tk.add(lowerBody);\n\t// Upper body (narrower, rounded front)\n\tconst upperBody = new Mesh(new BoxGeometry(1.7, 0.35, 2.8, 3, 2, 3), bodyM);\n\tupperBody.position.y = 0.7;\n\tk.add(upperBody);\n\t// Side air vents\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\tconst vent = new Mesh(new BoxGeometry(0.08, 0.25, 0.6, 1, 3, 1), new MeshStandardMaterial({\n\t\t\tcolor: 0x111111,\n\t\t\troughness: 0.95,\n\t\t\tmetalness: 0.1\n\t\t}));\n\t\tvent.position.set(s * 0.95, 0.55, 0.2);\n\t\tk.add(vent);\n\t\t// Vent grilles\n\t\tfor (let i = 0; i < 4; i++) {\n\t\t\tconst slat = new Mesh(new BoxGeometry(0.09, 0.02, 0.5), new MeshStandardMaterial({\n\t\t\t\tcolor: darkCol,\n\t\t\t\troughness: 0.3,\n\t\t\t\tmetalness: 0.7\n\t\t\t}));\n\t\t\tslat.position.set(s * 0.95, 0.45 + i * 0.07, 0.2);\n\t\t\tk.add(slat);\n\t\t}\n\t}\n\t// Front nose (rounded, higher detail)\n\tconst nose = new Mesh(new SphereGeometry(0.8, 20, 12, 0, Math.PI, 0, Math.PI / 2), bodyM);\n\tnose.position.set(0, 0.4, 1.6);\n\tnose.rotation.x = -Math.PI / 2;\n\tk.add(nose);\n\t// Front splitter (aerodynamic element)\n\tconst splitter = new Mesh(new BoxGeometry(1.9, 0.04, 0.4), new MeshStandardMaterial({\n\t\tcolor: 0x222222,\n\t\troughness: 0.2,\n\t\tmetalness: 0.8,\n\t\tflatShading: false\n\t}));\n\tsplitter.position.set(0, 0.12, 1.85);\n\tk.add(splitter);\n\t// Rear engine cover (more detailed)\n\tconst rearCover = new Mesh(new BoxGeometry(1.5, 0.45, 0.9, 2, 2, 2), new MeshStandardMaterial({\n\t\tcolor: darkCol,\n\t\troughness: 0.15,\n\t\tmetalness: 0.6,\n\t\tflatShading: false,\n\t\tclearcoat: 0.2\n\t}));\n\trearCover.position.set(0, 0.65, -1.5);\n\tk.add(rearCover);\n\t// Engine air intake\n\tconst intake = new Mesh(new BoxGeometry(0.6, 0.25, 0.35), new MeshStandardMaterial({\n\t\tcolor: 0x1a1a1a,\n\t\troughness: 0.8,\n\t\tmetalness: 0.2\n\t}));\n\tintake.position.set(0, 0.88, -1.35);\n\tk.add(intake);\n\t// Intake mesh grille\n\tconst intakeMesh = new Mesh(new BoxGeometry(0.55, 0.2, 0.3), new MeshStandardMaterial({\n\t\tcolor: 0x444444,\n\t\troughness: 0.4,\n\t\tmetalness: 0.7,\n\t\twireframe: true\n\t}));\n\tintakeMesh.position.set(0, 0.88, -1.35);\n\tk.add(intakeMesh);\n\t// Side skirts with racing stripes\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\tconst skirt = new Mesh(new BoxGeometry(0.18, 0.32, 2.8, 1, 2, 4), new MeshStandardMaterial({\n\t\t\tcolor: darkCol,\n\t\t\tflatShading: false,\n\t\t\troughness: 0.2,\n\t\t\tmetalness: 0.5\n\t\t}));\n\t\tskirt.position.set(s * 1, 0.25, 0);\n\t\tk.add(skirt);\n\t\t// Racing stripe\n\t\tconst stripe = new Mesh(new BoxGeometry(0.19, 0.05, 2.7), new MeshStandardMaterial({\n\t\t\tcolor: lightCol,\n\t\t\troughness: 0.15,\n\t\t\tmetalness: 0.7,\n\t\t\temissive: lightCol,\n\t\t\temissiveIntensity: 0.08\n\t\t}));\n\t\tstripe.position.set(s * 1, 0.35, 0);\n\t\tk.add(stripe);\n\t}\n\t// Front bumper\n\tconst bumper = new Mesh(new BoxGeometry(1.8, 0.25, 0.25, 2, 1, 1), new MeshStandardMaterial({\n\t\tcolor: 0x2a2a2a,\n\t\tflatShading: false,\n\t\tmetalness: 0.6,\n\t\troughness: 0.2\n\t}));\n\tbumper.position.set(0, 0.25, 1.8);\n\tk.add(bumper);\n\t// Rear bumper\n\tconst rBumper = new Mesh(new BoxGeometry(1.6, 0.2, 0.2), new MeshStandardMaterial({\n\t\tcolor: 0x2a2a2a,\n\t\tflatShading: false,\n\t\tmetalness: 0.6,\n\t\troughness: 0.2\n\t}));\n\trBumper.position.set(0, 0.25, -1.7);\n\tk.add(rBumper);\n\n\t// Cockpit with better detail\n\tconst cockpit = new Mesh(new BoxGeometry(1.2, 0.5, 1.2, 2, 2, 2), new MeshStandardMaterial({\n\t\tcolor: lightCol,\n\t\troughness: 0.12,\n\t\tmetalness: 0.25,\n\t\tflatShading: false,\n\t\tclearcoat: 0.4,\n\t\tclearcoatRoughness: 0.1\n\t}));\n\tcockpit.position.set(0, 0.95, -0.15);\n\tk.add(cockpit);\n\t// Cockpit roll bar\n\tconst rollBar = new Mesh(new CylinderGeometry(0.06, 0.06, 0.8, 12), new MeshStandardMaterial({\n\t\tcolor: metalCol,\n\t\troughness: 0.1,\n\t\tmetalness: 0.9\n\t}));\n\trollBar.position.set(0, 1.25, -0.4);\n\tk.add(rollBar);\n\t// Windshield (curved, more realistic)\n\tconst windshieldG = new SphereGeometry(1.3, 16, 12, 0, Math.PI, 0, Math.PI * 0.35);\n\tconst windshield = new Mesh(windshieldG, new MeshStandardMaterial({\n\t\tcolor: 0x88CCEE,\n\t\troughness: 0.01,\n\t\tmetalness: 0.1,\n\t\tflatShading: false,\n\t\ttransparent: true,\n\t\topacity: 0.4,\n\t\tenvMapIntensity: 3.0,\n\t\trefractionRatio: 0.95\n\t}));\n\twindshield.position.set(0, 1.05, 0.4);\n\twindshield.rotation.x = -Math.PI / 2 + 0.5;\n\twindshield.scale.set(0.85, 1, 0.9);\n\tk.add(windshield);\n\n\t// Steering wheel\n\tconst steeringG = new TorusGeometry(0.15, 0.03, 4, 8);\n\tconst steering = new Mesh(steeringG, new MeshStandardMaterial({\n\t\tcolor: 0x333333,\n\t\tflatShading: true\n\t}));\n\tsteering.position.set(0, 1.0, 0.2);\n\tsteering.rotation.x = -0.5;\n\tk.add(steering);\n\n\t// Character - more detailed\n\tconst head = new Mesh(new SphereGeometry(0.35, 16, 12), new MeshStandardMaterial({\n\t\tcolor: 0xFFCC99,\n\t\troughness: 0.75,\n\t\tflatShading: false\n\t}));\n\thead.position.set(0, 1.55, -0.15);\n\tk.add(head);\n\t// Helmet (rounded, better quality)\n\tconst helmet = new Mesh(new SphereGeometry(0.39, 20, 14, 0, Math.PI * 2, 0, Math.PI * 0.62), new MeshStandardMaterial({\n\t\tcolor,\n\t\tflatShading: false,\n\t\tmetalness: 0.6,\n\t\troughness: 0.08,\n\t\tclearcoat: 0.8,\n\t\tclearcoatRoughness: 0.05\n\t}));\n\thelmet.position.set(0, 1.58, -0.15);\n\tk.add(helmet);\n\t// Helmet racing stripe\n\tconst hStripe = new Mesh(new BoxGeometry(0.15, 0.4, 0.4), new MeshStandardMaterial({\n\t\tcolor: lightCol,\n\t\troughness: 0.1,\n\t\tmetalness: 0.7,\n\t\temissive: lightCol,\n\t\temissiveIntensity: 0.1\n\t}));\n\thStripe.position.set(0, 1.65, -0.12);\n\tk.add(hStripe);\n\t// Visor (curved)\n\tconst visorG = new SphereGeometry(0.38, 16, 12, -0.5, 1, 0.3, 0.5);\n\tconst visor = new Mesh(visorG, new MeshStandardMaterial({\n\t\tcolor: 0x0a0a22,\n\t\tflatShading: false,\n\t\tmetalness: 0.95,\n\t\troughness: 0.02,\n\t\ttransparent: true,\n\t\topacity: 0.7,\n\t\tenvMapIntensity: 2.5\n\t}));\n\tvisor.position.set(0, 1.52, 0.08);\n\tk.add(visor);\n\t// Eyes\n\t[-0.12, 0.12].forEach(x => {\n\t\tconst eye = new Mesh(new SphereGeometry(0.05, 3, 2), new MeshBasicMaterial({\n\t\t\tcolor: 0x111111\n\t\t}));\n\t\teye.position.set(x, 1.5, 0.2);\n\t\tk.add(eye);\n\t});\n\t// Arms\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\tconst arm = new Mesh(new CylinderGeometry(0.07, 0.07, 0.5, 4), new MeshStandardMaterial({\n\t\t\tcolor: color,\n\t\t\tflatShading: true\n\t\t}));\n\t\tarm.position.set(s * 0.45, 1.15, 0.1);\n\t\tarm.rotation.z = s * 0.8;\n\t\tarm.rotation.x = -0.3;\n\t\tk.add(arm);\n\t\t// Hand\n\t\tconst hand = new Mesh(new SphereGeometry(0.08, 3, 2), new MeshStandardMaterial({\n\t\t\tcolor: 0xFFCC99,\n\t\t\tflatShading: true\n\t\t}));\n\t\thand.position.set(s * 0.55, 1.0, 0.2);\n\t\tk.add(hand);\n\t}\n\n\t// Wheels with premium detail\n\tk.wheels = [];\n\t[\n\t\t[-0.95, 0.2, 1.1],\n\t\t[0.95, 0.2, 1.1],\n\t\t[-0.95, 0.2, -1.1],\n\t\t[0.95, 0.2, -1.1]\n\t].forEach(([x, y, z], idx) => {\n\t\tconst ww = new Group();\n\t\t// Tire (high detail)\n\t\tconst tire = new Mesh(new CylinderGeometry(0.38, 0.38, 0.35, 24), new MeshStandardMaterial({\n\t\t\tcolor: 0x151515,\n\t\t\troughness: 0.95,\n\t\t\tflatShading: false,\n\t\t\tbumpScale: 0.02\n\t\t}));\n\t\ttire.rotation.z = Math.PI / 2;\n\t\tww.add(tire);\n\t\t// Tire sidewall\n\t\tconst sidewall = new Mesh(new CylinderGeometry(0.36, 0.36, 0.37, 24), new MeshStandardMaterial({\n\t\t\tcolor: 0x2a2a2a,\n\t\t\troughness: 0.8,\n\t\t\tflatShading: false\n\t\t}));\n\t\tsidewall.rotation.z = Math.PI / 2;\n\t\tww.add(sidewall);\n\t\t// Tread pattern (detailed)\n\t\tfor (let i = 0; i < 16; i++) {\n\t\t\tconst treadBlock = new Mesh(new BoxGeometry(0.4, 0.03, 0.08), new MeshStandardMaterial({\n\t\t\t\tcolor: 0x0a0a0a,\n\t\t\t\troughness: 1\n\t\t\t}));\n\t\t\tconst angle = (i / 16) * Math.PI * 2;\n\t\t\ttreadBlock.position.set(0, Math.cos(angle) * 0.38, Math.sin(angle) * 0.38);\n\t\t\ttreadBlock.rotation.x = angle;\n\t\t\ttreadBlock.rotation.z = Math.PI / 2;\n\t\t\tww.add(treadBlock);\n\t\t}\n\t\t// Brake disc (visible through rim)\n\t\tconst brakeDisc = new Mesh(new CylinderGeometry(0.22, 0.22, 0.05, 24), new MeshStandardMaterial({\n\t\t\tcolor: 0x666666,\n\t\t\tmetalness: 0.9,\n\t\t\troughness: 0.2,\n\t\t\tflatShading: false\n\t\t}));\n\t\tbrakeDisc.rotation.z = Math.PI / 2;\n\t\tbrakeDisc.position.x = idx % 2 === 0 ? 0.15 : -0.15;\n\t\tww.add(brakeDisc);\n\t\t// Brake caliper\n\t\tconst caliper = new Mesh(new BoxGeometry(0.08, 0.15, 0.12), new MeshStandardMaterial({\n\t\t\tcolor: 0xFF2222,\n\t\t\tmetalness: 0.7,\n\t\t\troughness: 0.25\n\t\t}));\n\t\tcaliper.position.set(idx % 2 === 0 ? 0.15 : -0.15, 0.2, 0);\n\t\tww.add(caliper);\n\t\t// Hub cap (multi-spoke design)\n\t\tconst hubBase = new Mesh(new CylinderGeometry(0.19, 0.19, 0.36, 24), new MeshStandardMaterial({\n\t\t\tcolor: metalCol,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.85,\n\t\t\troughness: 0.1\n\t\t}));\n\t\thubBase.rotation.z = Math.PI / 2;\n\t\tww.add(hubBase);\n\t\t// Spokes\n\t\tfor (let i = 0; i < 5; i++) {\n\t\t\tconst spoke = new Mesh(new BoxGeometry(0.37, 0.05, 0.08), new MeshStandardMaterial({\n\t\t\t\tcolor: metalCol,\n\t\t\t\tmetalness: 0.9,\n\t\t\t\troughness: 0.08\n\t\t\t}));\n\t\t\tspoke.rotation.z = Math.PI / 2;\n\t\t\tspoke.rotation.x = (i / 5) * Math.PI * 2;\n\t\t\tww.add(spoke);\n\t\t}\n\t\t// Hub center with color accent\n\t\tconst hubCenter = new Mesh(new CylinderGeometry(0.08, 0.08, 0.38, 16), new MeshStandardMaterial({\n\t\t\tcolor,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.6,\n\t\t\troughness: 0.15,\n\t\t\temissive: color,\n\t\t\temissiveIntensity: 0.12\n\t\t}));\n\t\thubCenter.rotation.z = Math.PI / 2;\n\t\tww.add(hubCenter);\n\t\t// Lug nuts\n\t\tfor (let i = 0; i < 5; i++) {\n\t\t\tconst lug = new Mesh(new CylinderGeometry(0.025, 0.025, 0.015, 6), new MeshStandardMaterial({\n\t\t\t\tcolor: 0x333333,\n\t\t\t\tmetalness: 0.8,\n\t\t\t\troughness: 0.3\n\t\t\t}));\n\t\t\tconst angle = (i / 5) * Math.PI * 2;\n\t\t\tlug.position.set(idx % 2 === 0 ? 0.19 : -0.19, Math.cos(angle) * 0.12, Math.sin(angle) * 0.12);\n\t\t\tlug.rotation.z = Math.PI / 2;\n\t\t\tww.add(lug);\n\t\t}\n\t\tww.position.set(x, y, z);\n\t\tww.castShadow = true;\n\t\tk.add(ww);\n\t\tk.wheels.push(ww);\n\t});\n\n\t// Exhaust pipes (more detailed)\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\tconst ex = new Mesh(new CylinderGeometry(0.08, 0.1, 0.55, 16), new MeshStandardMaterial({\n\t\t\tcolor: 0x555555,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.85,\n\t\t\troughness: 0.12\n\t\t}));\n\t\tex.position.set(s * 0.45, 0.3, -1.75);\n\t\tex.rotation.x = Math.PI / 6;\n\t\tk.add(ex);\n\t\t// Exhaust heat shield\n\t\tconst shield = new Mesh(new CylinderGeometry(0.11, 0.13, 0.5, 16), new MeshStandardMaterial({\n\t\t\tcolor: 0x1a1a1a,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.3,\n\t\t\troughness: 0.7,\n\t\t\ttransparent: true,\n\t\t\topacity: 0.6\n\t\t}));\n\t\tshield.position.set(s * 0.45, 0.3, -1.75);\n\t\tshield.rotation.x = Math.PI / 6;\n\t\tk.add(shield);\n\t\t// Exhaust tip (chrome)\n\t\tconst exTip = new Mesh(new CylinderGeometry(0.1, 0.11, 0.1, 16), new MeshStandardMaterial({\n\t\t\tcolor: 0xaaaaaa,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.95,\n\t\t\troughness: 0.05,\n\t\t\tenvMapIntensity: 2.0\n\t\t}));\n\t\texTip.position.set(s * 0.45, 0.46, -1.88);\n\t\texTip.rotation.x = Math.PI / 6;\n\t\tk.add(exTip);\n\t\t// Inner exhaust opening\n\t\tconst exInner = new Mesh(new CylinderGeometry(0.07, 0.08, 0.05, 12), new MeshStandardMaterial({\n\t\t\tcolor: 0x0a0a0a,\n\t\t\troughness: 0.9,\n\t\t\tmetalness: 0.1\n\t\t}));\n\t\texInner.position.set(s * 0.45, 0.49, -1.91);\n\t\texInner.rotation.x = Math.PI / 6;\n\t\tk.add(exInner);\n\t}\n\t// Headlights (LED style with housing)\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\t// Headlight housing\n\t\tconst housing = new Mesh(new CylinderGeometry(0.16, 0.14, 0.12, 16), new MeshStandardMaterial({\n\t\t\tcolor: 0x1a1a1a,\n\t\t\tmetalness: 0.5,\n\t\t\troughness: 0.3\n\t\t}));\n\t\thousing.rotation.x = Math.PI / 2;\n\t\thousing.position.set(s * 0.55, 0.4, 1.82);\n\t\tk.add(housing);\n\t\t// LED element\n\t\tconst hl = new Mesh(new CircleGeometry(0.13, 16), new MeshStandardMaterial({\n\t\t\tcolor: 0xFFFFDD,\n\t\t\temissive: 0xFFFFAA,\n\t\t\temissiveIntensity: 0.8,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.2,\n\t\t\troughness: 0.05\n\t\t}));\n\t\thl.position.set(s * 0.55, 0.4, 1.83);\n\t\tk.add(hl);\n\t\t// Headlight reflector\n\t\tconst reflector = new Mesh(new CircleGeometry(0.11, 12), new MeshStandardMaterial({\n\t\t\tcolor: 0xFFFFFF,\n\t\t\tmetalness: 0.95,\n\t\t\troughness: 0.02\n\t\t}));\n\t\treflector.position.set(s * 0.55, 0.4, 1.79);\n\t\tk.add(reflector);\n\t\t// Headlight glow (larger)\n\t\tconst hlGlow = new Mesh(new CircleGeometry(0.28, 16), new MeshBasicMaterial({\n\t\t\tcolor: 0xFFFFAA,\n\t\t\ttransparent: true,\n\t\t\topacity: 0.2,\n\t\t\tblending: AdditiveBlending,\n\t\t\tdepthWrite: false\n\t\t}));\n\t\thlGlow.position.set(s * 0.55, 0.4, 1.84);\n\t\tk.add(hlGlow);\n\t}\n\t// Tail lights (LED bar style)\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\t// Tail light housing\n\t\tconst tlHousing = new Mesh(new BoxGeometry(0.15, 0.25, 0.08), new MeshStandardMaterial({\n\t\t\tcolor: 0x1a1a1a,\n\t\t\tmetalness: 0.4,\n\t\t\troughness: 0.4\n\t\t}));\n\t\ttlHousing.position.set(s * 0.55, 0.35, -1.71);\n\t\tk.add(tlHousing);\n\t\t// LED strip\n\t\tconst tl = new Mesh(new BoxGeometry(0.12, 0.22, 0.02), new MeshStandardMaterial({\n\t\t\tcolor: 0xFF3333,\n\t\t\temissive: 0xFF1111,\n\t\t\temissiveIntensity: 0.7,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.2,\n\t\t\troughness: 0.1\n\t\t}));\n\t\ttl.position.set(s * 0.55, 0.35, -1.72);\n\t\tk.add(tl);\n\t\t// Tail light glow\n\t\tconst tlGlow = new Mesh(new CircleGeometry(0.22, 12), new MeshBasicMaterial({\n\t\t\tcolor: 0xFF2200,\n\t\t\ttransparent: true,\n\t\t\topacity: 0.18,\n\t\t\tblending: AdditiveBlending,\n\t\t\tdepthWrite: false\n\t\t}));\n\t\ttlGlow.position.set(s * 0.55, 0.35, -1.73);\n\t\ttlGlow.rotation.y = Math.PI;\n\t\tk.add(tlGlow);\n\t}\n\t// Number plate\n\tconst numC = document.createElement('canvas');\n\tnumC.width = 16;\n\tnumC.height = 8;\n\tconst nx = numC.getContext('2d');\n\tnx.fillStyle = '#fff';\n\tnx.fillRect(0, 0, 16, 8);\n\tnx.fillStyle = '#000';\n\tnx.font = 'bold 7px sans-serif';\n\tnx.textAlign = 'center';\n\tnx.fillText(String(Math.floor(Math.random() * 9) + 1), 8, 7);\n\tconst numTex = new THREE.CanvasTexture(numC);\n\tnumTex.magFilter = THREE.LinearFilter;\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\tconst plate = new Mesh(new PlaneGeometry(0.5, 0.25), new MeshStandardMaterial({\n\t\t\tmap: numTex,\n\t\t\tflatShading: true\n\t\t}));\n\t\tplate.position.set(s * 1.01, 0.5, 0);\n\t\tplate.rotation.y = s * Math.PI / 2;\n\t\tk.add(plate);\n\t}\n\n\t// Rear spoiler (racing style, multi-element)\n\tconst spoiler = new Mesh(new BoxGeometry(1.85, 0.1, 0.4, 2, 1, 1), new MeshStandardMaterial({\n\t\tcolor,\n\t\tflatShading: false,\n\t\tmetalness: 0.6,\n\t\troughness: 0.08,\n\t\tclearcoat: 0.5\n\t}));\n\tspoiler.position.set(0, 1.22, -1.4);\n\tspoiler.rotation.x = -0.08;\n\tk.add(spoiler);\n\t// Upper spoiler element (double-decker)\n\tconst spoiler2 = new Mesh(new BoxGeometry(1.7, 0.08, 0.3), new MeshStandardMaterial({\n\t\tcolor: darkCol,\n\t\tmetalness: 0.7,\n\t\troughness: 0.1\n\t}));\n\tspoiler2.position.set(0, 1.38, -1.42);\n\tspoiler2.rotation.x = -0.1;\n\tk.add(spoiler2);\n\t// Spoiler endplates\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\tconst endplate = new Mesh(new BoxGeometry(0.08, 0.35, 0.45), new MeshStandardMaterial({\n\t\t\tcolor: darkCol,\n\t\t\tmetalness: 0.6,\n\t\t\troughness: 0.15\n\t\t}));\n\t\tendplate.position.set(s * 0.88, 1.12, -1.38);\n\t\tk.add(endplate);\n\t}\n\t// Spoiler struts (stronger, angled)\n\tfor (let s = -1; s <= 1; s += 2) {\n\t\tconst strut = new Mesh(new CylinderGeometry(0.05, 0.05, 0.55, 12), new MeshStandardMaterial({\n\t\t\tcolor: 0x2a2a2a,\n\t\t\tflatShading: false,\n\t\t\tmetalness: 0.8,\n\t\t\troughness: 0.2\n\t\t}));\n\t\tstrut.position.set(s * 0.6, 0.95, -1.4);\n\t\tk.add(strut);\n\t}\n\n\treturn k;\n}\n\nfunction createPlayerKart() {\n\tplayerKart = createKart(P_COL);\n\tconst sp = trackCurve.getPoint(0),\n\t\tst = trackCurve.getTangent(0);\n\tplayerKart.position.copy(sp);\n\tplayerKart.position.y = 0.22;\n\tpp.pos.copy(playerKart.position);\n\tpp.rot = Math.atan2(st.x, st.z);\n\tscene.add(playerKart);\n}\n\nfunction createCPUs() {\n\tcpuKarts = [];\n\tfor (let i = 0; i < NCPU; i++) {\n\t\tconst k = createKart(CPU_COL[i]);\n\t\tconst off = (i + 1) * 0.03,\n\t\t\tp = trackCurve.getPoint(off),\n\t\t\ttan = trackCurve.getTangent(off);\n\t\tconst r = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t\tconst lat = (i % 2 === 0 ? -1 : 1) * 3;\n\t\tk.position.copy(p);\n\t\tk.position.y = 0.22;\n\t\tk.position.add(r.clone().multiplyScalar(lat));\n\t\tcpuKarts.push({\n\t\t\tmesh: k,\n\t\t\ttrackT: off,\n\t\t\tspeed: 0,\n\t\t\ttargetSpeed: 28 + Math.random() * 10,\n\t\t\tlat,\n\t\t\tlap: 1,\n\t\t\tprevT: off,\n\t\t\tdone: false,\n\t\t\tfinishTime: 0,\n\t\t\twobble: Math.random() * Math.PI * 2,\n\t\t\tskill: 0.78 + Math.random() * 0.17\n\t\t});\n\t\tscene.add(k);\n\t}\n}\n\nfunction isTouchDevice() {\n\treturn ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (window.matchMedia('(pointer: coarse)').matches);\n}\n\nfunction setupInput() {\n\tconst prevent = ['Space', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];\n\twindow.addEventListener('keydown', e => {\n\t\tkeys[e.code] = true;\n\t\tif (prevent.includes(e.code)) e.preventDefault();\n\t\tensureAudio();\n\t});\n\twindow.addEventListener('keyup', e => {\n\t\tkeys[e.code] = false;\n\t});\n\twindow.addEventListener('click', ensureAudio);\n\twindow.addEventListener('touchstart', ensureAudio, {\n\t\tonce: true\n\t});\n\n\t// Mobile controls\n\tif (isTouchDevice()) {\n\t\tshowMobileControls();\n\t}\n\n\tsetupMobileButtons();\n\tsetupTiltButton();\n}\n\nfunction showMobileControls() {\n\tconst mc = document.getElementById('mobile-controls');\n\tif (mc) mc.classList.remove('hidden');\n}\n\nfunction hideMobileControls() {\n\tconst mc = document.getElementById('mobile-controls');\n\tif (mc) mc.classList.add('hidden');\n}\n\nconst activeTouches = new Map();\n\nfunction setupTiltButton() {\n\tconst btn = document.getElementById('btn-tilt');\n\tif (!btn) return;\n\tconst handler = (e) => {\n\t\te.preventDefault();\n\t\tensureAudio();\n\t\tplaySelect();\n\t\tif (tiltEnabled) {\n\t\t\tdisableTilt();\n\t\t} else {\n\t\t\tenableTilt();\n\t\t}\n\t};\n\tbtn.addEventListener('touchend', handler, {\n\t\tpassive: false\n\t});\n\tbtn.addEventListener('click', handler);\n\t// Long-press to recalibrate\n\tlet longPressTimer = null;\n\tbtn.addEventListener('touchstart', (e) => {\n\t\tlongPressTimer = setTimeout(() => {\n\t\t\tif (tiltEnabled) {\n\t\t\t\trecalibrateTilt();\n\t\t\t\tplayTone(880, 0.1, 'square', 0.08);\n\t\t\t\tsetTimeout(() => playTone(1100, 0.1, 'square', 0.06), 60);\n\t\t\t}\n\t\t}, 600);\n\t}, {\n\t\tpassive: true\n\t});\n\tbtn.addEventListener('touchend', () => clearTimeout(longPressTimer));\n\tbtn.addEventListener('touchcancel', () => clearTimeout(longPressTimer));\n}\n\nfunction setupMobileButtons() {\n\tconst allBtns = document.querySelectorAll('[data-key]');\n\n\tallBtns.forEach(btn => {\n\t\tconst keyCode = btn.dataset.key;\n\n\t\tbtn.addEventListener('touchstart', e => {\n\t\t\te.preventDefault();\n\t\t\tensureAudio();\n\t\t\tkeys[keyCode] = true;\n\t\t\tbtn.classList.add('dpad__btn--active', 'mobile-btn--active');\n\t\t\tfor (const touch of e.changedTouches) {\n\t\t\t\tactiveTouches.set(touch.identifier, {\n\t\t\t\t\tbtn,\n\t\t\t\t\tkeyCode\n\t\t\t\t});\n\t\t\t}\n\t\t}, {\n\t\t\tpassive: false\n\t\t});\n\n\t\tbtn.addEventListener('touchend', e => {\n\t\t\te.preventDefault();\n\t\t\tfor (const touch of e.changedTouches) {\n\t\t\t\tconst info = activeTouches.get(touch.identifier);\n\t\t\t\tif (info) {\n\t\t\t\t\tkeys[info.keyCode] = false;\n\t\t\t\t\tinfo.btn.classList.remove('dpad__btn--active', 'mobile-btn--active');\n\t\t\t\t\tactiveTouches.delete(touch.identifier);\n\t\t\t\t}\n\t\t\t}\n\t\t}, {\n\t\t\tpassive: false\n\t\t});\n\n\t\tbtn.addEventListener('touchcancel', e => {\n\t\t\tfor (const touch of e.changedTouches) {\n\t\t\t\tconst info = activeTouches.get(touch.identifier);\n\t\t\t\tif (info) {\n\t\t\t\t\tkeys[info.keyCode] = false;\n\t\t\t\t\tinfo.btn.classList.remove('dpad__btn--active', 'mobile-btn--active');\n\t\t\t\t\tactiveTouches.delete(touch.identifier);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n\n\t// Prevent context menu on long-press\n\tdocument.getElementById('mobile-controls')?.addEventListener('contextmenu', e => e.preventDefault());\n}\n\nfunction setupUI() {\n\tconst startHandler = () => {\n\t\tensureAudio();\n\t\tplaySelect();\n\t\tstartRace();\n\t};\n\tdocument.getElementById('btn-start').onclick = startHandler;\n\tdocument.getElementById('btn-start').ontouchend = (e) => {\n\t\te.preventDefault();\n\t\tstartHandler();\n\t};\n\tconst ctrlHandler = () => {\n\t\tensureAudio();\n\t\tplaySelect();\n\t\tdocument.getElementById('controls-info').classList.toggle('hidden');\n\t};\n\tdocument.getElementById('btn-controls').onclick = ctrlHandler;\n\tdocument.getElementById('btn-controls').ontouchend = (e) => {\n\t\te.preventDefault();\n\t\tctrlHandler();\n\t};\n\tconst restartHandler = () => {\n\t\tensureAudio();\n\t\tplaySelect();\n\t\tstartRace();\n\t};\n\tdocument.getElementById('btn-restart').onclick = restartHandler;\n\tdocument.getElementById('btn-restart').ontouchend = (e) => {\n\t\te.preventDefault();\n\t\trestartHandler();\n\t};\n\tconst menuHandler = () => {\n\t\tensureAudio();\n\t\tplaySelect();\n\t\tdocument.getElementById('finish-screen').classList.remove('active');\n\t\tdocument.getElementById('title-screen').classList.add('active');\n\t\tgameState = 'menu';\n\t};\n\tdocument.getElementById('btn-menu').onclick = menuHandler;\n\tdocument.getElementById('btn-menu').ontouchend = (e) => {\n\t\te.preventDefault();\n\t\tmenuHandler();\n\t};\n\n\tconst resetTrackHandler = () => {\n\t\tif (gameState !== 'racing' || pp.done) return;\n\t\tensureAudio();\n\t\tresetPlayerOnTrack();\n\t};\n\tdocument.getElementById('btn-reset-track').onclick = resetTrackHandler;\n\tdocument.getElementById('btn-reset-track').ontouchend = (e) => {\n\t\te.preventDefault();\n\t\tresetTrackHandler();\n\t};\n}\n\nfunction startRace() {\n\tdocument.getElementById('title-screen').classList.remove('active');\n\tdocument.getElementById('finish-screen').classList.remove('active');\n\tdocument.getElementById('hud').classList.remove('hidden');\n\tif (isTouchDevice()) showMobileControls();\n\tupdateTiltUI();\n\tpp.pos.copy(trackCurve.getPoint(0));\n\tpp.pos.y = 0.22;\n\tpp.vel.set(0, 0, 0);\n\tpp.speed = 0;\n\tpp.rot = Math.atan2(trackCurve.getTangent(0).x, trackCurve.getTangent(0).z);\n\tpp.trackT = 0;\n\tpp.prevT = 0;\n\tpp.lap = 1;\n\tpp.done = false;\n\tpp.spinTimer = 0;\n\tplayerLap = 1;\n\traceTime = 0;\n\tplayerBoostTimer = 0;\n\tcoinCount = 0;\n\tfuel = 1.0;\n\tfuelWarning = false;\n\tbumpCooldown = 0;\n\tdriftCharge = 0;\n\tlapTimes = [];\n\tlapStartTime = 0;\n\twrongWayTimer = 0;\n\titemMeshes.forEach(b => {\n\t\tb.userData.active = true;\n\t\tb.visible = true;\n\t\tb.userData.respawnTime = 0;\n\t});\n\tcpuKarts.forEach((c, i) => {\n\t\tconst off = (i + 1) * 0.03;\n\t\tc.trackT = off;\n\t\tc.prevT = off;\n\t\tc.speed = 0;\n\t\tc.lap = 1;\n\t\tc.done = false;\n\t\tc.finishTime = 0;\n\t});\n\tgameState = 'countdown';\n\tturboStartWindow = false;\n\tlet count = 3;\n\tconst el = document.getElementById('countdown');\n\tel.classList.remove('hidden');\n\tel.textContent = count;\n\tplayCountBeep(false);\n\tconst iv = setInterval(() => {\n\t\tcount--;\n\t\tif (count > 0) {\n\t\t\tel.textContent = count;\n\t\t\tel.style.animation = 'none';\n\t\t\tvoid el.offsetWidth;\n\t\t\tel.style.animation = 'countPop 0.5s cubic-bezier(0.34,1.56,0.64,1)';\n\t\t\tplayCountBeep(false);\n\t\t\tif (count === 1) turboStartWindow = true;\n\t\t} else if (count === 0) {\n\t\t\tel.textContent = 'GO!';\n\t\t\tel.style.color = '#2ecc71';\n\t\t\tel.style.animation = 'none';\n\t\t\tvoid el.offsetWidth;\n\t\t\tel.style.animation = 'countPop 0.5s cubic-bezier(0.34,1.56,0.64,1)';\n\t\t\tplayCountBeep(true);\n\t\t\tgameState = 'racing';\n\t\t\tlapStartTime = 0;\n\t\t\tif (turboStartWindow && keys.Space) {\n\t\t\t\tpp.speed = 45;\n\t\t\t\tplayerBoostTimer = 1.2;\n\t\t\t\tplayTurboStart();\n\t\t\t\tconst tp = document.getElementById('turbo-popup');\n\t\t\t\ttp.classList.remove('hidden');\n\t\t\t\tsetTimeout(() => tp.classList.add('hidden'), 1200);\n\t\t\t\tfor (let i = 0; i < 10; i++) spawnSpark(pp.pos.clone(), 0x00FF88);\n\t\t\t}\n\t\t\tturboStartWindow = false;\n\t\t} else {\n\t\t\tel.classList.add('hidden');\n\t\t\tel.style.color = '';\n\t\t\tclearInterval(iv);\n\t\t}\n\t}, 1000);\n}\n\nfunction updatePlayer(dt) {\n\tif (gameState !== 'racing' || pp.done) return;\n\tif (pp.spinTimer > 0) {\n\t\tpp.spinTimer -= dt;\n\t\tpp.speed *= Math.pow(0.92, dt * 60);\n\t\tpp.rot += 8 * dt;\n\t\tpp.pos.x += Math.sin(pp.rot) * pp.speed * dt * 0.3;\n\t\tpp.pos.z += Math.cos(pp.rot) * pp.speed * dt * 0.3;\n\t\tplayerKart.position.copy(pp.pos);\n\t\tplayerKart.rotation.y = pp.rot;\n\t\tplayerKart.rotation.z = Math.sin(raceTime * 20) * 0.3;\n\t\tplayerKart.rotation.x = Math.sin(raceTime * 15) * 0.15;\n\t\tconst ct = findT(pp.pos);\n\t\tpp.prevT = pp.trackT;\n\t\tpp.trackT = ct;\n\t\tconst tp = trackCurve.getPoint(ct);\n\t\tpp.pos.y = MathUtils.lerp(pp.pos.y, tp.y + 0.22, Math.min(1, dt * 14));\n\t\tcheckCollisions(dt);\n\t\treturn;\n\t}\n\tconst acc = keys.KeyW || keys.ArrowUp,\n\t\tbrk = keys.KeyS || keys.ArrowDown;\n\tlet lft = keys.KeyA || keys.ArrowLeft,\n\t\trgt = keys.KeyD || keys.ArrowRight;\n\t// Tilt steering override\n\tif (tiltEnabled) {\n\t\tif (keys.TiltLeft) lft = true;\n\t\tif (keys.TiltRight) rgt = true;\n\t}\n\tconst drf = keys.Space;\n\tconst maxSpd = 60,\n\t\taccel = 46,\n\t\tbrkF = 55,\n\t\tfric = 0.98,\n\t\tsteer = 3.4,\n\t\tdriftMul = 1.55;\n\t// Fuel consumption\n\tif (fuel > 0) {\n\t\tconst speedRatio = Math.min(Math.abs(pp.speed) / 60, 1);\n\t\tconst fuelRate = 0.002 + speedRatio * 0.02 + (playerBoostTimer > 0 ? 0.03 : 0);\n\t\tfuel = Math.max(0, fuel - fuelRate * dt);\n\t}\n\tconst fuelMult = fuel <= 0 ? 0.15 : fuel < 0.15 ? 0.4 + fuel * 4 : 1.0;\n\tif (acc) pp.speed += accel * fuelMult * dt;\n\tif (brk) pp.speed -= brkF * dt;\n\tpp.speed *= Math.pow(fric, dt * 60);\n\tif (fuel <= 0) {\n\t\tpp.speed *= Math.pow(0.94, dt * 60);\n\t\tif (Math.abs(pp.speed) < 0.5 && !pp.done) {\n\t\t\tpp.done = true;\n\t\t\tpp.speed = 0;\n\t\t\tfuelOutGameOver();\n\t\t\treturn;\n\t\t}\n\t\tif (pp.done) return;\n\t}\n\tif (playerBoostTimer > 0) pp.speed = Math.min(pp.speed, maxSpd + BOOST_STR + 5);\n\telse pp.speed = MathUtils.clamp(pp.speed, -15, maxSpd);\n\tconst sm = drf ? driftMul : 1,\n\t\tsf = Math.min(Math.abs(pp.speed) / 20, 1);\n\tif (tiltEnabled && (keys.TiltLeft || keys.TiltRight)) {\n\t\t// Proportional tilt steering\n\t\tconst tiltStr = keys.TiltStrength || 0;\n\t\tif (lft) pp.rot += steer * sm * sf * dt * tiltStr;\n\t\tif (rgt) pp.rot -= steer * sm * sf * dt * tiltStr;\n\t} else {\n\t\tif (lft) pp.rot += steer * sm * sf * dt;\n\t\tif (rgt) pp.rot -= steer * sm * sf * dt;\n\t}\n\tif (drf && Math.abs(pp.speed) > 5 && (lft || rgt)) {\n\t\tpp.speed *= Math.pow(0.97, dt * 60);\n\t\tpp.drift = true;\n\t\tdriftCharge = Math.min(1, driftCharge + dt * 0.8);\n\t\tif (Math.random() > 0.5) {\n\t\t\tconst sc = driftCharge < 0.33 ? 0x3399FF : driftCharge < 0.66 ? 0xFF8800 : 0xFF2266;\n\t\t\tconst sp = pp.pos.clone();\n\t\t\tsp.x += (Math.random() - 0.5) * 1.5;\n\t\t\tsp.z += (Math.random() - 0.5) * 1.5;\n\t\t\tspawnSpark(sp, sc);\n\t\t}\n\t} else if (pp.drift && !drf) {\n\t\tif (driftCharge > 0.2) {\n\t\t\tpp.speed += driftCharge * 22;\n\t\t\tplayerBoostTimer = Math.max(playerBoostTimer, driftCharge * 0.5);\n\t\t\tplayDriftBoost();\n\t\t\tfor (let i = 0; i < 8; i++) spawnSpark(pp.pos.clone(), driftCharge > 0.66 ? 0xFF2266 : 0xFF8800);\n\t\t\tconst bi = document.getElementById('boost-indicator');\n\t\t\tbi.textContent = driftCharge > 0.66 ? '⚡ MEGA BOOST! ⚡' : '⚡ DRIFT BOOST! ⚡';\n\t\t\tbi.classList.remove('hidden');\n\t\t\tsetTimeout(() => {\n\t\t\t\tbi.classList.add('hidden');\n\t\t\t\tbi.textContent = '⚡ BOOST! ⚡';\n\t\t\t}, 500);\n\t\t}\n\t\tpp.drift = false;\n\t\tdriftCharge = 0;\n\t} else {\n\t\tpp.drift = false;\n\t\tif (!drf) driftCharge = Math.max(0, driftCharge - dt * 2);\n\t}\n\tpp.pos.x += Math.sin(pp.rot) * pp.speed * dt;\n\tpp.pos.z += Math.cos(pp.rot) * pp.speed * dt;\n\tconst ct = findT(pp.pos),\n\t\ttp = trackCurve.getPoint(ct);\n\tpp.pos.y = MathUtils.lerp(pp.pos.y, tp.y + 0.22, Math.min(1, dt * 14));\n\tconst dtk = new Vector3(pp.pos.x, 0, pp.pos.z).distanceTo(new Vector3(tp.x, 0, tp.z));\n\tif (dtk > TW / 2 + 3) pp.speed *= Math.pow(0.9, dt * 60);\n\tif (dtk > TW / 2 + 15) {\n\t\tconst pd = new Vector3().subVectors(new Vector3(tp.x, 0, tp.z), new Vector3(pp.pos.x, 0, pp.pos.z)).normalize();\n\t\tpp.pos.x += pd.x * 0.5;\n\t\tpp.pos.z += pd.z * 0.5;\n\t\tpp.speed *= 0.9;\n\t}\n\tcheckBoosts(dt);\n\tcheckItemBoxes(dt);\n\tcheckCollisions(dt);\n\tplayerKart.position.copy(pp.pos);\n\tplayerKart.rotation.y = pp.rot;\n\tplayerKart.rotation.z = MathUtils.lerp(playerKart.rotation.z, (lft ? 1 : rgt ? -1 : 0) * 0.12 * sf, 0.12);\n\tplayerKart.rotation.x = MathUtils.lerp(playerKart.rotation.x || 0, 0, 0.1);\n\tconst ws = pp.speed * dt * 3;\n\tplayerKart.wheels.forEach(w => {\n\t\tw.children[0].rotation.x += ws;\n\t});\n\tif (playerKart.wheels[0]) playerKart.wheels[0].rotation.y = MathUtils.lerp(playerKart.wheels[0].rotation.y || 0, (lft ? 0.3 : rgt ? -0.3 : 0), 0.15);\n\tif (playerKart.wheels[1]) playerKart.wheels[1].rotation.y = MathUtils.lerp(playerKart.wheels[1].rotation.y || 0, (lft ? 0.3 : rgt ? -0.3 : 0), 0.15);\n\tplayerKart.position.y += Math.sin(raceTime * 14) * 0.008 * sf;\n\tif ((pp.drift || dtk > TW / 2 + 2) && Math.abs(pp.speed) > 8 && Math.random() > 0.5) spawnDust();\n\tif (Math.abs(pp.speed) > 5 && Math.random() > (playerBoostTimer > 0 ? 0.3 : 0.7)) spawnExhaust();\n\tif (Math.abs(pp.speed) > 35 && Math.random() > 0.6) spawnSpeedLine();\n\tif (playerBoostTimer > 0 && Math.random() > 0.4) spawnSpeedLine();\n\tengineTimer += dt;\n\tif (engineTimer > 0.06) {\n\t\tplayEngine(pp.speed);\n\t\tengineTimer = 0;\n\t}\n\tif (pp.drift) {\n\t\tdriftTimer += dt;\n\t\tif (driftTimer > 0.1) {\n\t\t\tplayDrift();\n\t\t\tdriftTimer = 0;\n\t\t}\n\t}\n\tconst prevT = pp.prevT;\n\tpp.prevT = pp.trackT;\n\tpp.trackT = ct;\n\tlet tDelta = pp.trackT - prevT;\n\tif (tDelta > 0.5) tDelta -= 1;\n\tif (tDelta < -0.5) tDelta += 1;\n\tif (tDelta < -0.005 && Math.abs(pp.speed) > 5) {\n\t\twrongWayTimer += dt;\n\t\tif (wrongWayTimer > 0.5) document.getElementById('wrong-way').classList.remove('hidden');\n\t} else {\n\t\twrongWayTimer = Math.max(0, wrongWayTimer - dt * 2);\n\t\tif (wrongWayTimer < 0.3) document.getElementById('wrong-way').classList.add('hidden');\n\t}\n\tif (pp.prevT > 0.9 && pp.trackT < 0.1) {\n\t\tpp.lap++;\n\t\tplayerLap = pp.lap;\n\t\tconst lt = raceTime - lapStartTime;\n\t\tlapTimes.push(lt);\n\t\tif (lt < bestLapTime) bestLapTime = lt;\n\t\tlapStartTime = raceTime;\n\t\tif (pp.lap > LAPS) {\n\t\t\tpp.done = true;\n\t\t\tfinishRace();\n\t\t} else {\n\t\t\tplayLap();\n\t\t\tshowLapPopup(pp.lap);\n\t\t}\n\t}\n\tif (pp.prevT < 0.1 && pp.trackT > 0.9) {\n\t\tpp.lap = Math.max(1, pp.lap - 1);\n\t\tplayerLap = pp.lap;\n\t}\n}\n\nfunction findT(pos) {\n\tlet best = 0,\n\t\tbd = Infinity;\n\tfor (let i = 0; i < 200; i++) {\n\t\tconst t = i / 200,\n\t\t\tp = trackCurve.getPoint(t);\n\t\tconst dx = pos.x - p.x,\n\t\t\tdz = pos.z - p.z;\n\t\tconst d = dx * dx + dz * dz;\n\t\tif (d < bd) {\n\t\t\tbd = d;\n\t\t\tbest = t;\n\t\t}\n\t}\n\tconst step = 1 / 200;\n\tfor (let i = -10; i <= 10; i++) {\n\t\tconst t = ((best + i * step / 10) % 1 + 1) % 1;\n\t\tconst p = trackCurve.getPoint(t);\n\t\tconst dx = pos.x - p.x,\n\t\t\tdz = pos.z - p.z;\n\t\tconst d = dx * dx + dz * dz;\n\t\tif (d < bd) {\n\t\t\tbd = d;\n\t\t\tbest = t;\n\t\t}\n\t}\n\treturn best;\n}\n\nfunction updateCPU(dt) {\n\tif (gameState !== 'racing') return;\n\tconst playerProgress = (pp.lap - 1) + pp.trackT;\n\tcpuKarts.forEach(c => {\n\t\tif (c.done) return;\n\t\tconst cpuP = (c.lap - 1) + c.trackT;\n\t\tlet rb = 1.0;\n\t\tconst diff = playerProgress - cpuP;\n\t\tif (diff > 0.2) rb = 1 + Math.min(diff * 0.6, 0.5);\n\t\telse if (diff < -0.15) rb = 1 - Math.min(Math.abs(diff) * 0.15, 0.1);\n\t\tc.speed = MathUtils.lerp(c.speed, c.targetSpeed * c.skill * rb, dt * 2.5);\n\t\tBOOST_T.forEach(bt => {\n\t\t\tif (Math.abs(c.trackT - bt) < 0.008) c.speed += 5 * dt * 60;\n\t\t});\n\t\tconst adv = (c.speed * dt) / trackCurve.getLength();\n\t\tc.prevT = c.trackT;\n\t\tc.trackT = (c.trackT + adv) % 1;\n\t\tif (c.prevT > 0.9 && c.trackT < 0.1) {\n\t\t\tc.lap++;\n\t\t\tif (c.lap > LAPS) {\n\t\t\t\tc.done = true;\n\t\t\t\tc.finishTime = raceTime;\n\t\t\t}\n\t\t}\n\t\tconst p = trackCurve.getPoint(c.trackT),\n\t\t\ttan = trackCurve.getTangent(c.trackT).normalize();\n\t\tconst rv = new Vector3().crossVectors(tan, new Vector3(0, 1, 0)).normalize();\n\t\tc.wobble += dt * 1.5;\n\t\tconst wb = Math.sin(c.wobble) * 2.5;\n\t\tconst tp = p.clone().add(rv.clone().multiplyScalar(c.lat + wb));\n\t\ttp.y += 0.22;\n\t\tc.mesh.position.lerp(tp, dt * 8);\n\t\tconst la = trackCurve.getPoint((c.trackT + 0.01) % 1);\n\t\tc.mesh.rotation.y = Math.atan2(la.x - c.mesh.position.x, la.z - c.mesh.position.z);\n\t\tconst sp = c.speed * dt * 3;\n\t\tc.mesh.wheels.forEach(w => {\n\t\t\tw.children[0].rotation.x += sp;\n\t\t});\n\t\tconst curv = getCurv(c.trackT);\n\t\tc.mesh.rotation.z = -curv * 0.18;\n\t\t// CPU slows slightly on tight curves but less than before\n\t\tif (Math.abs(curv) > 0.3) c.speed *= (1 - Math.abs(curv) * 0.015);\n\t\tc.mesh.position.y += Math.sin(raceTime * 10 + c.wobble) * 0.006;\n\t});\n}\n\nfunction getCurv(t) {\n\tconst d = 0.005,\n\t\tt1 = ((t - d) + 1) % 1,\n\t\tt2 = (t + d) % 1;\n\tconst p1 = trackCurve.getPoint(t1),\n\t\tp2 = trackCurve.getPoint(t),\n\t\tp3 = trackCurve.getPoint(t2);\n\tconst d1 = new Vector3().subVectors(p2, p1).normalize(),\n\t\td2 = new Vector3().subVectors(p3, p2).normalize();\n\treturn d1.x * d2.z - d1.z * d2.x;\n}\n\nfunction updateCam(dt) {\n\tconst speedFactor = Math.min(Math.abs(pp.speed) / 60, 1);\n\tconst cd = 10.5 + speedFactor * 1.5,\n\t\tch = 4.8 - speedFactor * 0.5,\n\t\tla = 6 + speedFactor * 3;\n\tconst targetFOV = 60 + speedFactor * 14 + (playerBoostTimer > 0 ? 10 : 0);\n\tcamera.fov = MathUtils.lerp(camera.fov, targetFOV, dt * 3.5);\n\tcamera.updateProjectionMatrix();\n\tconst tb = new Vector3(pp.pos.x - Math.sin(pp.rot) * cd, pp.pos.y + ch, pp.pos.z - Math.cos(pp.rot) * cd);\n\tcamera.position.lerp(tb, dt * 5.5);\n\tif (cameraShake > 0) {\n\t\tcameraShake *= Math.pow(0.9, dt * 60);\n\t\tif (cameraShake < 0.01) cameraShake = 0;\n\t\tcamera.position.x += (Math.random() - 0.5) * cameraShake;\n\t\tcamera.position.y += (Math.random() - 0.5) * cameraShake * 0.5;\n\t\tcamera.position.z += (Math.random() - 0.5) * cameraShake;\n\t}\n\tcamera.lookAt(new Vector3(pp.pos.x + Math.sin(pp.rot) * la, pp.pos.y + 1, pp.pos.z + Math.cos(pp.rot) * la));\n}\n\nfunction showLapPopup(lap) {\n\tconst el = document.getElementById('lap-popup');\n\tlet text = lap >= LAPS ? 'FINAL LAP!' : 'LAP ' + lap;\n\tif (lapTimes.length > 0) {\n\t\tconst lt = lapTimes[lapTimes.length - 1];\n\t\tconst m = Math.floor(lt / 60),\n\t\t\ts = (lt % 60).toFixed(2);\n\t\ttext += `  ${m}:${s.padStart(5,'0')}`;\n\t}\n\tel.textContent = text;\n\tel.style.color = lap >= LAPS ? '#FF4444' : '#FFFFFF';\n\tel.classList.remove('hidden');\n\tsetTimeout(() => el.classList.add('hidden'), 2000);\n}\n\nfunction updateHUD() {\n\tif (gameState !== 'racing' && gameState !== 'countdown') return;\n\tdocument.getElementById('hud-speed').textContent = Math.abs(Math.round(pp.speed * 3.6));\n\tdocument.getElementById('hud-lap').textContent = Math.min(pp.lap, LAPS);\n\tconst mds = 60 * 3.6;\n\tdocument.getElementById('speed-bar-fill').style.width = Math.min(100, (Math.abs(pp.speed) * 3.6 / mds) * 100) + '%';\n\tif (playerBoostTimer > 0) document.getElementById('speed-bar-boost').style.width = Math.max(0, Math.min(100, ((Math.abs(pp.speed) * 3.6 - mds) / (BOOST_STR * 3.6)) * 100)) + '%';\n\telse document.getElementById('speed-bar-boost').style.width = '0%';\n\tdocument.getElementById('drift-bar-fill').style.width = (driftCharge * 100) + '%';\n\tdocument.getElementById('hud-coins').textContent = coinCount;\n\t// Fuel gauge\n\tconst fuelPct = Math.round(fuel * 100);\n\tdocument.getElementById('fuel-bar-fill').style.width = fuelPct + '%';\n\tdocument.getElementById('fuel-pct').textContent = fuelPct + '%';\n\tif (fuel < 0.15 && fuel > 0) {\n\t\tif (!fuelWarning) {\n\t\t\tfuelWarning = true;\n\t\t\tdocument.getElementById('fuel-warning').classList.remove('hidden');\n\t\t}\n\t\tdocument.getElementById('fuel-bar-fill').style.background = 'linear-gradient(90deg, #ff2222, #ff4422)';\n\t} else if (fuel <= 0) {\n\t\tif (!fuelWarning) {\n\t\t\tfuelWarning = true;\n\t\t\tdocument.getElementById('fuel-warning').classList.remove('hidden');\n\t\t}\n\t\tdocument.getElementById('fuel-warning').textContent = '⛽ EMPTY! ⛽';\n\t\tdocument.getElementById('fuel-bar-fill').style.background = '#ff0000';\n\t} else {\n\t\tif (fuelWarning) {\n\t\t\tfuelWarning = false;\n\t\t\tdocument.getElementById('fuel-warning').classList.add('hidden');\n\t\t\tdocument.getElementById('fuel-warning').textContent = '⛽ LOW FUEL! ⛽';\n\t\t}\n\t\tdocument.getElementById('fuel-bar-fill').style.background = 'linear-gradient(90deg, #ff4422, #ff8844, #44cc44)';\n\t}\n\tconst pos = getPos();\n\tdocument.getElementById('hud-position').textContent = pos;\n\tdocument.getElementById('hud-suffix').textContent = ['st', 'nd', 'rd', 'th', 'th', 'th'][pos - 1];\n\tconst posEl = document.getElementById('hud-position').parentElement;\n\tif (pos === 1) posEl.style.borderColor = '#FFD700';\n\telse if (pos <= 3) posEl.style.borderColor = '#f5a623';\n\telse posEl.style.borderColor = '#ff4444';\n\tconst m = Math.floor(raceTime / 60),\n\t\ts = Math.floor(raceTime % 60),\n\t\tt = Math.floor((raceTime * 10) % 10);\n\tdocument.getElementById('hud-timer').textContent = `${m}:${String(s).padStart(2,'0')}.${t}`;\n\tdrawMinimap();\n}\n\nfunction getPos() {\n\tconst ps = (pp.lap - 1) + pp.trackT;\n\tlet pos = 1;\n\tcpuKarts.forEach(c => {\n\t\tif ((c.lap - 1) + c.trackT > ps) pos++;\n\t});\n\treturn pos;\n}\n\nfunction drawMinimap() {\n\tconst cv = document.getElementById('minimapCanvas'),\n\t\tcx = cv.getContext('2d'),\n\t\tw = cv.width,\n\t\th = cv.height;\n\tcx.clearRect(0, 0, w, h);\n\tcx.fillStyle = 'rgba(0, 0, 0, 0.15)';\n\tcx.fillRect(0, 0, w, h);\n\tconst pad = 12;\n\tlet mnX = 1e9,\n\t\tmxX = -1e9,\n\t\tmnZ = 1e9,\n\t\tmxZ = -1e9;\n\tfor (let t = 0; t < 1; t += 0.01) {\n\t\tconst p = trackCurve.getPoint(t);\n\t\tmnX = Math.min(mnX, p.x);\n\t\tmxX = Math.max(mxX, p.x);\n\t\tmnZ = Math.min(mnZ, p.z);\n\t\tmxZ = Math.max(mxZ, p.z);\n\t}\n\tconst rX = mxX - mnX,\n\t\trZ = mxZ - mnZ,\n\t\tsc = Math.min((w - pad * 2) / rX, (h - pad * 2) / rZ);\n\tconst oX = (w - rX * sc) / 2,\n\t\toZ = (h - rZ * sc) / 2;\n\tconst mx = x => oX + (x - mnX) * sc,\n\t\tmz = z => oZ + (z - mnZ) * sc;\n\tcx.strokeStyle = 'rgba(255,255,255,0.08)';\n\tcx.lineWidth = 7;\n\tcx.beginPath();\n\tfor (let t = 0; t <= 1; t += 0.005) {\n\t\tconst p = trackCurve.getPoint(t);\n\t\tt === 0 ? cx.moveTo(mx(p.x), mz(p.z)) : cx.lineTo(mx(p.x), mz(p.z));\n\t}\n\tcx.closePath();\n\tcx.stroke();\n\tcx.strokeStyle = 'rgba(255,255,255,0.25)';\n\tcx.lineWidth = 4;\n\tcx.beginPath();\n\tfor (let t = 0; t <= 1; t += 0.005) {\n\t\tconst p = trackCurve.getPoint(t);\n\t\tt === 0 ? cx.moveTo(mx(p.x), mz(p.z)) : cx.lineTo(mx(p.x), mz(p.z));\n\t}\n\tcx.closePath();\n\tcx.stroke();\n\tcx.fillStyle = '#F80';\n\tBOOST_T.forEach(bt => {\n\t\tconst p = trackCurve.getPoint(bt);\n\t\tcx.fillRect(mx(p.x) - 2, mz(p.z) - 2, 4, 4);\n\t});\n\tcx.fillStyle = '#FFD700';\n\tITEM_T.forEach(it => {\n\t\tconst p = trackCurve.getPoint(it);\n\t\tcx.fillRect(mx(p.x) - 2, mz(p.z) - 2, 4, 4);\n\t});\n\tcpuKarts.forEach((c, i) => {\n\t\tcx.fillStyle = '#' + CPU_COL[i].toString(16).padStart(6, '0');\n\t\tcx.beginPath();\n\t\tcx.arc(mx(c.mesh.position.x), mz(c.mesh.position.z), 3, 0, Math.PI * 2);\n\t\tcx.fill();\n\t});\n\tcx.fillStyle = '#e33';\n\tcx.strokeStyle = '#fff';\n\tcx.lineWidth = 2;\n\tcx.beginPath();\n\tcx.arc(mx(pp.pos.x), mz(pp.pos.z), 4, 0, Math.PI * 2);\n\tcx.fill();\n\tcx.stroke();\n\tconst al = 8,\n\t\tax = mx(pp.pos.x) + Math.sin(pp.rot) * al * sc * 0.08,\n\t\taz = mz(pp.pos.z) + Math.cos(pp.rot) * al * sc * 0.08;\n\tcx.strokeStyle = '#fff';\n\tcx.lineWidth = 2;\n\tcx.beginPath();\n\tcx.moveTo(mx(pp.pos.x), mz(pp.pos.z));\n\tcx.lineTo(ax, az);\n\tcx.stroke();\n}\n\nfunction finishRace() {\n\tgameState = 'finished';\n\tconst pos = getPos(),\n\t\tsf = ['1st', '2nd', '3rd', '4th', '5th', '6th'];\n\tdocument.getElementById('finish-position').textContent = sf[pos - 1];\n\tdocument.getElementById('finish-position').style.background = '';\n\tdocument.getElementById('finish-position').style.webkitBackgroundClip = '';\n\tdocument.getElementById('finish-position').style.backgroundClip = '';\n\tdocument.getElementById('finish-title').textContent = 'FINISH!';\n\tdocument.getElementById('finish-flag').textContent = '🏁';\n\tconst m = Math.floor(raceTime / 60),\n\t\ts = (raceTime % 60).toFixed(2);\n\tdocument.getElementById('finish-time').textContent = `TIME ${m}:${s.padStart(5,'0')}`;\n\tlet html = `POSITION: ${sf[pos-1]}<br>FUEL PICKUPS: ${coinCount}<br>FUEL LEFT: ${Math.round(fuel*100)}%<br>`;\n\tlapTimes.forEach((lt, i) => {\n\t\tconst lm = Math.floor(lt / 60),\n\t\t\tls = (lt % 60).toFixed(2);\n\t\thtml += `LAP ${i+1}: ${lm}:${ls.padStart(5,'0')}`;\n\t\tif (lt === bestLapTime && bestLapTime < Infinity) html += ' ★';\n\t\thtml += '<br>';\n\t});\n\tif (bestLapTime < Infinity) {\n\t\tconst bm = Math.floor(bestLapTime / 60),\n\t\t\tbs = (bestLapTime % 60).toFixed(2);\n\t\thtml += `BEST: ${bm}:${bs.padStart(5,'0')}<br>`;\n\t}\n\thtml += (pos === 1 ? '★ WINNER! ★' : 'TRY FOR 1ST!');\n\tdocument.getElementById('finish-stats').innerHTML = html;\n\tplayFinish();\n\tsetTimeout(() => {\n\t\tdocument.getElementById('hud').classList.add('hidden');\n\t\tdocument.getElementById('finish-screen').classList.add('active');\n\t\thideMobileControls();\n\t}, 1500);\n}\n\nfunction fuelOutGameOver() {\n\ttry {\n\t\tgameState = 'finished';\n\t\tpp.done = true;\n\t\tpp.speed = 0;\n\t\tpp.spinTimer = 0;\n\t\tplayBump();\n\t\tsetTimeout(() => {\n\t\t\ttry {\n\t\t\t\tplayTone(220, 0.3, 'sawtooth', 0.1);\n\t\t\t} catch (e) {}\n\t\t}, 200);\n\t\tsetTimeout(() => {\n\t\t\ttry {\n\t\t\t\tplayTone(165, 0.4, 'sawtooth', 0.08);\n\t\t\t} catch (e) {}\n\t\t}, 400);\n\t\tsetTimeout(() => {\n\t\t\ttry {\n\t\t\t\tgameState = 'menu';\n\t\t\t\tdocument.getElementById('hud').classList.add('hidden');\n\t\t\t\tdocument.getElementById('finish-screen').classList.remove('active');\n\t\t\t\tdocument.getElementById('title-screen').classList.add('active');\n\t\t\t\thideMobileControls();\n\t\t\t\t// Reset fuel and state for next race\n\t\t\t\tfuel = 1.0;\n\t\t\t\tfuelWarning = false;\n\t\t\t\tconst fwEl = document.getElementById('fuel-warning');\n\t\t\t\tif (fwEl) {\n\t\t\t\t\tfwEl.classList.add('hidden');\n\t\t\t\t\tfwEl.textContent = '⛽ LOW FUEL! ⛽';\n\t\t\t\t}\n\t\t\t\tconst fbFill = document.getElementById('fuel-bar-fill');\n\t\t\t\tif (fbFill) {\n\t\t\t\t\tfbFill.style.width = '100%';\n\t\t\t\t\tfbFill.style.background = 'linear-gradient(90deg, #ff4422, #ff8844, #44cc44)';\n\t\t\t\t}\n\t\t\t\tconst fpEl = document.getElementById('fuel-pct');\n\t\t\t\tif (fpEl) fpEl.textContent = '100%';\n\t\t\t} catch (e) {\n\t\t\t\tconsole.warn('fuelOutGameOver cleanup error:', e);\n\t\t\t}\n\t\t}, 1500);\n\t} catch (e) {\n\t\tconsole.warn('fuelOutGameOver error:', e);\n\t\tgameState = 'menu';\n\t}\n}\n\nlet boostAnim = 0,\n\tlastTime = 0;\n\nfunction animate(time = 0) {\n\trequestAnimationFrame(animate);\n\tconst dt = Math.min((time - lastTime) / 1000, 0.05);\n\tlastTime = time;\n\tif (gameState === 'racing') {\n\t\traceTime += dt;\n\t\tupdatePlayer(dt);\n\t\tupdateCPU(dt);\n\t}\n\tupdateDust(dt);\n\tupdateSparks(dt);\n\tupdateExhaust(dt);\n\tupdateSpeedLines(dt);\n\titemMeshes.forEach(b => {\n\t\tif (b.userData.active) {\n\t\t\tb.rotation.y += dt * 1.8;\n\t\t\tb.position.y = trackCurve.getPoint(b.userData.trackT).y + 2.0 + Math.sin(time * 0.003 + b.userData.trackT * 10) * 0.25;\n\t\t\t// Pulse glow when player fuel is low\n\t\t\tif (fuel < 0.3) {\n\t\t\t\tconst pulseScale = 1.0 + Math.sin(time * 0.008) * 0.12;\n\t\t\t\tb.scale.setScalar(pulseScale);\n\t\t\t} else {\n\t\t\t\tb.scale.setScalar(1.0);\n\t\t\t}\n\t\t}\n\t});\n\tboostAnim += dt;\n\tboostMeshes.forEach((p, i) => {\n\t\tconst pulse = 0.2 + Math.sin(boostAnim * 5 + i * 1.5) * 0.15;\n\t\tif (p.material.emissiveIntensity < 1) p.material.emissiveIntensity = pulse;\n\t});\n\tclouds.forEach(cl => {\n\t\tcl.position.x += (cl.userData.speed || 1) * dt * 0.3;\n\t\tif (cl.position.x > 300) cl.position.x = -300;\n\t});\n\tif (waterMesh) {\n\t\twaterMesh.material.map.offset.x = Math.sin(time * 0.0002) * 0.15;\n\t\twaterMesh.material.map.offset.y = time * 0.00004;\n\t\twaterMesh.position.y = -3 + Math.sin(time * 0.0008) * 0.2;\n\t}\n\tif (sunMesh) {\n\t\tsunMesh.lookAt(camera.position);\n\t\tif (typeof sunGlows !== 'undefined') sunGlows.forEach(g => g.lookAt(camera.position));\n\t}\n\tif (gameState === 'racing' || gameState === 'countdown') {\n\t\tupdateCam(dt);\n\t\tupdateHUD();\n\t\tif (tiltEnabled) {\n\t\t\tconst indicator = document.getElementById('tilt-indicator');\n\t\t\tif (indicator && indicator.classList.contains('hidden')) indicator.classList.remove('hidden');\n\t\t}\n\t} else if (gameState === 'finished') {\n\t\ttry {\n\t\t\tupdateCam(dt);\n\t\t} catch (e) {}\n\t\ttry {\n\t\t\tupdateHUD();\n\t\t} catch (e) {}\n\t}\n\trenderer.render(scene, camera);\n}\n\nfunction onResize() {\n\tcamera.aspect = innerWidth / innerHeight;\n\tcamera.updateProjectionMatrix();\n\trenderer.setSize(innerWidth, innerHeight, false);\n}\n\ninit();"},{"name":"style.css","content":"@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');\n@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&display=swap');\n\n:root {\n\tcolor-scheme: light;\n\t--clr-primary: #e8432a;\n\t--clr-secondary: #f5a623;\n\t--clr-accent: #3498db;\n\t--clr-white: #fff8f0;\n\t--clr-dark: #1a1a2e;\n\tfont-family: 'Press Start 2P', monospace;\n}\n\n* {\n\tbox-sizing: border-box;\n\tmargin: 0;\n\tpadding: 0;\n}\n\nhtml, body {\n\toverflow: hidden;\n\theight: 100%;\n\twidth: 100%;\n}\n\n#game-container {\n\tposition: relative;\n\twidth: 100vw;\n\theight: 100vh;\n\toverflow: hidden;\n\tbackground: #000;\n}\n\n#gameCanvas {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tdisplay: block;\n\timage-rendering: auto;\n\tfilter: contrast(1.05) saturate(1.12);\n}\n\n#scanlines {\n\tposition: absolute;\n\tinset: 0;\n\tz-index: 45;\n\tpointer-events: none;\n\tbackground: none;\n}\n\n#scanlines::after {\n\tcontent: '';\n\tposition: absolute;\n\tinset: 0;\n\tbackground: radial-gradient(ellipse at center, transparent 75%, rgba(0, 0, 0, 0.06) 100%);\n}\n\n.screen {\n\tposition: absolute;\n\tinset: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tz-index: 100;\n\ttransition: opacity 0.5s ease, visibility 0.5s;\n\tpointer-events: none;\n\topacity: 0;\n\tvisibility: hidden;\n\tbackground: radial-gradient(ellipse at 50% 40%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.8) 100%);\n\tbackdrop-filter: blur(6px);\n\t-webkit-backdrop-filter: blur(6px);\n}\n\n.screen.active {\n\topacity: 1;\n\tvisibility: visible;\n\tpointer-events: all;\n}\n\n.title-content {\n\ttext-align: center;\n\tanimation: fadeSlideIn 0.8s cubic-bezier(0.22, 1, 0.36, 1);\n\tbackground: linear-gradient(135deg, rgba(15, 15, 45, 0.85) 0%, rgba(25, 25, 60, 0.75) 100%);\n\tborder: 2px solid rgba(255, 255, 255, 0.12);\n\tpadding: 2.5rem 3rem;\n\tborder-radius: 32px;\n\tbox-shadow: 0 30px 80px rgba(0, 0, 0, 0.6), 0 10px 30px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -1px 0 rgba(0, 0, 0, 0.2);\n\tbackdrop-filter: blur(24px) saturate(180%);\n\t-webkit-backdrop-filter: blur(24px) saturate(180%);\n\tmax-width: 90vw;\n\tposition: relative;\n\toverflow: hidden;\n}\n\n.title-content::before {\n\tcontent: '';\n\tposition: absolute;\n\ttop: -50%;\n\tleft: -50%;\n\twidth: 200%;\n\theight: 200%;\n\tbackground: conic-gradient(from 0deg, transparent, rgba(255, 100, 50, 0.03), transparent, rgba(100, 150, 255, 0.03), transparent);\n\tanimation: rotateBg 12s linear infinite;\n\tpointer-events: none;\n}\n\n.retro-badge {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: clamp(0.5rem, 1.4vw, 0.75rem);\n\tfont-weight: 700;\n\tcolor: transparent;\n\tbackground: linear-gradient(90deg, #f5a623, #ff6b35, #f5a623);\n\tbackground-size: 200% 100%;\n\t-webkit-background-clip: text;\n\tbackground-clip: text;\n\tletter-spacing: 5px;\n\tmargin-bottom: 0.8rem;\n\tanimation: shimmer 3s ease infinite;\n\tposition: relative;\n}\n\n.game-title {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: clamp(1.8rem, 6vw, 4rem);\n\tfont-weight: 900;\n\tcolor: transparent;\n\tbackground: linear-gradient(180deg, #ffffff 0%, #ffccaa 40%, #ff6633 100%);\n\t-webkit-background-clip: text;\n\tbackground-clip: text;\n\tmargin-bottom: 0.15em;\n\tline-height: 1.2;\n\tfilter: drop-shadow(0 4px 8px rgba(255, 80, 30, 0.4)) drop-shadow(0 0 30px rgba(255, 100, 50, 0.15));\n\tletter-spacing: -1px;\n\tposition: relative;\n}\n\n.game-subtitle {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: clamp(0.5rem, 1.8vw, 0.85rem);\n\tfont-weight: 400;\n\tcolor: rgba(255, 220, 180, 0.7);\n\ttext-shadow: 0 0 20px rgba(255, 150, 80, 0.2);\n\tmargin-bottom: 1.2rem;\n\tletter-spacing: 5px;\n}\n\n.controls-hint {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: clamp(0.35rem, 1vw, 0.5rem);\n\tcolor: rgba(255, 255, 255, 0.35);\n\tmargin-bottom: 1.8rem;\n\tletter-spacing: 3px;\n\tanimation: pulse 2.5s ease infinite;\n}\n\n.menu-buttons {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 0.7rem;\n}\n\n.menu-btn {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-weight: 700;\n\tfont-size: clamp(0.6rem, 1.6vw, 0.85rem);\n\tpadding: 1em 2.5em;\n\tborder: 2px solid rgba(255, 100, 80, 0.4);\n\tborder-radius: 16px;\n\tbackground: linear-gradient(135deg, rgba(255, 70, 50, 0.95) 0%, rgba(232, 67, 42, 0.95) 50%, rgba(200, 40, 20, 0.95) 100%);\n\tcolor: var(--clr-white);\n\tcursor: pointer;\n\ttext-shadow: 0 2px 6px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.3);\n\tbox-shadow: 0 6px 20px rgba(232, 67, 42, 0.4), 0 2px 8px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2), inset 0 -2px 0 rgba(0, 0, 0, 0.15);\n\ttransition: all 0.3s cubic-bezier(0.22, 1, 0.36, 1);\n\tletter-spacing: 1.5px;\n\tposition: relative;\n\toverflow: hidden;\n}\n\n.menu-btn::before {\n\tcontent: '';\n\tposition: absolute;\n\ttop: 0;\n\tleft: -100%;\n\twidth: 100%;\n\theight: 100%;\n\tbackground: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);\n\ttransition: left 0.5s;\n}\n\n.menu-btn:hover::before {\n\tleft: 100%;\n}\n\n.menu-btn:hover {\n\ttransform: translateY(-4px) scale(1.02);\n\tbox-shadow: 0 10px 35px rgba(232, 67, 42, 0.55), 0 4px 15px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.25);\n\tbackground: linear-gradient(135deg, rgba(255, 100, 70, 1) 0%, rgba(255, 85, 51, 0.98) 50%, rgba(232, 67, 42, 0.98) 100%);\n\tborder-color: rgba(255, 150, 100, 0.6);\n}\n\n.menu-btn:active {\n\ttransform: translateY(1px);\n\tbox-shadow: 0 2px 8px rgba(232, 67, 42, 0.3);\n}\n\n.menu-btn--secondary {\n\tbackground: linear-gradient(135deg, rgba(60, 170, 240, 0.9) 0%, rgba(52, 152, 219, 0.92) 50%, rgba(41, 128, 185, 0.92) 100%);\n\tfont-size: clamp(0.5rem, 1.2vw, 0.65rem);\n\tbox-shadow: 0 5px 18px rgba(52, 152, 219, 0.35), 0 2px 6px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.15), inset 0 -2px 0 rgba(0, 0, 0, 0.1);\n\tborder-color: rgba(80, 180, 240, 0.4);\n}\n\n.menu-btn--secondary:hover {\n\tbackground: linear-gradient(135deg, rgba(90, 190, 255, 0.95) 0%, rgba(74, 168, 232, 0.95) 50%, rgba(52, 152, 219, 0.95) 100%);\n\tbox-shadow: 0 9px 30px rgba(52, 152, 219, 0.5), 0 4px 12px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.2);\n\tborder-color: rgba(120, 200, 255, 0.5);\n}\n\n.controls-info {\n\tmargin-top: 1.2rem;\n\tbackground: linear-gradient(135deg, rgba(10, 10, 30, 0.7) 0%, rgba(20, 20, 45, 0.6) 100%);\n\tborder: 1.5px solid rgba(255, 255, 255, 0.12);\n\tpadding: 1.2rem 1.6rem;\n\tborder-radius: 18px;\n\tbackdrop-filter: blur(16px) saturate(150%);\n\t-webkit-backdrop-filter: blur(16px) saturate(150%);\n\tbox-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.08);\n}\n\n.controls-info p {\n\tcolor: rgba(255, 255, 255, 0.75);\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: 0.45rem;\n\tmargin: 0.4em 0;\n\tline-height: 2;\n}\n\n.controls-info kbd {\n\tdisplay: inline-block;\n\tbackground: linear-gradient(135deg, rgba(255, 180, 50, 0.95), rgba(245, 166, 35, 0.9));\n\tcolor: #fff;\n\tpadding: 0.3em 0.6em;\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: 0.4rem;\n\tfont-weight: 700;\n\tmin-width: 1.8em;\n\ttext-align: center;\n\tmargin-right: 0.4em;\n\tborder: 1.5px solid rgba(255, 200, 80, 0.4);\n\tborder-radius: 6px;\n\tbox-shadow: 0 3px 8px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2);\n}\n\n.hidden {\n\tdisplay: none !important;\n}\n\n/* Mobile Controls */\n.mobile-controls {\n\tposition: absolute;\n\tbottom: 0;\n\tleft: 0;\n\tright: 0;\n\tz-index: 60;\n\tpointer-events: none;\n\tpadding: 0.8rem;\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: flex-end;\n\tpadding-bottom: max(0.8rem, env(safe-area-inset-bottom));\n}\n\n.mobile-controls__left,\n.mobile-controls__right {\n\tpointer-events: all;\n\tdisplay: flex;\n\tgap: 10px;\n\talign-items: flex-end;\n}\n\n.mobile-controls__center {\n\tpointer-events: all;\n\tposition: absolute;\n\tbottom: calc(100% + 12px);\n\tleft: 50%;\n\ttransform: translateX(-50%);\n}\n\n.mobile-btn--tilt {\n\twidth: clamp(50px, 14vw, 70px);\n\theight: clamp(50px, 14vw, 70px);\n\tborder-radius: 50%;\n\tfont-size: clamp(1rem, 3.5vw, 1.4rem);\n\tbackground: rgba(80, 80, 120, 0.5);\n\tborder-color: rgba(150, 150, 220, 0.4);\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n\tline-height: 1;\n\ttransition: background 0.2s, border-color 0.2s, box-shadow 0.2s;\n}\n\n.mobile-btn--tilt.tilt-active {\n\tbackground: rgba(34, 170, 220, 0.55);\n\tborder-color: rgba(34, 200, 255, 0.7);\n\tbox-shadow: 0 0 15px rgba(34, 200, 255, 0.3), inset 0 0 8px rgba(34, 200, 255, 0.15);\n}\n\n.mobile-btn--tilt .mobile-btn__label {\n\tfont-size: clamp(0.3rem, 1vw, 0.4rem);\n\tmargin-top: 2px;\n\topacity: 0.7;\n\tletter-spacing: 1px;\n}\n\n.tilt-indicator {\n\tposition: absolute;\n\tbottom: calc(max(0.8rem, env(safe-area-inset-bottom)) + clamp(70px, 20vw, 100px) + 80px);\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tpointer-events: none;\n\tz-index: 61;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tbackground: linear-gradient(135deg, rgba(10, 10, 30, 0.7) 0%, rgba(15, 15, 35, 0.65) 100%);\n\tpadding: 6px 14px;\n\tborder-radius: 24px;\n\tborder: 2px solid rgba(34, 200, 255, 0.35);\n\tbackdrop-filter: blur(10px) saturate(140%);\n\t-webkit-backdrop-filter: blur(10px) saturate(140%);\n\tbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n\n.tilt-indicator__bar {\n\twidth: 90px;\n\theight: 8px;\n\tbackground: linear-gradient(135deg, rgba(20, 20, 40, 0.8) 0%, rgba(10, 10, 25, 0.9) 100%);\n\tborder-radius: 6px;\n\tposition: relative;\n\toverflow: hidden;\n\tborder: 1px solid rgba(255, 255, 255, 0.15);\n\tbox-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.5);\n}\n\n.tilt-indicator__dot {\n\tposition: absolute;\n\ttop: -1px;\n\tleft: 50%;\n\twidth: 10px;\n\theight: 10px;\n\tbackground: linear-gradient(135deg, #66eeff, #44ddff);\n\tborder-radius: 50%;\n\ttransform: translateX(-50%);\n\ttransition: left 0.08s ease-out;\n\tbox-shadow: 0 0 10px rgba(68, 221, 255, 0.7), 0 0 20px rgba(68, 221, 255, 0.4), inset 0 1px 2px rgba(255, 255, 255, 0.5);\n\tborder: 1px solid rgba(255, 255, 255, 0.3);\n}\n\n.tilt-indicator__label {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: 0.35rem;\n\tcolor: rgba(255, 255, 255, 0.5);\n\tletter-spacing: 1px;\n}\n\n.mobile-btn {\n\tfont-family: 'Press Start 2P', monospace;\n\tborder: 3px solid rgba(255, 255, 255, 0.45);\n\tbackground: linear-gradient(135deg, rgba(20, 20, 40, 0.75) 0%, rgba(10, 10, 25, 0.8) 100%);\n\tbackdrop-filter: blur(10px) saturate(140%);\n\t-webkit-backdrop-filter: blur(10px) saturate(140%);\n\tcolor: rgba(255, 255, 255, 0.9);\n\tcursor: pointer;\n\t-webkit-tap-highlight-color: transparent;\n\ttouch-action: manipulation;\n\tuser-select: none;\n\t-webkit-user-select: none;\n\ttransition: all 0.08s ease;\n\tbox-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.15), inset 0 -2px 0 rgba(0, 0, 0, 0.3);\n\ttext-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);\n}\n\n.mobile-btn:active,\n.mobile-btn--active {\n\tbackground: linear-gradient(135deg, rgba(80, 80, 120, 0.8) 0%, rgba(60, 60, 100, 0.85) 100%);\n\tborder-color: rgba(255, 255, 255, 0.7);\n\tbox-shadow: 0 2px 6px rgba(0, 0, 0, 0.3), inset 0 2px 6px rgba(0, 0, 0, 0.4);\n\ttransform: scale(0.96);\n}\n\n.mobile-btn--steer {\n\twidth: clamp(60px, 16vw, 85px);\n\theight: clamp(70px, 20vw, 100px);\n\tborder-radius: 14px;\n\tfont-size: clamp(1rem, 4vw, 1.6rem);\n}\n\n.mobile-btn--accel {\n\twidth: clamp(60px, 16vw, 85px);\n\theight: clamp(70px, 20vw, 100px);\n\tborder-radius: 14px;\n\tfont-size: clamp(0.8rem, 3vw, 1.2rem);\n\tbackground: linear-gradient(135deg, rgba(40, 200, 40, 0.7) 0%, rgba(34, 170, 34, 0.75) 100%);\n\tbackdrop-filter: blur(10px);\n\t-webkit-backdrop-filter: blur(10px);\n\tborder-color: rgba(60, 240, 60, 0.6);\n\tbox-shadow: 0 4px 16px rgba(34, 170, 34, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2), inset 0 -2px 0 rgba(0, 0, 0, 0.3);\n}\n\n.mobile-btn--accel:active,\n.mobile-btn--accel.mobile-btn--active {\n\tbackground: linear-gradient(135deg, rgba(50, 240, 50, 0.85) 0%, rgba(40, 200, 40, 0.9) 100%);\n\tborder-color: #44FF44;\n\tbox-shadow: 0 2px 8px rgba(34, 220, 34, 0.4), inset 0 2px 8px rgba(0, 0, 0, 0.3), 0 0 15px rgba(34, 220, 34, 0.3);\n}\n\n.mobile-btn--brake {\n\twidth: clamp(60px, 16vw, 85px);\n\theight: clamp(70px, 20vw, 100px);\n\tborder-radius: 14px;\n\tfont-size: clamp(0.8rem, 3vw, 1.2rem);\n\tbackground: linear-gradient(135deg, rgba(220, 50, 50, 0.7) 0%, rgba(200, 40, 40, 0.75) 100%);\n\tbackdrop-filter: blur(10px);\n\t-webkit-backdrop-filter: blur(10px);\n\tborder-color: rgba(240, 70, 70, 0.6);\n\tbox-shadow: 0 4px 16px rgba(200, 40, 40, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2), inset 0 -2px 0 rgba(0, 0, 0, 0.3);\n}\n\n.mobile-btn--brake:active,\n.mobile-btn--brake.mobile-btn--active {\n\tbackground: linear-gradient(135deg, rgba(255, 70, 70, 0.85) 0%, rgba(220, 50, 50, 0.9) 100%);\n\tborder-color: #FF4444;\n\tbox-shadow: 0 2px 8px rgba(220, 50, 50, 0.4), inset 0 2px 8px rgba(0, 0, 0, 0.3), 0 0 15px rgba(220, 50, 50, 0.3);\n}\n\n.mobile-btn__label {\n\tdisplay: block;\n\tfont-size: clamp(0.3rem, 1.2vw, 0.45rem);\n\tmargin-top: 4px;\n\topacity: 0.6;\n}\n\n.hud {\n\tposition: absolute;\n\tinset: 0;\n\tz-index: 50;\n\tpointer-events: none;\n\tpadding: 0.6rem;\n}\n\n.hud__top {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: flex-start;\n\tposition: relative;\n}\n\n.hud__reset-btn {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tmargin-top: 2.2rem;\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-weight: 700;\n\tfont-size: clamp(0.4rem, 1.1vw, 0.55rem);\n\tpadding: 0.5em 1.3em;\n\tborder: 2px solid rgba(255, 255, 255, 0.3);\n\tborder-radius: 12px;\n\tbackground: linear-gradient(135deg, rgba(15, 15, 35, 0.8) 0%, rgba(20, 20, 45, 0.75) 100%);\n\tbackdrop-filter: blur(12px) saturate(140%);\n\t-webkit-backdrop-filter: blur(12px) saturate(140%);\n\tcolor: rgba(255, 255, 255, 0.9);\n\tcursor: pointer;\n\tpointer-events: all;\n\ttransition: all 0.3s cubic-bezier(0.22, 1, 0.36, 1);\n\tz-index: 55;\n\tletter-spacing: 1.2px;\n\tbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.15), inset 0 -2px 0 rgba(0, 0, 0, 0.2);\n\t-webkit-tap-highlight-color: transparent;\n\ttouch-action: manipulation;\n\ttext-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);\n}\n\n.hud__reset-btn:hover {\n\tbackground: linear-gradient(135deg, rgba(60, 170, 240, 0.85) 0%, rgba(52, 152, 219, 0.8) 100%);\n\tborder-color: rgba(80, 180, 255, 0.5);\n\tcolor: #fff;\n\ttransform: translateX(-50%) translateY(-2px) scale(1.03);\n\tbox-shadow: 0 6px 20px rgba(52, 152, 219, 0.4), 0 2px 8px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2);\n}\n\n.hud__reset-btn:active {\n\ttransform: translateX(-50%) translateY(1px);\n\tbox-shadow: 0 1px 5px rgba(0, 0, 0, 0.3);\n}\n\n.hud__position {\n\tbackground: linear-gradient(135deg, rgba(10, 10, 25, 0.8) 0%, rgba(20, 20, 40, 0.75) 100%);\n\tbackdrop-filter: blur(12px) saturate(150%);\n\t-webkit-backdrop-filter: blur(12px) saturate(150%);\n\tborder: 2.5px solid var(--clr-secondary);\n\tpadding: 0.4rem 0.8rem;\n\tfont-size: 1.4rem;\n\tcolor: var(--clr-secondary);\n\ttext-shadow: 0 3px 10px rgba(0, 0, 0, 0.7), 0 1px 3px rgba(0, 0, 0, 0.5), 0 0 15px rgba(245, 166, 35, 0.3);\n\tline-height: 1;\n\tborder-radius: 12px;\n\tbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), 0 2px 6px rgba(245, 166, 35, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -2px 0 rgba(0, 0, 0, 0.3);\n}\n\n.hud__position-suffix {\n\tfont-size: 0.6rem;\n\tvertical-align: super;\n}\n\n.hud__position-label {\n\tfont-size: 0.6rem;\n\tcolor: rgba(255, 255, 255, 0.5);\n}\n\n.hud__timer {\n\tbackground: linear-gradient(135deg, rgba(10, 10, 25, 0.75) 0%, rgba(20, 20, 40, 0.7) 100%);\n\tbackdrop-filter: blur(12px) saturate(140%);\n\t-webkit-backdrop-filter: blur(12px) saturate(140%);\n\tborder: 2px solid rgba(255, 255, 255, 0.2);\n\tpadding: 0.4rem 0.8rem;\n\tcolor: var(--clr-white);\n\tfont-size: 0.7rem;\n\ttext-shadow: 0 2px 8px rgba(0, 0, 0, 0.6), 0 1px 3px rgba(0, 0, 0, 0.4);\n\tborder-radius: 10px;\n\tbox-shadow: 0 3px 14px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -2px 0 rgba(0, 0, 0, 0.2);\n}\n\n.hud__lap {\n\tbackground: linear-gradient(135deg, rgba(10, 10, 25, 0.75) 0%, rgba(20, 20, 40, 0.7) 100%);\n\tbackdrop-filter: blur(12px) saturate(140%);\n\t-webkit-backdrop-filter: blur(12px) saturate(140%);\n\tborder: 2.5px solid var(--clr-primary);\n\tpadding: 0.4rem 0.8rem;\n\tcolor: var(--clr-white);\n\tfont-size: 0.9rem;\n\tborder-radius: 10px;\n\tbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), 0 2px 6px rgba(232, 67, 42, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -2px 0 rgba(0, 0, 0, 0.2);\n}\n\n.hud__lap-label {\n\tfont-size: 0.45rem;\n\tcolor: rgba(255, 255, 255, 0.4);\n\tmargin-right: 0.2em;\n}\n\n.hud__lap-total {\n\tcolor: rgba(255, 255, 255, 0.35);\n\tfont-size: 0.6rem;\n}\n\n.hud__boost-indicator {\n\tposition: absolute;\n\ttop: 50%;\n\tleft: 50%;\n\ttransform: translate(-50%, -70px);\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-weight: 900;\n\tfont-size: clamp(0.8rem, 2.5vw, 1.1rem);\n\tcolor: transparent;\n\tbackground: linear-gradient(90deg, #ff8800, #ffcc00, #ff8800);\n\tbackground-size: 200% 100%;\n\t-webkit-background-clip: text;\n\tbackground-clip: text;\n\tfilter: drop-shadow(0 2px 8px rgba(255, 136, 0, 0.6));\n\tanimation: shimmer 0.8s ease infinite;\n}\n\n.hud__lap-popup {\n\tposition: absolute;\n\ttop: 35%;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-weight: 900;\n\tfont-size: clamp(1rem, 3.5vw, 1.6rem);\n\tcolor: transparent;\n\tbackground: linear-gradient(180deg, #ffffff, #88ccff);\n\t-webkit-background-clip: text;\n\tbackground-clip: text;\n\tfilter: drop-shadow(0 3px 10px rgba(100, 180, 255, 0.4));\n\tanimation: countPop 0.6s ease-out;\n\tletter-spacing: 2px;\n}\n\n.hud__turbo-popup {\n\tposition: absolute;\n\ttop: 42%;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-weight: 900;\n\tfont-size: clamp(0.9rem, 3vw, 1.3rem);\n\tcolor: transparent;\n\tbackground: linear-gradient(90deg, #00ff88, #44ffcc, #00ff88);\n\tbackground-size: 200% 100%;\n\t-webkit-background-clip: text;\n\tbackground-clip: text;\n\tfilter: drop-shadow(0 2px 12px rgba(0, 255, 136, 0.5));\n\tanimation: countPop 0.6s ease-out, shimmer 1s ease infinite;\n}\n\n.hud__wrong-way {\n\tposition: absolute;\n\ttop: 25%;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-weight: 900;\n\tfont-size: clamp(0.8rem, 2.5vw, 1.1rem);\n\tcolor: #ff2222;\n\ttext-shadow: 0 0 20px rgba(255, 34, 34, 0.5);\n\tanimation: blink 0.5s step-start infinite;\n\tbackground: rgba(100, 0, 0, 0.3);\n\tpadding: 0.4em 1em;\n\tborder-radius: 8px;\n\tborder: 1px solid rgba(255, 50, 50, 0.3);\n}\n\n.hud__bottom {\n\tposition: absolute;\n\tbottom: 0.6rem;\n\tleft: 0.6rem;\n\tright: 0.6rem;\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: flex-end;\n\tpointer-events: none;\n}\n\n@media (max-width: 768px), (pointer: coarse) {\n\t.hud__bottom {\n\t\tbottom: calc(max(0.8rem, env(safe-area-inset-bottom)) + clamp(70px, 20vw, 100px) + 20px);\n\t}\n\n\t.hud__minimap {\n\t\ttransform: scale(0.7);\n\t\ttransform-origin: bottom right;\n\t}\n\n\t.hud__left-panel {\n\t\ttransform: scale(0.85);\n\t\ttransform-origin: bottom left;\n\t}\n}\n\n.hud__left-panel {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 0.3rem;\n}\n\n.hud__speed {\n\tbackground: linear-gradient(135deg, rgba(10, 10, 25, 0.8) 0%, rgba(20, 20, 40, 0.75) 100%);\n\tbackdrop-filter: blur(12px) saturate(150%);\n\t-webkit-backdrop-filter: blur(12px) saturate(150%);\n\tborder: 2.5px solid rgba(255, 255, 255, 0.25);\n\tpadding: 0.4rem 0.8rem;\n\tfont-size: 1.1rem;\n\tcolor: var(--clr-white);\n\tborder-radius: 10px;\n\tbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.12), inset 0 -2px 0 rgba(0, 0, 0, 0.25);\n}\n\n.hud__speed-unit {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: 0.35rem;\n\tcolor: rgba(255, 255, 255, 0.35);\n\tmargin-left: 0.2em;\n}\n\n.hud__speed-bar {\n\twidth: 140px;\n\theight: 12px;\n\tbackground: linear-gradient(135deg, rgba(10, 10, 25, 0.7) 0%, rgba(5, 5, 15, 0.8) 100%);\n\tborder: 2px solid rgba(255, 255, 255, 0.2);\n\tposition: relative;\n\toverflow: hidden;\n\tborder-radius: 8px;\n\tbox-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);\n}\n\n.hud__speed-bar-fill {\n\tposition: absolute;\n\tleft: 0;\n\ttop: 0;\n\theight: 100%;\n\twidth: 0%;\n\tbackground: linear-gradient(90deg, #22cc44, #66dd22, #88ee00, #aaff11, #ccff00);\n\tbox-shadow: 0 0 10px rgba(136, 238, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.3);\n\ttransition: width 0.1s;\n\tborder-radius: 6px;\n}\n\n.hud__speed-bar-boost {\n\tposition: absolute;\n\tright: 0;\n\ttop: 0;\n\theight: 100%;\n\twidth: 0%;\n\tbackground: linear-gradient(90deg, #ff6600, #ffcc00);\n\tanimation: boostFlash 0.15s step-start infinite alternate;\n\ttransition: width 0.1s;\n\tborder-radius: 4px;\n}\n\n.hud__drift-meter {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.3rem;\n}\n\n.hud__drift-label {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: 0.3rem;\n\tcolor: rgba(255, 255, 255, 0.35);\n\tletter-spacing: 1px;\n}\n\n.hud__drift-bar {\n\twidth: 100px;\n\theight: 8px;\n\tbackground: rgba(0, 0, 0, 0.5);\n\tborder: 1px solid rgba(255, 255, 255, 0.12);\n\tposition: relative;\n\toverflow: hidden;\n\tborder-radius: 4px;\n}\n\n.hud__drift-bar-fill {\n\tposition: absolute;\n\tleft: 0;\n\ttop: 0;\n\theight: 100%;\n\twidth: 0%;\n\tbackground: linear-gradient(90deg, #3399ff, #cc44ff, #ff2266);\n\ttransition: width 0.15s;\n\tborder-radius: 3px;\n}\n\n.hud__coins {\n\tbackground: linear-gradient(135deg, rgba(20, 15, 10, 0.75) 0%, rgba(30, 20, 10, 0.7) 100%);\n\tbackdrop-filter: blur(10px) saturate(140%);\n\t-webkit-backdrop-filter: blur(10px) saturate(140%);\n\tborder: 2px solid rgba(255, 215, 0, 0.5);\n\tpadding: 0.25rem 0.55rem;\n\tfont-size: 0.55rem;\n\tcolor: #FFD700;\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.35rem;\n\tborder-radius: 10px;\n\tbox-shadow: 0 3px 12px rgba(0, 0, 0, 0.35), 0 1px 4px rgba(255, 215, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.15), inset 0 -2px 0 rgba(0, 0, 0, 0.2);\n\ttext-shadow: 0 1px 3px rgba(0, 0, 0, 0.5), 0 0 8px rgba(255, 215, 0, 0.3);\n}\n\n.hud__coin-icon {\n\tcolor: #FF8844;\n\tfont-size: 0.6rem;\n\tfilter: drop-shadow(0 1px 3px rgba(255, 100, 30, 0.4));\n}\n\n.hud__minimap {\n\tbackground: linear-gradient(135deg, rgba(10, 10, 25, 0.6) 0%, rgba(15, 15, 30, 0.5) 100%);\n\tborder: 2.5px solid rgba(255, 255, 255, 0.2);\n\tpadding: 5px;\n\tborder-radius: 16px;\n\tbackdrop-filter: blur(12px) saturate(140%);\n\t-webkit-backdrop-filter: blur(12px) saturate(140%);\n\tbox-shadow: 0 6px 24px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -2px 0 rgba(0, 0, 0, 0.3);\n}\n\n#minimapCanvas {\n\tdisplay: block;\n\timage-rendering: auto;\n}\n\n.countdown {\n\tposition: absolute;\n\ttop: 50%;\n\tleft: 50%;\n\ttransform: translate(-50%, -50%);\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-weight: 900;\n\tfont-size: clamp(3rem, 10vw, 6rem);\n\tcolor: transparent;\n\tbackground: linear-gradient(180deg, #ffffff, #ffcc88);\n\t-webkit-background-clip: text;\n\tbackground-clip: text;\n\tfilter: drop-shadow(0 4px 15px rgba(255, 100, 50, 0.5)) drop-shadow(0 0 40px rgba(255, 80, 30, 0.3));\n\tanimation: countPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n.finish-content {\n\ttext-align: center;\n\tanimation: fadeSlideIn 0.6s cubic-bezier(0.22, 1, 0.36, 1);\n\tbackground: linear-gradient(135deg, rgba(15, 15, 45, 0.9) 0%, rgba(25, 25, 60, 0.85) 100%);\n\tborder: 2.5px solid rgba(255, 255, 255, 0.15);\n\tpadding: 2.5rem 3.5rem;\n\tmax-width: 90vw;\n\tborder-radius: 32px;\n\tbackdrop-filter: blur(28px) saturate(180%);\n\t-webkit-backdrop-filter: blur(28px) saturate(180%);\n\tbox-shadow: 0 30px 80px rgba(0, 0, 0, 0.6), 0 10px 30px rgba(0, 0, 0, 0.4), inset 0 2px 0 rgba(255, 255, 255, 0.12), inset 0 -2px 0 rgba(0, 0, 0, 0.25);\n\tposition: relative;\n\toverflow: hidden;\n}\n\n.finish-flag {\n\tfont-size: 3rem;\n\tmargin-bottom: 0.5rem;\n\tanimation: pulse 1.5s ease infinite;\n\tfilter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));\n}\n\n.finish-title {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-weight: 900;\n\tfont-size: clamp(1.2rem, 4vw, 2.2rem);\n\tcolor: transparent;\n\tbackground: linear-gradient(180deg, #ffffff 0%, #ffcc88 100%);\n\t-webkit-background-clip: text;\n\tbackground-clip: text;\n\tfilter: drop-shadow(0 3px 6px rgba(255, 100, 50, 0.4));\n\tmargin-bottom: 0.5em;\n}\n\n.finish-position {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-weight: 900;\n\tfont-size: clamp(2rem, 8vw, 4rem);\n\tcolor: transparent;\n\tbackground: linear-gradient(180deg, #FFD700 0%, #FF8800 50%, #FF4400 100%);\n\t-webkit-background-clip: text;\n\tbackground-clip: text;\n\tfilter: drop-shadow(0 4px 10px rgba(255, 136, 0, 0.4));\n\tmargin-bottom: 0.2em;\n}\n\n.finish-time {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: clamp(0.5rem, 1.4vw, 0.75rem);\n\tcolor: rgba(255, 255, 255, 0.8);\n\tmargin-bottom: 0.8rem;\n\tletter-spacing: 2px;\n}\n\n.finish-stats {\n\tfont-family: 'Orbitron', sans-serif;\n\tfont-size: 0.42rem;\n\tcolor: rgba(255, 255, 255, 0.65);\n\tmargin-bottom: 1.4rem;\n\tline-height: 2.6;\n\tbackground: linear-gradient(135deg, rgba(10, 10, 30, 0.5) 0%, rgba(15, 15, 35, 0.4) 100%);\n\tpadding: 1rem 1.4rem;\n\tborder-radius: 16px;\n\tborder: 1.5px solid rgba(255, 255, 255, 0.08);\n\tbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.06);\n\tbackdrop-filter: blur(8px);\n\t-webkit-backdrop-filter: blur(8px);\n}\n\n.finish-buttons {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tgap: 0.5rem;\n}\n\n@keyframes bounceIn {\n\t0% {\n\t\ttransform: scale(0.3);\n\t\topacity: 0;\n\t}\n\n\t100% {\n\t\ttransform: scale(1);\n\t\topacity: 1;\n\t}\n}\n\n@keyframes fadeSlideIn {\n\t0% {\n\t\ttransform: translateY(30px) scale(0.95);\n\t\topacity: 0;\n\t}\n\n\t100% {\n\t\ttransform: translateY(0) scale(1);\n\t\topacity: 1;\n\t}\n}\n\n@keyframes countPop {\n\t0% {\n\t\ttransform: translate(-50%, -50%) scale(2.5);\n\t\topacity: 0;\n\t}\n\n\t60% {\n\t\ttransform: translate(-50%, -50%) scale(0.95);\n\t\topacity: 1;\n\t}\n\n\t100% {\n\t\ttransform: translate(-50%, -50%) scale(1);\n\t\topacity: 1;\n\t}\n}\n\n@keyframes blink {\n\t50% {\n\t\topacity: 0;\n\t}\n}\n\n@keyframes pulse {\n\t0%, 100% {\n\t\topacity: 0.35;\n\t}\n\n\t50% {\n\t\topacity: 0.7;\n\t}\n}\n\n@keyframes shimmer {\n\t0% {\n\t\tbackground-position: 200% 0;\n\t}\n\n\t100% {\n\t\tbackground-position: -200% 0;\n\t}\n}\n\n@keyframes rotateBg {\n\t0% {\n\t\ttransform: rotate(0deg);\n\t}\n\n\t100% {\n\t\ttransform: rotate(360deg);\n\t}\n}\n\n@keyframes boostFlash {\n\t0% {\n\t\tcolor: #ff8800;\n\t}\n\n\t100% {\n\t\tcolor: #ffee00;\n\t}\n}"}],"folders":[]},"variants":null,"createdAt":"2026-02-09T15:06:45.399Z","updatedAt":"2026-03-02T01:59:42.969Z"}}