<!DOCTYPE html>
<html lang="id">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <title>Franchise Game — Arena Pacu Jalur</title>
    <link rel="stylesheet" href="../assets/css/game-layout.css">
    <style>
        /* Phaser canvas di bawah overlay */
        #game-container canvas {
            z-index: 1;
        }
    </style>
</head>

<body>

    <div id="desktop-wrapper">
        <div id="mobile-frame">
            <div id="status-bar">
                <span id="clock">00:00</span>
                <span>&#11044;&#11044;&#11044;</span>
            </div>
            <div id="game-container"></div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/phaser@3.88.2/dist/phaser.min.js"></script>

    <script>
        const GAME_WIDTH = 360;
        const GAME_HEIGHT = 760;

        // =====================================================
        //  HELPER — Dynamic Pixel Art Recoloring
        // =====================================================
        function recolorCharacterImage(scene, sourceKey, customColors) {
            const sourceTexture = scene.textures.get(sourceKey);
            const sourceImage = sourceTexture.getSourceImage();

            const canvas = document.createElement('canvas');
            canvas.width = sourceImage.width;
            canvas.height = sourceImage.height;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(sourceImage, 0, 0);

            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;

            const targetHair = Phaser.Display.Color.HexStringToColor(customColors.hair);
            const targetShirt = Phaser.Display.Color.HexStringToColor(customColors.shirt);
            const targetPants = Phaser.Display.Color.HexStringToColor(customColors.pants);
            const targetPaddle = Phaser.Display.Color.HexStringToColor(customColors.paddle);

            for (let i = 0; i < data.length; i += 4) {
                const r = data[i];
                const g = data[i + 1];
                const b = data[i + 2];
                const a = data[i + 3];

                if (a < 10) continue; // transparan
                if (r < 40 && g < 40 && b < 40) continue; // outline gelap

                // 1. Rambut (Merah): R dominan dan R - G > 100
                if (r - g > 100 && r - b > 100) {
                    const factor = Math.min(1.2, r / 199);
                    data[i] = Math.min(255, targetHair.r * factor);
                    data[i + 1] = Math.min(255, targetHair.g * factor);
                    data[i + 2] = Math.min(255, targetHair.b * factor);
                }
                // 2. Celana (Hijau): G dominan dan G - R > 50
                else if (g - r > 50 && g - b > 40) {
                    const factor = Math.min(1.2, g / 122);
                    data[i] = Math.min(255, targetPants.r * factor);
                    data[i + 1] = Math.min(255, targetPants.g * factor);
                    data[i + 2] = Math.min(255, targetPants.b * factor);
                }
                // 3. Dayung (Biru): B dominan dan B - R > 80
                else if (b - r > 80 && b - g > 40) {
                    const factor = Math.min(1.2, b / 203);
                    data[i] = Math.min(255, targetPaddle.r * factor);
                    data[i + 1] = Math.min(255, targetPaddle.g * factor);
                    data[i + 2] = Math.min(255, targetPaddle.b * factor);
                }
                // 4. Baju/Badan (Abu-abu): R, G, B mirip
                else if (Math.abs(r - g) < 20 && Math.abs(g - b) < 20 && Math.abs(r - b) < 20) {
                    const factor = Math.min(1.2, ((r + g + b) / 3) / 78);
                    data[i] = Math.min(255, targetShirt.r * factor);
                    data[i + 1] = Math.min(255, targetShirt.g * factor);
                    data[i + 2] = Math.min(255, targetShirt.b * factor);
                }
            }

            ctx.putImageData(imgData, 0, 0);
            return canvas;
        }

        // =====================================================
        //  ARENA SCENE
        // =====================================================
        class ArenaScene extends Phaser.Scene {
            constructor() { super({ key: 'ArenaScene' }); }

            preload() {
                this.load.image('bgmenu', '../assets/image/bg/bgmenu.jpg');
                this.load.image('back', '../assets/image/ui/back.png');
                this.load.image('koin', '../assets/image/ui/koin.png');
                this.load.image('jalur_boat', '../assets/image/jalur/jalur.png');

                // Load frame-frame gambar orang mendayung (rowing animation frames)
                this.load.image('char1', '../assets/image/char/1.png');
                this.load.image('char2', '../assets/image/char/2.png');
                this.load.image('char3', '../assets/image/char/3.png');
                this.load.image('char4', '../assets/image/char/4.png');
                this.load.image('char5', '../assets/image/char/5.png');

                // Load frame pancang (1 sampai 6)
                for (let i = 1; i <= 6; i++) {
                    this.load.image(`pancang${i}`, `../assets/image/pancang/${i}.png`);
                }

                // Load spanduk promosi (1 sampai 8)
                for (let i = 1; i <= 8; i++) {
                    this.load.image(`promosi${i}`, `../assets/image/promosi/spanduk_${i}.png`);
                }
            }

            applyRecolor(isPlayer, customColors) {
                const prefix = isPlayer ? 'player' : 'opponent';

                // Jalankan pewarnaan ulang frame 1-5
                for (let f = 1; f <= 5; f++) {
                    const sourceKey = `char${f}`;
                    const destKey = `${prefix}_char${f}`;

                    const canvas = recolorCharacterImage(this, sourceKey, customColors);

                    if (this.textures.exists(destKey)) {
                        this.textures.remove(destKey);
                    }
                    this.textures.addCanvas(destKey, canvas);
                }

                // Buat animasi rowing
                const animKey = `${prefix}_rowing_anim`;
                if (this.anims.exists(animKey)) {
                    this.anims.remove(animKey);
                }
                this.anims.create({
                    key: animKey,
                    frames: [
                        { key: `${prefix}_char1` },
                        { key: `${prefix}_char2` },
                        { key: `${prefix}_char3` },
                        { key: `${prefix}_char4` },
                        { key: `${prefix}_char5` }
                    ],
                    frameRate: 8,
                    repeat: -1
                });
            }

            applyPlayerCorak(boatImg, boatGroup) {
                const dataUrl = localStorage.getItem('corak_data_url');
                if (!dataUrl) return;

                const img = new Image();
                img.onload = () => {
                    if (!this.textures) return;
                    const boatSource = this.textures.get('jalur_boat').getSourceImage();
                    const CORAK_SCALE = 2.3;
                    const displayW = Math.round(boatSource.width * CORAK_SCALE);
                    const displayH = Math.round(boatSource.height * CORAK_SCALE);

                    const maskCanvas = document.createElement('canvas');
                    maskCanvas.width = displayW;
                    maskCanvas.height = displayH;
                    const ctx = maskCanvas.getContext('2d');

                    ctx.imageSmoothingEnabled = false;
                    ctx.drawImage(img, 0, 0, displayW, displayH);

                    // Hapus background putih
                    const imageData = ctx.getImageData(0, 0, displayW, displayH);
                    const data = imageData.data;
                    const WHITE_THRESHOLD = 240;
                    for (let i = 0; i < data.length; i += 4) {
                        const r = data[i], g = data[i + 1], b = data[i + 2];
                        if (r > WHITE_THRESHOLD && g > WHITE_THRESHOLD && b > WHITE_THRESHOLD) {
                            const brightness = Math.min(r, g, b);
                            const fade = (brightness - WHITE_THRESHOLD) / (255 - WHITE_THRESHOLD);
                            data[i + 3] = Math.round(255 * (1 - fade));
                        }
                    }
                    ctx.putImageData(imageData, 0, 0);

                    ctx.globalCompositeOperation = 'destination-in';
                    ctx.drawImage(boatSource, 0, 0, displayW, displayH);
                    ctx.globalCompositeOperation = 'source-over';

                    if (this.textures.exists('player_corak_texture')) {
                        this.textures.remove('player_corak_texture');
                    }
                    this.textures.addCanvas('player_corak_texture', maskCanvas);

                    const corakSprite = this.make.image({
                        x: 0,
                        y: 15,
                        key: 'player_corak_texture',
                        add: false
                    });
                    corakSprite.setScale(1.0);
                    corakSprite.setAlpha(0.82);
                    corakSprite.setBlendMode(Phaser.BlendModes.MULTIPLY);

                    boatGroup.add(corakSprite);
                    if (boatImg && boatGroup.list.includes(boatImg)) {
                        const boatIdx = boatGroup.getIndex(boatImg);
                        boatGroup.moveTo(corakSprite, boatIdx + 1);
                    }
                };
                img.src = dataUrl;
            }

            applyPlayerLambai(boatImg, boatGroup) {
                const dataUrl = localStorage.getItem('lambai_data_url');
                if (!dataUrl) return;

                const img = new Image();
                img.onload = () => {
                    if (!this.textures) return;
                    const LAMBAI_SCALE = 1.3;
                    const LAMBAI_OFFSET_X = 125;
                    const LAMBAI_OFFSET_Y = -18;

                    const targetSize = 48;
                    let w = img.width;
                    let h = img.height;
                    if (w > h) {
                        h = Math.round((h / w) * targetSize);
                        w = targetSize;
                    } else {
                        w = Math.round((w / h) * targetSize);
                        h = targetSize;
                    }

                    const canvas = document.createElement('canvas');
                    canvas.width = w;
                    canvas.height = h;
                    const ctx = canvas.getContext('2d');

                    ctx.imageSmoothingEnabled = false;
                    ctx.drawImage(img, 0, 0, w, h);

                    // Hapus background putih
                    const imageData = ctx.getImageData(0, 0, w, h);
                    const data = imageData.data;
                    const WHITE_THRESHOLD = 240;
                    for (let i = 0; i < data.length; i += 4) {
                        const r = data[i], g = data[i + 1], b = data[i + 2];
                        if (r > WHITE_THRESHOLD && g > WHITE_THRESHOLD && b > WHITE_THRESHOLD) {
                            const brightness = Math.min(r, g, b);
                            const fade = (brightness - WHITE_THRESHOLD) / (255 - WHITE_THRESHOLD);
                            data[i + 3] = Math.round(255 * (1 - fade));
                        }
                    }
                    ctx.putImageData(imageData, 0, 0);

                    if (this.textures.exists('player_lambai_texture')) {
                        this.textures.remove('player_lambai_texture');
                    }
                    this.textures.addCanvas('player_lambai_texture', canvas);

                    const lambaiSprite = this.make.image({
                        x: LAMBAI_OFFSET_X,
                        y: LAMBAI_OFFSET_Y,
                        key: 'player_lambai_texture',
                        add: false
                    });
                    lambaiSprite.setScale(LAMBAI_SCALE);
                    lambaiSprite.texture.setFilter(Phaser.Textures.FilterMode.NEAREST);

                    boatGroup.add(lambaiSprite);
                    if (boatImg && boatGroup.list.includes(boatImg)) {
                        const boatIdx = boatGroup.getIndex(boatImg);
                        boatGroup.moveTo(lambaiSprite, boatIdx); // Di bawah perahu
                    }
                    // Animasi lambai akan disinkronkan dengan frame dayungan di makeRowersAndEmitters
                    boatGroup.lambaiSprite = lambaiSprite;
                };
                img.src = dataUrl;
            }

            create() {
                const W = this.scale.width;
                const H = this.scale.height;
                const cx = W / 2;

                this.cameras.main.fadeIn(500, 240, 253, 244);

                // --- Load Data dari LocalStorage ---
                this.customColors = {
                    boat: localStorage.getItem('custom_boat') || '#8b4513',
                    hair: localStorage.getItem('custom_hair') || '#e53e3e',
                    shirt: localStorage.getItem('custom_shirt') || '#a0aec0',
                    pants: localStorage.getItem('custom_pants') || '#38a169',
                    paddle: localStorage.getItem('custom_paddle') || '#3182ce',
                    splash: localStorage.getItem('custom_splash') || '#a5f3fc'
                };

                // Warna rival/lawan (Amber, biru, orange)
                this.opponentColors = {
                    boat: '#d97706',
                    hair: '#2563eb',
                    shirt: '#ea580c',
                    pants: '#4b5563',
                    paddle: '#854d0e',
                    splash: '#a5f3fc'
                };

                // --- Game States ---
                this.raceDistance = 1000; // 1000 meter lintasan
                this.playerDistance = this.raceDistance;
                this.opponentDistance = this.raceDistance;
                this.playerSpeed = 0;
                this.opponentSpeed = 0;
                this.maxSpeed = 25; // m/s
                this.gameState = 'countdown'; // countdown, racing, finished
                this.scrollSpeed = 0;
                this.elapsedTime = 0;
                this.pointerX = 0;
                this.pointerTime = 0;

                // --- 1. Background static & Dynamic Water ---
                const bg = this.add.image(cx, H / 2, 'bgmenu');
                const scaleX_bg = W / bg.width;
                const scaleY_bg = H / bg.height;
                bg.setScale(Math.max(scaleX_bg, scaleY_bg));
                bg.setAlpha(0.28); // Kurangi opacity agar perahu dan air menonjol

                // Generate River Texture
                if (this.textures.exists('river_water')) {
                    this.textures.remove('river_water');
                }
                const riverGfx = this.make.graphics({ add: false });
                riverGfx.fillStyle(0x0284c7, 1);
                riverGfx.fillRect(0, 0, 64, 64);
                riverGfx.fillStyle(0x0ea5e9, 0.4);
                riverGfx.fillRect(0, 14, 64, 3);
                riverGfx.fillRect(0, 44, 64, 3);
                riverGfx.fillStyle(0x38bdf8, 0.25);
                riverGfx.fillRect(16, 28, 32, 2);
                riverGfx.fillRect(32, 58, 20, 2);
                riverGfx.generateTexture('river_water', 64, 64);
                riverGfx.destroy();

                // Generate Water Shimmer / Glow Texture
                if (this.textures.exists('water_shimmer')) {
                    this.textures.remove('water_shimmer');
                }
                const shimmerGfx = this.make.graphics({ add: false });
                shimmerGfx.fillStyle(0xffffff, 0.4); // Putih transparan untuk pantulan cahaya
                shimmerGfx.fillRoundedRect(5, 10, 20, 2, 1);
                shimmerGfx.fillRoundedRect(40, 25, 15, 2, 1);
                shimmerGfx.fillRoundedRect(15, 45, 25, 2, 1);
                shimmerGfx.fillStyle(0xffffff, 0.6); // Lebih terang di beberapa titik
                shimmerGfx.fillRect(10, 10, 5, 2);
                shimmerGfx.fillRect(45, 25, 6, 2);
                shimmerGfx.generateTexture('water_shimmer', 64, 64);
                shimmerGfx.destroy();

                // Generate Grass Bank Texture
                if (this.textures.exists('grass_bank')) {
                    this.textures.remove('grass_bank');
                }
                const grassGfx = this.make.graphics({ add: false });
                grassGfx.fillStyle(0x22c55e, 1);
                grassGfx.fillRect(0, 0, 32, 32);
                grassGfx.fillStyle(0x16a34a, 0.7);
                grassGfx.fillRect(0, 0, 32, 2);
                grassGfx.fillRect(4, 8, 4, 4);
                grassGfx.fillRect(20, 24, 4, 4);
                grassGfx.generateTexture('grass_bank', 32, 32);
                grassGfx.destroy();

                // Air sungai & Rumput pinggiran
                this.riverTile = this.add.tileSprite(cx, 350, W, 300, 'river_water');

                // Lapisan pantulan cahaya (shimmer) untuk efek glow mengalir
                this.shimmerTile = this.add.tileSprite(cx, 350, W, 300, 'water_shimmer');
                this.shimmerTile.setBlendMode(Phaser.BlendModes.ADD); // Efek bercahaya
                this.shimmerTile.setAlpha(0.6);

                // Animasi kelap-kelip glow air
                this.tweens.add({
                    targets: this.shimmerTile,
                    alpha: 0.15,
                    duration: 1200,
                    yoyo: true,
                    repeat: -1,
                    ease: 'Sine.easeInOut'
                });

                this.topBank = this.add.tileSprite(cx, 195, W, 10, 'grass_bank');
                this.bottomBank = this.add.tileSprite(cx, 505, W, 10, 'grass_bank');

                // --- 2. Pembuatan Tribun & Penonton Cheering ---
                // Tribun Penonton Atas (80px - 190px)
                // Tribun Penonton Bawah (510px - 620px)
                this.spectators = [];
                const spectatorColors = [0xef4444, 0x3b82f6, 0x10b981, 0xf59e0b, 0x8b5cf6, 0xec4899, 0xf43f5e, 0x06b6d4];

                // Generate Spectator Texture
                if (this.textures.exists('spectator_crowd')) {
                    this.textures.remove('spectator_crowd');
                }
                const specGfx = this.make.graphics({ add: false });
                specGfx.fillStyle(0xffdbac); // Skin head
                specGfx.fillRect(4, 0, 8, 8);
                specGfx.fillStyle(0xffffff); // Shirt body
                specGfx.fillRect(2, 8, 12, 10);
                specGfx.generateTexture('spectator_crowd', 16, 18);
                specGfx.destroy();

                const spawnSpectators = (yPos, num) => {
                    const spacing = (W + 100) / num;
                    let lastBannerIdx = -100; // Melacak penonton terakhir yang memegang spanduk agar tidak tumpang tindih

                    for (let i = 0; i < num; i++) {
                        const x = i * spacing - 50 + Math.random() * 15;

                        // Buat container agar penonton dan spanduk bisa bounce bersama
                        const specContainer = this.add.container(x, yPos);

                        const spec = this.add.image(0, 0, 'spectator_crowd');
                        spec.setScale(1.2);
                        spec.texture.setFilter(Phaser.Textures.FilterMode.NEAREST);
                        spec.setTint(Phaser.Utils.Array.GetRandom(spectatorColors));

                        specContainer.add(spec);

                        // Probabilitas dinaikkan jadi 30%, tapi dengan syarat jarak minimal (i - lastBannerIdx > 3)
                        // Ini memastikan spanduk yang besar tidak akan saling menimpa
                        if (yPos < 300 && Math.random() < 0.30 && (i - lastBannerIdx) > 3) {
                            lastBannerIdx = i; // Simpan indeks penonton yang memegang spanduk
                            const bannerIdx = Phaser.Math.Between(1, 8);
                            const bannerImg = this.add.image(0, 0, `promosi${bannerIdx}`);

                            // Skalakan spanduk agar besar dan seakan dipegang oleh banyak penonton
                            const BANNER_W = 140;
                            const BANNER_H = 44;
                            bannerImg.setDisplaySize(BANNER_W, BANNER_H);

                            // Background putih untuk memberikan sedikit padding (bingkai spanduk)
                            const bannerBg = this.add.graphics();
                            bannerBg.fillStyle(0xffffff, 1);
                            // Padding 3 pixel di tiap sisi
                            bannerBg.fillRect(-BANNER_W / 2 - 3, -BANNER_H / 2 - 3, BANNER_W + 6, BANNER_H + 6);

                            // Letakkan spanduk sedikit ke bawah agar seakan dipegang di dada/tangan
                            const bannerGroup = this.add.container(0, 10);
                            bannerGroup.add(bannerBg);
                            bannerGroup.add(bannerImg);

                            specContainer.add(bannerGroup);

                            // Naikkan z-index container ini agar spanduknya berada di atas penonton lain
                            specContainer.setDepth(yPos + 10);
                        } else {
                            specContainer.setDepth(yPos);
                        }

                        // Animasi melonjak/cheer konstan HANYA PADA PENONTON, bukan spanduk
                        this.tweens.add({
                            targets: spec,
                            y: -5 - Math.random() * 4,
                            duration: 180 + Math.random() * 100,
                            yoyo: true,
                            repeat: -1,
                            delay: Math.random() * 400,
                            ease: 'Sine.easeInOut'
                        });

                        this.spectators.push({ sprite: specContainer, baseTranslateY: yPos });
                    }
                };

                // Spawn barisan penonton di tribun atas
                spawnSpectators(135, 10); // Baris 1
                spawnSpectators(165, 12); // Baris 2
                // Spawn barisan penonton di tribun bawah
                spawnSpectators(545, 12); // Baris 1
                spawnSpectators(575, 10); // Baris 2

                // Struktur Tribun Kayu (menggambar bangku tribun horizontal)
                const tribuneColor = 0xb45309; // Kayu coklat
                const tb = this.add.graphics();
                // Benches atas
                tb.fillStyle(tribuneColor, 0.9);
                tb.fillRect(0, 140, W, 8);
                tb.fillRect(0, 170, W, 8);
                tb.lineStyle(2, 0x78350f, 1);
                tb.strokeRect(0, 140, W, 8);
                tb.strokeRect(0, 170, W, 8);

                // Benches bawah
                tb.fillRect(0, 550, W, 8);
                tb.fillRect(0, 580, W, 8);
                tb.strokeRect(0, 550, W, 8);
                tb.strokeRect(0, 580, W, 8);

                // --- 2.5 Pancang Pemisah di Tengah Sungai ---
                this.pancangs = [];
                // 6 Pancang untuk membagi jarak 1000m (Pancang 1 di start 1000m, Pancang 6 di finish 0m)
                const pDistances = [1000, 800, 600, 400, 200, 0];
                pDistances.forEach((dist, index) => {
                    const pancangImg = this.add.image(-100, 350, `pancang${index + 1}`);

                    // Jadikan pixelated (NEAREST filter)
                    pancangImg.texture.setFilter(Phaser.Textures.FilterMode.NEAREST);

                    // Skalakan gambar secara proporsional dengan target tinggi 140 pixel
                    pancangImg.displayHeight = 140;
                    pancangImg.scaleX = pancangImg.scaleY;

                    pancangImg.setDepth(350); // Di tengah antara lawan(280) dan player(420)
                    this.pancangs.push({ sprite: pancangImg, dist: dist });
                });

                // --- 3. Pembentukan Kontainer Perahu Pemain & Lawan ---
                const BOAT_SCALE = 2.3;
                const ROWER_SCALE = 0.18;
                const ROWER_SPACING = 35;
                const BOAT_OFFSET_X = 0;
                const BOAT_OFFSET_Y = 15;
                const ROWER_OFFSET_X = -25;
                const ROWER_OFFSET_Y = -25;

                // A. Kontainer Pemain (Player)
                this.playerBoatGroup = this.add.container(cx, 420); // Jalur Bawah
                this.playerBoatGroup.baseY = 420;
                this.playerBoatGroup.setDepth(420); // Z-index sorting
                this.applyRecolor(true, this.customColors);

                this.playerBoatImg = this.add.image(BOAT_OFFSET_X, BOAT_OFFSET_Y, 'jalur_boat');
                this.playerBoatImg.setScale(BOAT_SCALE);
                this.playerBoatImg.texture.setFilter(Phaser.Textures.FilterMode.NEAREST);
                const playerBoatColInt = Phaser.Display.Color.HexStringToColor(this.customColors.boat).color;
                this.playerBoatImg.setTint(playerBoatColInt);
                this.playerBoatGroup.add(this.playerBoatImg);

                // B. Kontainer Lawan (Opponent)
                this.opponentBoatGroup = this.add.container(cx, 280); // Jalur Atas
                this.opponentBoatGroup.baseY = 280;
                this.opponentBoatGroup.setDepth(280); // Z-index sorting
                this.applyRecolor(false, this.opponentColors);

                this.opponentBoatImg = this.add.image(BOAT_OFFSET_X, BOAT_OFFSET_Y, 'jalur_boat');
                this.opponentBoatImg.setScale(BOAT_SCALE);
                this.opponentBoatImg.texture.setFilter(Phaser.Textures.FilterMode.NEAREST);
                const oppBoatColInt = Phaser.Display.Color.HexStringToColor(this.opponentColors.boat).color;
                this.opponentBoatImg.setTint(oppBoatColInt);
                this.opponentBoatGroup.add(this.opponentBoatImg);

                // Terapkan Corak & Ekor Pemain dari LocalStorage
                this.applyPlayerCorak(this.playerBoatImg, this.playerBoatGroup);
                this.applyPlayerLambai(this.playerBoatImg, this.playerBoatGroup);

                // Tambahkan Teks Nama di atas jalur masing-masing perahu
                const pName = localStorage.getItem('username') || 'PLAYER';
                this.playerNameText = this.add.text(0, -60, pName, {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '11px',
                    color: '#ffffff',
                    stroke: '#15803d', // Hijau tua
                    strokeThickness: 5,
                    shadow: { offsetX: 2, offsetY: 2, color: '#000', blur: 0, fill: true }
                }).setOrigin(0.5);
                this.playerBoatGroup.add(this.playerNameText);

                this.oppNameText = this.add.text(0, -60, 'LAWAN', {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '11px',
                    color: '#ffffff',
                    stroke: '#b45309', // Coklat
                    strokeThickness: 5,
                    shadow: { offsetX: 2, offsetY: 2, color: '#000', blur: 0, fill: true }
                }).setOrigin(0.5);
                this.opponentBoatGroup.add(this.oppNameText);

                // Buat Tekstur Splash Air programmatically
                if (this.textures.exists('water_particle_splash')) {
                    this.textures.remove('water_particle_splash');
                }
                const pGfx = this.make.graphics({ add: false });
                pGfx.fillStyle(0xffffff, 1);
                pGfx.fillRect(0, 0, 8, 8);
                pGfx.generateTexture('water_particle_splash', 8, 8);
                pGfx.destroy();

                // Generate Electric Spark Texture
                if (this.textures.exists('electric_spark')) {
                    this.textures.remove('electric_spark');
                }
                const sparkGfx = this.make.graphics({ add: false });
                sparkGfx.fillStyle(0xffffff, 1);
                sparkGfx.fillRect(0, 0, 10, 3);
                sparkGfx.generateTexture('electric_spark', 10, 3);
                sparkGfx.destroy();

                // Emitter Partikel Listrik Global
                this.sparkEmitter = this.add.particles(0, 0, 'electric_spark', {
                    speed: { min: 100, max: 280 },
                    angle: { min: 0, max: 360 },
                    scale: { start: 1, end: 0 },
                    alpha: { start: 1, end: 0 },
                    lifespan: { min: 200, max: 400 },
                    blendMode: 'ADD',
                    tint: [0x00ffff, 0xffff00, 0xff00ff, 0xffffff],
                    emitting: false
                });
                this.sparkEmitter.setDepth(995); // Di belakang teks (yang memiliki depth 1000)

                const SPLASH_OFFSET_X = -1;
                const SPLASH_OFFSET_Y = 32;

                const makeRowersAndEmitters = (boatGroup, colorObj, isPlayer) => {
                    const rowers = [];
                    const emitters = [];
                    const animKey = isPlayer ? 'player_rowing_anim' : 'opponent_rowing_anim';
                    const offsetsX = [-ROWER_SPACING * 2, -ROWER_SPACING, 0, ROWER_SPACING, ROWER_SPACING * 2];

                    const emitterList = [];
                    offsetsX.forEach((offsetX) => {
                        const rowerX = BOAT_OFFSET_X + ROWER_OFFSET_X + offsetX;
                        const rowerY = BOAT_OFFSET_Y + ROWER_OFFSET_Y;

                        const rowerSprite = this.add.sprite(rowerX, rowerY, `${isPlayer ? 'player' : 'opponent'}_char1`);
                        rowerSprite.setScale(ROWER_SCALE);
                        rowerSprite.play(animKey);
                        rowerSprite.texture.setFilter(Phaser.Textures.FilterMode.NEAREST);

                        boatGroup.add(rowerSprite);
                        rowers.push(rowerSprite);
                        emitterList.push({ rowerX, rowerY, rowerSprite });
                    });

                    emitterList.forEach(({ rowerX, rowerY, rowerSprite }) => {
                        const emitter = this.add.particles(rowerX + SPLASH_OFFSET_X, rowerY + SPLASH_OFFSET_Y, 'water_particle_splash', {
                            speed: { min: 45, max: 115 },
                            angle: { min: 280, max: 340 },
                            scale: { start: 2.2, end: 0 },
                            lifespan: { min: 300, max: 550 },
                            gravityY: 350,
                            quantity: 2,
                            frequency: -1
                        });
                        emitter.texture.setFilter(Phaser.Textures.FilterMode.NEAREST);
                        const splashColorInt = Phaser.Display.Color.HexStringToColor(colorObj.splash).color;
                        emitter.setParticleTint(splashColorInt);

                        emitters.push(emitter);
                        boatGroup.add(emitter);

                        rowerSprite.on('animationupdate', (anim, frame) => {
                            if (frame.index === 3 || frame.index === 4) {
                                emitter.explode(12);
                            }

                            // Sinkronisasi pantulan (bounce) dan kibasan lambai menggunakan frame dayungan (rower 1)
                            if (rowers.indexOf(rowerSprite) === 0) {
                                // Pantulan perahu (y offset)
                                const bounceY = (frame.index === 1 || frame.index === 5) ? 0 :
                                    (frame.index === 2 || frame.index === 4) ? 2 : 4;
                                boatGroup.y = boatGroup.baseY + bounceY;

                                // Penari/lambai hanya ikut bounce dengan perahu, tidak bergoyang kiri-kanan
                                if (boatGroup.lambaiSprite) {
                                    boatGroup.lambaiSprite.angle = 0;
                                }
                            }
                        });
                    });

                    return { rowers, emitters };
                };

                this.playerRowers = makeRowersAndEmitters(this.playerBoatGroup, this.customColors, true);
                this.opponentRowers = makeRowersAndEmitters(this.opponentBoatGroup, this.opponentColors, false);

                // Bobbing halus sekarang disinkronkan langsung dengan frame animasi mendayung (di atas)
                // Jadi dihapus dari sini agar tidak tabrakan

                // --- 4. Garis Finish Banner ---
                // (Dihapus sesuai permintaan)

                // --- 5. PROGRESS BAR BALAPAN (Header Glassmorphism) ---
                const progressContainer = this.add.container(cx, 68);
                const pbWidth = 180;
                const pbHeight = 24;

                const pbBg = this.add.graphics();
                pbBg.fillStyle(0xffffff, 0.22);
                pbBg.lineStyle(2, 0xffffff, 0.45);
                pbBg.fillRoundedRect(-pbWidth / 2, -pbHeight / 2, pbWidth, pbHeight, 6);
                pbBg.strokeRoundedRect(-pbWidth / 2, -pbHeight / 2, pbWidth, pbHeight, 6);
                progressContainer.add(pbBg);

                // Track Line di dalam progress bar
                const track = this.add.graphics();
                track.fillStyle(0x15803d, 0.5);
                track.fillRect(-pbWidth / 2 + 10, -2, pbWidth - 20, 4);
                progressContainer.add(track);

                // Marker Finish di ujung KIRI (karena perahu melaju ke kiri)
                const finishMarker = this.add.text(-pbWidth / 2 + 14, 0, '🏁', {
                    fontSize: '11px'
                }).setOrigin(0.5);
                progressContainer.add(finishMarker);

                // Marker Pemain (P) dan Lawan (L) mulai dari KANAN
                this.playerMarker = this.add.text(pbWidth / 2 - 10, -1, 'P', {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '9px',
                    color: '#ffffff',
                    stroke: '#15803d',
                    strokeThickness: 3
                }).setOrigin(0.5);

                this.opponentMarker = this.add.text(pbWidth / 2 - 10, -1, 'L', {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '9px',
                    color: '#f59e0b',
                    stroke: '#78350f',
                    strokeThickness: 3
                }).setOrigin(0.5);

                progressContainer.add(this.playerMarker);
                progressContainer.add(this.opponentMarker);

                // --- 6. UI KONTROL & PENGUKUR KECEPATAN (BAWAH SCREEN) ---
                // Rhythm Timing Bar Container
                const barContainer = this.add.container(cx, H - 220);
                barContainer.setDepth(2000);

                // Bar background & zones (Red, Yellow, Green, Yellow, Red)
                const barGfx = this.add.graphics();
                // Red (outer sides)
                barGfx.fillStyle(0xef4444, 1);
                barGfx.fillRect(-100, -7, 40, 14);
                barGfx.fillRect(60, -7, 40, 14);
                // Yellow (middle sides)
                barGfx.fillStyle(0xf59e0b, 1);
                barGfx.fillRect(-60, -7, 40, 14);
                barGfx.fillRect(20, -7, 40, 14);
                // Green (center perfect)
                barGfx.fillStyle(0x22c55e, 1);
                barGfx.fillRect(-20, -7, 40, 14);
                // White border
                barGfx.lineStyle(2, 0xffffff, 1);
                barGfx.strokeRect(-100, -7, 200, 14);
                barContainer.add(barGfx);

                // Pointer
                this.pointerGfx = this.add.graphics();
                this.pointerGfx.fillStyle(0xffffff, 1);
                this.pointerGfx.lineStyle(1.5, 0x000000, 1);
                // Draw triangle pointing down to touch the bar top edge
                this.pointerGfx.fillTriangle(0, -7, -5, -15, 5, -15);
                this.pointerGfx.strokeTriangle(0, -7, -5, -15, 5, -15);
                barContainer.add(this.pointerGfx);

                // Tombol PADDLE / TEKAN di bawah bar
                const paddleBtnY = H - 170;
                const paddleBtn = this.add.container(cx, paddleBtnY);
                paddleBtn.setDepth(2000);
                const pBtnW = 140;
                const pBtnH = 38;

                const pBtnGfx = this.add.graphics();
                const drawPaddleBtn = (hovered) => {
                    pBtnGfx.clear();
                    pBtnGfx.fillStyle(hovered ? 0x15803d : 0x22c55e, 1);
                    pBtnGfx.lineStyle(3, 0x14532d, 1);
                    // Shadow
                    pBtnGfx.fillStyle(0x14532d, 0.22);
                    pBtnGfx.fillRoundedRect(-pBtnW / 2 + 3, -pBtnH / 2 + 3, pBtnW, pBtnH, 8);
                    // Main button
                    pBtnGfx.fillStyle(hovered ? 0x15803d : 0x22c55e, 1);
                    pBtnGfx.fillRoundedRect(-pBtnW / 2, -pBtnH / 2, pBtnW, pBtnH, 8);
                    pBtnGfx.strokeRoundedRect(-pBtnW / 2, -pBtnH / 2, pBtnW, pBtnH, 8);
                };
                drawPaddleBtn(false);
                paddleBtn.add(pBtnGfx);

                const pBtnTxt = this.add.text(0, 0, 'KAYUAH (TAP)', {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '10px',
                    color: '#ffffff',
                    fontStyle: 'bold',
                    stroke: '#14532d',
                    strokeThickness: 3
                }).setOrigin(0.5);
                paddleBtn.add(pBtnTxt);

                paddleBtn.setSize(pBtnW, pBtnH);
                paddleBtn.setInteractive({ useHandCursor: true });

                // Event listener klik tombol TEKAN
                paddleBtn.on('pointerover', () => drawPaddleBtn(true));
                paddleBtn.on('pointerout', () => drawPaddleBtn(false));
                paddleBtn.on('pointerdown', () => {
                    if (this.gameState !== 'racing') return;

                    this.tweens.add({
                        targets: paddleBtn,
                        scaleX: 0.9, scaleY: 0.9,
                        duration: 50, yoyo: true
                    });

                    // Evaluasi posisi pointer ritme
                    const absX = Math.abs(this.pointerX);
                    let speedBoost = 0;
                    let feedbackStr = "";
                    let tintTop = 0xffffff;
                    let tintBottom = 0xffffff;
                    let feedbackStroke = "";

                    if (absX <= 20) { // Green (Perfect)
                        speedBoost = 5; // Sangat kencang!
                        feedbackStr = "BAKABUUIKKK!!";
                        tintTop = 0xffea00; // Kuning/Emas
                        tintBottom = 0xff0055; // Merah/Pink Neon
                        feedbackStroke = "#4c0519";
                        this.cameras.main.shake(100, 0.004);
                        this.playerRowers.emitters.forEach(emitter => {
                            emitter.explode(22);
                        });
                    } else if (absX <= 60) { // Yellow (Good)
                        speedBoost = 2; // Lumayan
                        feedbackStr = "KAYUAHHHHH!";
                        tintTop = 0x00ffff; // Cyan
                        tintBottom = 0x0000ff; // Biru Gelap
                        feedbackStroke = "#0f172a";
                        this.cameras.main.shake(60, 0.002);
                        this.playerRowers.emitters.forEach(emitter => {
                            emitter.explode(10);
                        });
                    } else { // Red (Bad)
                        speedBoost = 0; // Buruk (Tidak nambah kecepatan)
                        feedbackStr = "LOMAHHHH!";
                        tintTop = 0xff0000; // Merah
                        tintBottom = 0x440000; // Merah Gelap
                        feedbackStroke = "#000000";
                    }

                    // Tambah speed
                    this.playerSpeed = Math.min(this.maxSpeed, this.playerSpeed + speedBoost);

                    // Tampilkan kata pop up di atas perahu player
                    this.showFeedbackText(feedbackStr, tintTop, tintBottom, feedbackStroke);
                });

                // Panel Speedometer di bagian atas-tengah di bawah progress bar (Glassmorphism)
                const speedContainer = this.add.container(cx, 114);
                const sBg = this.add.graphics();
                sBg.fillStyle(0xffffff, 0.22);
                sBg.lineStyle(1.5, 0xffffff, 0.35);
                sBg.fillRoundedRect(-70, -11, 140, 22, 6);
                sBg.strokeRoundedRect(-70, -11, 140, 22, 6);
                speedContainer.add(sBg);

                this.speedText = this.add.text(0, 0, 'SPEED: 0 km/h', {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '7px',
                    color: '#ffffff',
                    stroke: '#15803d',
                    strokeThickness: 2
                }).setOrigin(0.5);
                speedContainer.add(this.speedText);

                // --- 7. TOMBOL KEMBALI & KOIN HEADER ---
                const backBtnContainer = this.add.container(38, 34);
                backBtnContainer.setSize(48, 48);
                backBtnContainer.setInteractive({ useHandCursor: true });

                const backBtnBg = this.add.graphics();
                const drawBackBtnBg = (fillAlpha, lineAlpha, lineWidth) => {
                    backBtnBg.clear();
                    backBtnBg.fillStyle(0xffffff, fillAlpha);
                    backBtnBg.lineStyle(lineWidth, 0xffffff, lineAlpha);
                    backBtnBg.fillRoundedRect(-24, -24, 48, 48, 8);
                    backBtnBg.strokeRoundedRect(-24, -24, 48, 48, 8);
                };
                drawBackBtnBg(0.2, 0.4, 2);
                backBtnContainer.add(backBtnBg);

                const backIcon = this.add.image(0, 0, 'back').setDisplaySize(32, 32);
                backBtnContainer.add(backIcon);

                backBtnContainer.on('pointerdown', () => {
                    this.tweens.add({
                        targets: backBtnContainer,
                        scaleX: 0.8, scaleY: 0.8,
                        duration: 80, ease: 'Power2',
                        yoyo: true,
                        onComplete: () => {
                            this.cameras.main.fadeOut(300, 240, 253, 244);
                            this.cameras.main.once('camerafadeoutcomplete', () => {
                                window.location.href = '../mainmenu.php';
                            });
                        }
                    });
                });

                backBtnContainer.on('pointerover', () => {
                    drawBackBtnBg(0.35, 0.7, 2.5);
                    this.tweens.add({ targets: backBtnContainer, scaleX: 1.05, scaleY: 1.05, duration: 90 });
                });
                backBtnContainer.on('pointerout', () => {
                    drawBackBtnBg(0.2, 0.4, 2);
                    this.tweens.add({ targets: backBtnContainer, scaleX: 1, scaleY: 1, duration: 90 });
                });

                // KOIN TOP RIGHT
                const COIN_ICON_X = W - 78;
                this.coinImg = this.add.image(COIN_ICON_X, 34, 'koin').setDisplaySize(36, 36);
                let coinCount = parseInt(localStorage.getItem('coins') || '100000');
                this.coinText = this.add.text(COIN_ICON_X + 22, 35, String(coinCount), {
                    fontFamily: '"Pixelify Sans", monospace',
                    fontSize: '13px',
                    fontStyle: 'bold',
                    color: '#FFD700',
                    stroke: '#15803d',
                    strokeThickness: 3
                }).setOrigin(0, 0.5);

                // --- 8. COUNTDOWN 3, 2, 1, GO! ---
                this.countdownText = this.add.text(cx, H / 2, 'READY?', {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '28px',
                    color: '#ffffff',
                    stroke: '#000000',
                    strokeThickness: 8,
                    align: 'center',
                    shadow: { offsetX: 4, offsetY: 4, color: '#000', blur: 0, fill: true }
                }).setOrigin(0.5).setDepth(1000);

                // Efek Warna Gradasi Retro untuk READY?
                this.countdownText.setTint(0x00ffff, 0x00ffff, 0xff00ff, 0xff00ff); // Cyan ke Magenta

                // Efek Listrik / Heboh bergetar (Dikurangi sesuai permintaan)
                this.tweens.add({
                    targets: this.countdownText,
                    angle: { from: -1, to: 1 },
                    scaleX: { value: '+=0.02', duration: 60 },
                    scaleY: { value: '+=0.02', duration: 60 },
                    duration: 60,
                    yoyo: true,
                    repeat: -1,
                    ease: 'Sine.easeInOut'
                });

                // Jalankan Sequence Countdown tanpa Nesting
                let count = 3;
                const countdownTimer = this.time.addEvent({
                    delay: 1000,
                    loop: true,
                    callback: () => {
                        if (count > 0) {
                            this.countdownText.setText(String(count));
                            // Gradasi angka 3,2,1 (Kuning ke Oranye)
                            this.countdownText.setTint(0xffff00, 0xffff00, 0xff6600, 0xff6600);
                            this.countdownText.setScale(0.8);
                            this.tweens.add({ targets: this.countdownText, scaleX: 1.2, scaleY: 1.2, duration: 300, ease: 'Back.easeOut' });

                            if (this.sparkEmitter) {
                                const txtW = this.countdownText.width;
                                for (let i = 0; i < 20; i++) {
                                    const randX = cx + Phaser.Math.Between(-txtW / 2 - 10, txtW / 2 + 10);
                                    const randY = (H / 2) + Phaser.Math.Between(-15, 15);
                                    this.sparkEmitter.emitParticleAt(randX, randY);
                                }
                            }

                            count--;
                        } else if (count === 0) {
                            this.countdownText.setText('GO!!');
                            // Gradasi GO!! (Kuning/Emas ke Merah menyala)
                            this.countdownText.setTint(0xffea00, 0xffea00, 0xff0000, 0xff0000);
                            this.countdownText.setScale(1.0);
                            this.countdownText.setStroke('#4c0519', 8);
                            this.tweens.add({ targets: this.countdownText, scaleX: 1.5, scaleY: 1.5, duration: 300, ease: 'Back.easeOut' });

                            if (this.sparkEmitter) {
                                const txtW = this.countdownText.width;
                                for (let i = 0; i < 40; i++) {
                                    const randX = cx + Phaser.Math.Between(-txtW / 2 - 20, txtW / 2 + 20);
                                    const randY = (H / 2) + Phaser.Math.Between(-20, 20);
                                    this.sparkEmitter.emitParticleAt(randX, randY);
                                }
                            }

                            this.gameState = 'racing';
                            count--;
                        } else {
                            this.countdownText.setVisible(false);
                            countdownTimer.destroy();
                        }
                    }
                });
            }

            showFeedbackText(txt, tintTop, tintBottom, stroke) {
                const cx = this.scale.width / 2;
                const container = this.add.container(cx, 380);
                container.setDepth(1000);

                const popText = this.add.text(
                    0, 0,
                    txt, {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '18px', // Lebihkan sikit biar heboh
                    color: '#ffffff', // Warna dasar putih agar tint gradien terlihat
                    stroke: stroke,
                    strokeThickness: 8,
                    align: 'center',
                    shadow: { offsetX: 3, offsetY: 3, color: '#000', blur: 0, fill: true }
                }
                ).setOrigin(0.5);

                // Aplikasikan gradasi retro vertikal
                popText.setTint(tintTop, tintTop, tintBottom, tintBottom);

                container.add(popText);

                // Ledakkan partikel listrik merata di sepanjang lebar teks!
                if (this.sparkEmitter) {
                    const txtW = popText.width;
                    for (let i = 0; i < 30; i++) {
                        const randX = cx + Phaser.Math.Between(-txtW / 2 - 10, txtW / 2 + 10);
                        const randY = 380 + Phaser.Math.Between(-15, 15);
                        this.sparkEmitter.emitParticleAt(randX, randY);
                    }
                }

                // Efek Listrik / Heboh (Shaking & Scaling dikurangi sesuai permintaan)
                this.tweens.add({
                    targets: popText,
                    angle: { from: -1, to: 1 },
                    scaleX: { from: 0.95, to: 1.05 },
                    scaleY: { from: 0.95, to: 1.05 },
                    duration: 60, // diperhalus
                    yoyo: true,
                    repeat: -1,
                    ease: 'Sine.easeInOut'
                });

                // Efek melayang ke atas dan hilang
                this.tweens.add({
                    targets: container,
                    y: container.y - 65,
                    alpha: 0,
                    duration: 850,
                    ease: 'Back.easeOut',
                    onComplete: () => container.destroy()
                });
            }

            // --- 9. MODAL POP-UP HASIL PERTANDINGAN (WIN/LOSE) ---
            showRaceResult(isWinner) {
                this.gameState = 'finished';
                this.playerSpeed = 0;
                this.opponentSpeed = 0;

                const W = this.scale.width;
                const H = this.scale.height;
                const cx = W / 2;

                // Stop animasinya
                this.playerRowers.rowers.forEach(r => r.stop());
                this.opponentRowers.rowers.forEach(r => r.stop());

                // Sembunyikan semua elemen game kecuali background menu
                this.children.list.forEach(child => {
                    if (child.texture && child.texture.key === 'bgmenu') return;
                    child.setVisible(false);
                });

                // Overlay Gelap
                const overlay = this.add.graphics();
                overlay.fillStyle(0x042f1a, 0.62);
                overlay.fillRect(0, 0, W, H);
                overlay.setAlpha(0);
                this.tweens.add({ targets: overlay, alpha: 1, duration: 450 });

                // Modal Container
                const modal = this.add.container(cx, H / 2);
                modal.setScale(0);

                const modalW = W - 50;
                const modalH = 290;
                const modalBg = this.add.graphics();

                // Shadow
                modalBg.fillStyle(0x14532d, 0.28);
                modalBg.fillRoundedRect(-modalW / 2 + 6, -modalH / 2 + 6, modalW, modalH, 16);

                // Body
                modalBg.fillStyle(0xffffff, 0.95);
                modalBg.lineStyle(5, isWinner ? 0x22c55e : 0xef4444, 1);
                modalBg.fillRoundedRect(-modalW / 2, -modalH / 2, modalW, modalH, 16);
                modalBg.strokeRoundedRect(-modalW / 2, -modalH / 2, modalW, modalH, 16);
                modal.add(modalBg);

                // Judul Result
                const titleStr = isWinner ? '✦ KEMENANGAN ✦' : '✦ KEKALAHAN ✦';
                const titleCol = isWinner ? '#16a34a' : '#dc2626';
                const strokeCol = isWinner ? '#dcfce7' : '#fee2e2';

                const titleTxt = this.add.text(0, -modalH / 2 + 35, titleStr, {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '14px',
                    color: titleCol,
                    fontStyle: 'bold',
                    stroke: strokeCol,
                    strokeThickness: 3
                }).setOrigin(0.5);
                modal.add(titleTxt);

                // Detil Hadiah Koin
                const coinsReward = isWinner ? 500 : 150;
                // Simpan ke localStorage
                let currentCoins = parseInt(localStorage.getItem('coins') || '100000');
                localStorage.setItem('coins', String(currentCoins + coinsReward));
                this.coinText.setText(String(currentCoins + coinsReward));

                const msgStr = isWinner
                    ? "Hebat! Kamu berhasil\nmenjadi yang tercepat!"
                    : "Sayang sekali!\nLawan mendahuluimu.";

                const msgTxt = this.add.text(0, -25, msgStr, {
                    fontFamily: '"Pixelify Sans", monospace',
                    fontSize: '14px',
                    fontStyle: 'bold',
                    color: '#374151',
                    align: 'center',
                    lineSpacing: 4
                }).setOrigin(0.5);
                modal.add(msgTxt);

                // Ikon koin hadiah
                const coinGroup = this.add.container(0, 32);
                modal.add(coinGroup);
                const coinIcon = this.add.image(-25, 0, 'koin').setDisplaySize(28, 28);
                const rewardTxt = this.add.text(10, 0, `+${coinsReward}`, {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '12px',
                    color: '#d97706',
                    fontStyle: 'bold'
                }).setOrigin(0.5);
                coinGroup.add(coinIcon);
                coinGroup.add(rewardTxt);

                // --- 2 Tombol Modal (Main Lagi & Kembali) ---
                const btnW = 110;
                const btnH = 34;
                const btnY = modalH / 2 - 45;

                // Tombol Main Lagi
                const btnRetry = this.add.container(-60, btnY);
                modal.add(btnRetry);

                const btnR_gfx = this.add.graphics();
                const drawBtnR = (hovered) => {
                    btnR_gfx.clear();
                    btnR_gfx.fillStyle(hovered ? 0x15803d : 0x22c55e, 1);
                    btnR_gfx.lineStyle(2, 0x14532d, 1);
                    btnR_gfx.fillRoundedRect(-btnW / 2, -btnH / 2, btnW, btnH, 6);
                    btnR_gfx.strokeRoundedRect(-btnW / 2, -btnH / 2, btnW, btnH, 6);
                };
                drawBtnR(false);
                btnRetry.add(btnR_gfx);

                const btnR_txt = this.add.text(0, 0, 'LAGI', {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '7.5px',
                    color: '#ffffff',
                    stroke: '#14532d',
                    strokeThickness: 2
                }).setOrigin(0.5);
                btnRetry.add(btnR_txt);

                btnRetry.setSize(btnW, btnH);
                btnRetry.setInteractive({ useHandCursor: true });
                btnRetry.on('pointerover', () => drawBtnR(true));
                btnRetry.on('pointerout', () => drawBtnR(false));
                btnRetry.on('pointerdown', () => {
                    this.tweens.add({
                        targets: btnRetry,
                        scaleX: 0.9, scaleY: 0.9,
                        duration: 60, yoyo: true,
                        onComplete: () => {
                            this.scene.restart();
                        }
                    });
                });

                // Tombol Kembali ke Menu Utama
                const btnMenu = this.add.container(60, btnY);
                modal.add(btnMenu);

                const btnM_gfx = this.add.graphics();
                const drawBtnM = (hovered) => {
                    btnM_gfx.clear();
                    btnM_gfx.fillStyle(hovered ? 0x4b5563 : 0x6b7280, 1);
                    btnM_gfx.lineStyle(2, 0x374151, 1);
                    btnM_gfx.fillRoundedRect(-btnW / 2, -btnH / 2, btnW, btnH, 6);
                    btnM_gfx.strokeRoundedRect(-btnW / 2, -btnH / 2, btnW, btnH, 6);
                };
                drawBtnM(false);
                btnMenu.add(btnM_gfx);

                const btnM_txt = this.add.text(0, 0, 'MENU', {
                    fontFamily: '"Press Start 2P", monospace',
                    fontSize: '7.5px',
                    color: '#ffffff',
                    stroke: '#374151',
                    strokeThickness: 2
                }).setOrigin(0.5);
                btnMenu.add(btnM_txt);

                btnMenu.setSize(btnW, btnH);
                btnMenu.setInteractive({ useHandCursor: true });
                btnMenu.on('pointerover', () => drawBtnM(true));
                btnMenu.on('pointerout', () => drawBtnM(false));
                btnMenu.on('pointerdown', () => {
                    this.tweens.add({
                        targets: btnMenu,
                        scaleX: 0.9, scaleY: 0.9,
                        duration: 60, yoyo: true,
                        onComplete: () => {
                            this.cameras.main.fadeOut(300, 240, 253, 244);
                            this.cameras.main.once('camerafadeoutcomplete', () => {
                                window.location.href = '../mainmenu.php';
                            });
                        }
                    });
                });

                // Animasi masuk modal
                this.tweens.add({
                    targets: modal,
                    scaleX: 1, scaleY: 1,
                    duration: 500,
                    ease: 'Back.easeOut'
                });
            }

            update(time, delta) {
                const W = this.scale.width;

                if (this.gameState === 'racing') {
                    // --- Update Rhythm Pointer ---
                    this.pointerTime += delta;
                    // Pointer berayun ke kiri dan kanan dari -100 ke +100
                    this.pointerX = Math.sin(this.pointerTime / 250) * 100;
                    this.pointerGfx.x = this.pointerX;

                    // Kecepatan konstan 8.5 untuk lawan (default speed diturunkan sedikit)
                    this.opponentSpeed = 8.5;

                    // Update drag player speed
                    // Jika player tidak tap, kecepatan sama dengan lawan (seri)
                    // Jika di tap, player speed bertambah lalu perlahan turun ke kecepatan lawan
                    if (this.playerSpeed > this.opponentSpeed) {
                        this.playerSpeed = Math.max(this.opponentSpeed, this.playerSpeed - 0.06);
                    } else {
                        this.playerSpeed = this.opponentSpeed;
                    }

                    // Mengurangi sisa jarak tempuh
                    this.playerDistance = Math.max(0, this.playerDistance - this.playerSpeed * (delta / 1000));
                    this.opponentDistance = Math.max(0, this.opponentDistance - this.opponentSpeed * (delta / 1000));

                    // Kecepatan scroll background dikendalikan oleh player
                    this.scrollSpeed = this.playerSpeed * 0.3;

                    // Update UI Teks Kecepatan
                    this.speedText.setText(`SPEED: ${Math.round(this.playerSpeed * 3.6)} km/h`);

                    // Sinkronisasi frame rate mendayung berdasarkan kecepatan masing-masing
                    // Animasi player tetap berjalan dengan kecepatan dasar meski tidak di tap
                    this.playerRowers.rowers.forEach(r => {
                        if (!r.anims.isPlaying) r.play('player_rowing_anim');
                        r.anims.timeScale = 0.8 + (this.playerSpeed / 10);
                    });

                    if (this.opponentSpeed > 0) {
                        this.opponentRowers.rowers.forEach(r => {
                            if (!r.anims.isPlaying) r.play('opponent_rowing_anim');
                            r.anims.timeScale = this.opponentSpeed / 8.5;
                        });
                    }
                } // <--- END OF RACING STATE LOGIC (Speed/Distance Updates)

                // =========================================================
                // VISUAL UPDATES (Runs constantly regardless of state)
                // =========================================================

                // --- Pergeseran Posisi Boat Secara Visual ---
                // Player dijangkar di tengah layar (cx)
                // Posisi lawan (Opponent) digeser maju/mundur berdasarkan selisih jarak
                const distDiff = this.playerDistance - this.opponentDistance;
                const visualOffsetScale = 6; // Pergeseran pixel per meter selisih
                // Karena balapan arah KIRI, maka saat player menang (distDiff negatif), lawan harus tertinggal (geser ke KANAN / X bertambah)
                const targetOpponentX = (W / 2) - distDiff * visualOffsetScale;

                // Biarkan lawan bisa keluar layar jika tertinggal jauh atau memimpin sangat jauh
                this.opponentBoatGroup.x = targetOpponentX;

                // --- Efek Emitter Cipratan Air berdasarkan Kecepatan ---
                this.playerRowers.emitters.forEach(emitter => {
                    emitter.setParticleSpeed(45 + this.playerSpeed * 6, 60 + this.playerSpeed * 10);
                });

                // --- Scroll Penonton & Tribun ---
                // Perahu maju ke kiri, berarti penonton & tribun scroll ke kanan
                this.spectators.forEach(specData => {
                    specData.sprite.x += this.scrollSpeed;
                    if (specData.sprite.x > W + 80) {
                        specData.sprite.x = -60 - Math.random() * 30;
                    }
                });

                // --- Scroll Pancang Pemisah ---
                // Jarak visual 1 meter = 18 pixel (sesuai konversi scrollSpeed)
                const DISTANCE_TO_PIXELS = 18;
                // Offset moncong perahu agar pancang pas di depan perahu saat jarak cocok
                const MONCONG_OFFSET = 130;
                this.pancangs.forEach(p => {
                    // Jika playerDistance == p.dist, maka pancang tepat di moncong perahu (kiri cx)
                    p.sprite.x = (W / 2) - MONCONG_OFFSET - (this.playerDistance - p.dist) * DISTANCE_TO_PIXELS;
                });

                // Agar air mengalir ke kanan (perahu ke kiri), kurangi tilePositionX
                this.riverTile.tilePositionX -= this.scrollSpeed;

                // Shimmer mengalir sedikit lebih cepat dan turun perlahan untuk efek arus
                this.shimmerTile.tilePositionX -= (this.scrollSpeed * 1.3 + 0.4);
                this.shimmerTile.tilePositionY += 0.15;

                // --- Sinkronisasi Progress Bar Marker ---
                // Karena balapan ke KIRI, marker bergerak dari kanan (+80) ke kiri (-60)
                const barStart = 80;
                const barLength = -140;

                const playerProgress = 1 - (this.playerDistance / this.raceDistance);
                this.playerMarker.x = barStart + playerProgress * barLength;

                const opponentProgress = 1 - (this.opponentDistance / this.raceDistance);
                this.opponentMarker.x = barStart + opponentProgress * barLength;

                // --- Pemicu Garis Finish ---
                // (Visual garis hitam dihapus)

                // --- Check Finish Rule ---
                if (this.gameState === 'racing') {
                    if (this.playerDistance <= 0) {
                        this.showRaceResult(true); // Player menang!
                    } else if (this.opponentDistance <= 0) {
                        this.showRaceResult(false); // Opponent menang
                    }
                }
            }
        }

        // =====================================================
        //  INIT PHASER
        // =====================================================
        const game = new Phaser.Game({
            type: Phaser.AUTO,
            width: GAME_WIDTH,
            height: GAME_HEIGHT,
            backgroundColor: '#f0fdf4',
            parent: 'game-container',
            pixelArt: true,
            scene: [ArenaScene],
            scale: {
                mode: Phaser.Scale.RESIZE,
                autoCenter: Phaser.Scale.CENTER_BOTH
            }
        });
    </script>

    <script src="../assets/js/game-layout.js?v=<?= time() ?>"></script>
</body>

</html>