<template>
    <div class="datav-container">
        <!-- Three.js 画布容器 -->
        <div ref="canvasContainer" class="canvas-container"></div>
        
        <!-- 顶部标题 -->
        <div class="header">
            <div class="title">牛只运输监控大屏</div>
            <div class="subtitle">CATTLE TRANSPORT MONITORING SYSTEM</div>
        </div>

        <!-- 全屏控制按钮 -->
        <div class="controls">
            <button @click="toggleFullScreen">全屏沉浸体验</button>
        </div>

        <!-- 加载提示 -->
        <div v-if="loading" class="loading-overlay">
            <div class="loading-text">正在构建地形地图数据...</div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import * as d3 from 'd3-geo';
import { getDatavData } from '@/api/datav.js';

// 状态
const canvasContainer = ref<HTMLElement | null>(null);
const loading = ref(true);
let scene: THREE.Scene;
let camera: THREE.PerspectiveCamera;
let renderer: THREE.WebGLRenderer;
let controls: OrbitControls;
let animationFrameId: number;
let clock: THREE.Clock;

// 地图相关变量
let terrainMesh: THREE.Mesh | null = null;
let terrainGroup: THREE.Group;
let mapBorderGroup: THREE.Group;
let flyLineGroup: THREE.Group;
let bgParticlesGroup: THREE.Group;
let uniforms: {
    uTime: { value: number };
    uHeightScale: { value: number };
    uNoiseScale: { value: number };
    uLightDir: { value: THREE.Vector3 };
    uBaseColor: { value: THREE.Color };
    uMountainColor: { value: THREE.Color };
    uVegetationColor: { value: THREE.Color };
    uVegetationDensity: { value: number };
    uBorderColor: { value: THREE.Color };
    uCameraPos: { value: THREE.Vector3 };
};

// 飞线数据 (起始地 -> 目的地)
let transportRoutes: Array<{ from: [number, number]; to: [number, number] }> = [];

// 地形顶点着色器
const terrainVertexShader = `
    uniform float uTime;
    uniform float uHeightScale;
    uniform float uNoiseScale;
    
    varying vec2 vUv;
    varying vec3 vNormal;
    varying vec3 vPosition;
    varying vec3 vWorldPosition;
    varying float vElevation;
    
    // 噪声函数
    float random(vec2 st) {
        return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
    }
    
    float noise(vec2 st) {
        vec2 i = floor(st);
        vec2 f = fract(st);
        float a = random(i);
        float b = random(i + vec2(1.0, 0.0));
        float c = random(i + vec2(0.0, 1.0));
        float d = random(i + vec2(1.0, 1.0));
        vec2 u = f * f * (3.0 - 2.0 * f);
        return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
    }
    
    // 分形布朗运动 - 生成地形
    float fbm(vec2 st) {
        float value = 0.0;
        float amplitude = 0.5;
        float frequency = 1.0;
        for (int i = 0; i < 6; i++) {
            value += amplitude * noise(st * frequency);
            frequency *= 2.0;
            amplitude *= 0.5;
        }
        return value;
    }
    
    void main() {
        vUv = uv;
        vPosition = position;
        
        // 计算地形高度
        vec2 noiseCoord = uv * uNoiseScale;
        float elevation = fbm(noiseCoord);
        vElevation = elevation;
        
        // 应用高度偏移
        vec3 pos = position;
        pos.z += elevation * uHeightScale;
        
        // 计算法线（用于光照）
        float offset = 0.01;
        float hL = fbm((uv + vec2(offset, 0.0)) * uNoiseScale);
        float hR = fbm((uv + vec2(-offset, 0.0)) * uNoiseScale);
        float hD = fbm((uv + vec2(0.0, offset)) * uNoiseScale);
        float hU = fbm((uv + vec2(0.0, -offset)) * uNoiseScale);
        
        vec3 normal = normalize(vec3(
            (hL - hR) / (2.0 * offset),
            (hD - hU) / (2.0 * offset),
            1.0
        ));
        vNormal = normal;
        
        vec4 worldPos = modelMatrix * vec4(pos, 1.0);
        vWorldPosition = worldPos.xyz;
        
        gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
    }
`;

// 地形片元着色器（包含植被效果）
const terrainFragmentShader = `
    uniform float uTime;
    uniform vec3 uLightDir;
    uniform vec3 uBaseColor;
    uniform vec3 uMountainColor;
    uniform vec3 uVegetationColor;
    uniform float uVegetationDensity;
    
    varying vec2 vUv;
    varying vec3 vNormal;
    varying vec3 vPosition;
    varying vec3 vWorldPosition;
    varying float vElevation;
    
    // 噪声函数（与顶点着色器相同）
    float random(vec2 st) {
        return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
    }
    
    float noise(vec2 st) {
        vec2 i = floor(st);
        vec2 f = fract(st);
        float a = random(i);
        float b = random(i + vec2(1.0, 0.0));
        float c = random(i + vec2(0.0, 1.0));
        float d = random(i + vec2(1.0, 1.0));
        vec2 u = f * f * (3.0 - 2.0 * f);
        return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
    }
    
    float fbm(vec2 st) {
        float value = 0.0;
        float amplitude = 0.5;
        float frequency = 1.0;
        for (int i = 0; i < 4; i++) {
            value += amplitude * noise(st * frequency);
            frequency *= 2.0;
            amplitude *= 0.5;
        }
        return value;
    }
    
    void main() {
        // 基础地形颜色（根据高度）
        vec3 baseTerrain = mix(uBaseColor, uMountainColor, vElevation);
        
        // 植被层（在低海拔区域）
        float vegetationMask = 1.0 - smoothstep(0.3, 0.7, vElevation);
        float vegetationNoise = fbm(vUv * 20.0 + uTime * 0.1);
        vegetationMask *= step(0.3, vegetationNoise) * uVegetationDensity;
        
        vec3 vegetation = uVegetationColor * vegetationMask;
        
        // 光照计算
        vec3 normal = normalize(vNormal);
        vec3 lightDir = normalize(uLightDir);
        float diff = max(dot(normal, lightDir), 0.1);
        
        // 最终颜色
        vec3 finalColor = (baseTerrain + vegetation) * diff;
        
        // 添加一些细节纹理
        float detail = fbm(vUv * 50.0);
        finalColor += (detail - 0.5) * 0.1;
        
        // 添加一些环境光
        finalColor += vec3(0.05, 0.05, 0.08);
        
        gl_FragColor = vec4(finalColor, 1.0);
    }
`;

// 边框发光着色器
const borderVertexShader = `
    varying vec3 vWorldPosition;
    varying vec3 vNormal;
    
    void main() {
        vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
        vNormal = normalize(normalMatrix * normal);
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
`;

const borderFragmentShader = `
    uniform vec3 uBorderColor;
    uniform float uTime;
    uniform vec3 uCameraPos;
    
    varying vec3 vWorldPosition;
    varying vec3 vNormal;
    
    void main() {
        // 计算到相机的距离
        float dist = distance(vWorldPosition, uCameraPos);
        
        // 菲涅尔效应 - 边缘发光
        vec3 viewDir = normalize(uCameraPos - vWorldPosition);
        vec3 normal = normalize(vNormal);
        float fresnel = pow(1.0 - max(dot(viewDir, normal), 0.0), 2.0);
        
        // 发光强度
        float glow = fresnel * 2.0;
        
        // 添加脉冲效果
        float pulse = sin(uTime * 2.0) * 0.5 + 0.5;
        glow += pulse * 0.3;
        
        vec3 finalColor = uBorderColor * glow;
        float alpha = min(glow, 1.0);
        
        gl_FragColor = vec4(finalColor, alpha);
    }
`;

// 飞线顶点着色器
const flylineVertexShader = `
    attribute float percent;
    varying float vPercent;
    uniform float uTime;
    
    void main() {
        vPercent = percent;
        vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
        gl_Position = projectionMatrix * mvPosition;
    }
`;

// 飞线片元着色器
const flylineFragmentShader = `
    varying float vPercent;
    uniform float uTime;
    uniform vec3 uColor;
    
    void main() {
        // 飞线动画
        float length = 0.3; // 拖尾长度
        float speed = 0.8;
        float loop = fract(uTime * speed); // 0~1 循环
        
        // 计算当前像素在飞线上的位置是否应该发光
        float dist = distance(vPercent, loop);
        
        // 处理循环边界 (例如 0.9 和 0.1 应该也很远，但在循环中很近，这里简化处理)
        // 实际上对于飞线，我们希望它是一段一段飞过去
        
        float alpha = 0.0;
        if (vPercent < loop && vPercent > loop - length) {
            alpha = (vPercent - (loop - length)) / length; // 渐变拖尾
            alpha = pow(alpha, 2.0); // 增强头部亮度
        }
        
        // 基础底色透明度
        float baseAlpha = 0.1;
        
        gl_FragColor = vec4(uColor, baseAlpha + alpha);
    }
`;

// 初始化 Three.js 场景
const initThreeScene = () => {
    if (!canvasContainer.value) return;

    // 1. 场景
    scene = new THREE.Scene();
    scene.fog = new THREE.FogExp2(0x000000, 0.0008);

    // 2. 相机
    const width = canvasContainer.value.clientWidth;
    const height = canvasContainer.value.clientHeight;
    camera = new THREE.PerspectiveCamera(60, width / height, 1, 10000);
    camera.position.set(0, -100, 200); 
    camera.lookAt(0, 0, 0);

    // 3. 渲染器
    renderer = new THREE.WebGLRenderer({ 
        antialias: true, 
        alpha: true,
        powerPreference: "high-performance"
    });
    renderer.setSize(width, height);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    renderer.setClearColor(0x000000, 0);
    canvasContainer.value.appendChild(renderer.domElement);

    // 4. 控制器
    controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;
    controls.minDistance = 10;
    controls.maxDistance = 800;
    controls.maxPolarAngle = Math.PI / 2 + 0.2;

    clock = new THREE.Clock();
    
    // 创建层级组
    bgParticlesGroup = new THREE.Group(); // 背景旋转粒子
    terrainGroup = new THREE.Group();     // 地形层
    mapBorderGroup = new THREE.Group();   // 地图边框
    flyLineGroup = new THREE.Group();     // 飞线层
    
    scene.add(bgParticlesGroup);
    scene.add(terrainGroup);
    scene.add(mapBorderGroup);
    scene.add(flyLineGroup);

    // 初始化 Uniforms
    uniforms = {
        uTime: { value: 0 },
        uHeightScale: { value: 15.0 },
        uNoiseScale: { value: 2.0 },
        uLightDir: { value: new THREE.Vector3(0.5, 0.8, 0.3).normalize() },
        uBaseColor: { value: new THREE.Color('#1a1a2e') },
        uMountainColor: { value: new THREE.Color('#16213e') },
        uVegetationColor: { value: new THREE.Color('#0f3460') },
        uVegetationDensity: { value: 0.3 },
        uBorderColor: { value: new THREE.Color('#ffffff') },
        uCameraPos: { value: new THREE.Vector3() }
    };

    // 窗口大小调整
    window.addEventListener('resize', onWindowResize);
};

// 生成背景旋转粒子 (开普勒轨道风格)
const createBackgroundParticles = () => {
    const count = 3000;
    const geometry = new THREE.BufferGeometry();
    const positions = new Float32Array(count * 3);
    const sizes = new Float32Array(count);
    const colors = new Float32Array(count * 3);
    
    const color1 = new THREE.Color('#1e3799');
    const color2 = new THREE.Color('#0c2461');

    for(let i = 0; i < count; i++) {
        // 环形分布
        const angle = Math.random() * Math.PI * 2;
        // 半径范围 200 - 500
        const radius = 200 + Math.random() * 300; 
        // 稍微有些高度差，形成圆盘状
        const height = (Math.random() - 0.5) * 50;
        
        positions[i*3] = Math.cos(angle) * radius;
        positions[i*3+1] = Math.sin(angle) * radius; // 竖起来的圆盘
        positions[i*3+2] = height;
        
        sizes[i] = Math.random() * 2;
        
        const c = Math.random() > 0.5 ? color1 : color2;
        colors[i*3] = c.r;
        colors[i*3+1] = c.g;
        colors[i*3+2] = c.b;
    }
    
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
    geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
    
    const material = new THREE.PointsMaterial({
        size: 2,
        vertexColors: true,
        map: createCircleTexture(),
        transparent: true,
        opacity: 0.6,
        depthWrite: false,
        blending: THREE.AdditiveBlending
    });
    
    const points = new THREE.Points(geometry, material);
    bgParticlesGroup.add(points);
};

// 创建圆形纹理
const createCircleTexture = () => {
    const canvas = document.createElement('canvas');
    canvas.width = 32;
    canvas.height = 32;
    const context = canvas.getContext('2d');
    if (context) {
        const gradient = context.createRadialGradient(16, 16, 0, 16, 16, 16);
        gradient.addColorStop(0, 'rgba(255,255,255,1)');
        gradient.addColorStop(1, 'rgba(255,255,255,0)');
        context.fillStyle = gradient;
        context.fillRect(0, 0, 32, 32);
    }
    const texture = new THREE.Texture(canvas);
    texture.needsUpdate = true;
    return texture;
};

// 创建地形网格（使用 LOD 优化）
const createTerrain = () => {
    const width = 400;
    const height = 400;
    const segments = 128; // 细分程度，影响地形细节
    
    const geometry = new THREE.PlaneGeometry(width, height, segments, segments);
    
    const material = new THREE.ShaderMaterial({
        uniforms: {
            uTime: uniforms.uTime,
            uHeightScale: uniforms.uHeightScale,
            uNoiseScale: uniforms.uNoiseScale,
            uLightDir: uniforms.uLightDir,
            uBaseColor: uniforms.uBaseColor,
            uMountainColor: uniforms.uMountainColor,
            uVegetationColor: uniforms.uVegetationColor,
            uVegetationDensity: uniforms.uVegetationDensity
        },
        vertexShader: terrainVertexShader,
        fragmentShader: terrainFragmentShader,
        side: THREE.DoubleSide
    });
    
    const terrain = new THREE.Mesh(geometry, material);
    terrain.rotation.x = -Math.PI / 2; // 平铺在地面
    terrain.position.y = -50; // 放在地图下方
    terrain.receiveShadow = false;
    terrain.castShadow = false;
    
    terrainGroup.add(terrain);
    terrainMesh = terrain;
    
    return terrain;
};

// 创建地图边框（发光效果）
const createMapBorder = async () => {
    try {
        // 投影转换
        const projection = d3.geoMercator().center([104, 35]).scale(400).translate([0, 0]);

        // 获取 GeoJSON
        const response = await fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json');
        const chinaJson = await response.json();

        // 合并所有边界点
        const borderPoints: THREE.Vector3[] = [];

        chinaJson.features.forEach((feature: any) => {
            if (feature.properties.name === "") return;

            const coordinates = feature.geometry.coordinates;
            const type = feature.geometry.type;
            const polygons = type === 'MultiPolygon' ? coordinates : [coordinates];

            polygons.forEach((polygon: any) => {
                const ring = type === 'MultiPolygon' ? polygon[0] : polygon[0];
                
                for (let i = 0; i < ring.length; i++) {
                    const [lng, lat] = ring[i];
                    const [x, y] = projection([lng, lat]) || [0, 0];
                    borderPoints.push(new THREE.Vector3(x, -y, 5)); // 稍微抬高一点
                }
            });
        });

        // 创建边框几何体（使用 Line 实现发光效果）
        if (borderPoints.length > 0) {
            // 创建边框线（使用 LineSegments 实现更粗的线条）
            const lineGeometry = new THREE.BufferGeometry().setFromPoints(borderPoints);
            
            // 使用自定义着色器材质实现发光效果
            const borderMaterial = new THREE.ShaderMaterial({
                uniforms: {
                    uBorderColor: uniforms.uBorderColor,
                    uTime: uniforms.uTime,
                    uCameraPos: uniforms.uCameraPos
                },
                vertexShader: borderVertexShader,
                fragmentShader: borderFragmentShader,
                transparent: true,
                blending: THREE.AdditiveBlending,
                linewidth: 2
            });
            
            const border = new THREE.Line(lineGeometry, borderMaterial);
            mapBorderGroup.add(border);
            
            // 添加额外的细线边框作为基础
            const baseLineMaterial = new THREE.LineBasicMaterial({
                color: 0xffffff,
                transparent: true,
                opacity: 0.4,
                linewidth: 1
            });
            const baseLine = new THREE.Line(lineGeometry, baseLineMaterial);
            mapBorderGroup.add(baseLine);
        }

        return projection;
    } catch (error) {
        console.error('Failed to load map border data:', error);
        return null;
    }
};

// 生成飞线 (3D 贝塞尔曲线)
const createFlyLines = (projection: any) => {
    if (!projection) return;
    transportRoutes.forEach(route => {
        const start = projection(route.from);
        const end = projection(route.to);
        if (!start || !end) return;

        const v0 = new THREE.Vector3(start[0], -start[1], 0);
        const v3 = new THREE.Vector3(end[0], -end[1], 0);
        
        // 计算控制点，使曲线拱起
        const dist = v0.distanceTo(v3);
        const height = dist * 0.5; // 拱起高度
        
        const v1 = v0.clone().lerp(v3, 0.33).add(new THREE.Vector3(0, 0, height));
        const v2 = v0.clone().lerp(v3, 0.67).add(new THREE.Vector3(0, 0, height));
        
        const curve = new THREE.CubicBezierCurve3(v0, v1, v2, v3);
        const points = curve.getPoints(50); // 50个分段
        
        // 创建飞线几何体
        const geometry = new THREE.BufferGeometry().setFromPoints(points);
        const percents = new Float32Array(points.length);
        for(let i=0; i<points.length; i++) {
            percents[i] = i / (points.length - 1);
        }
        geometry.setAttribute('percent', new THREE.BufferAttribute(percents, 1));
        
        const material = new THREE.ShaderMaterial({
            uniforms: {
                uTime: uniforms.uTime,
                uColor: { value: new THREE.Color('#ff9f43') } // 橙色飞线
            },
            vertexShader: flylineVertexShader,
            fragmentShader: flylineFragmentShader,
            transparent: true,
            depthWrite: false,
            blending: THREE.AdditiveBlending
        });
        
        const line = new THREE.Line(geometry, material);
        flyLineGroup.add(line);
        
        // 添加终点箭头 (圆锥体)
        const coneGeo = new THREE.ConeGeometry(1, 3, 8);
        const coneMat = new THREE.MeshBasicMaterial({ color: 0xff9f43 });
        const cone = new THREE.Mesh(coneGeo, coneMat);
        cone.position.copy(v3);
        // 箭头朝向曲线切线方向
        const tangent = curve.getTangent(1);
        cone.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), tangent);
        flyLineGroup.add(cone);
        
        // 起点光圈
        const ringGeo = new THREE.RingGeometry(1, 1.5, 16);
        const ringMat = new THREE.MeshBasicMaterial({ color: 0x00ffff, side: THREE.DoubleSide });
        const ring = new THREE.Mesh(ringGeo, ringMat);
        ring.position.copy(v0);
        flyLineGroup.add(ring);
    });
};

// 窗口大小调整处理
const onWindowResize = () => {
    if (!canvasContainer.value || !camera || !renderer) return;
    const width = canvasContainer.value.clientWidth;
    const height = canvasContainer.value.clientHeight;
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
    renderer.setSize(width, height);
};

// 全屏切换
const toggleFullScreen = () => {
    if (!document.fullscreenElement) {
        document.documentElement.requestFullscreen();
    } else {
        if (document.exitFullscreen) {
            document.exitFullscreen();
        }
    }
};

// 动画循环
const animate = () => {
    animationFrameId = requestAnimationFrame(animate);
    const elapsedTime = clock.getElapsedTime();

    // 更新 Uniforms
    if (uniforms) {
        uniforms.uTime.value = elapsedTime;
        uniforms.uCameraPos.value.copy(camera.position);
        
        // LOD 优化：根据相机距离调整地形细节
        const cameraDistance = camera.position.length();
        if (terrainMesh) {
            const geometry = terrainMesh.geometry as THREE.PlaneGeometry;
            // 可以根据距离动态调整 segments（这里简化处理）
            // 实际可以使用 THREE.LOD 对象
        }
    }

    // 旋转背景
    bgParticlesGroup.rotation.z = elapsedTime * 0.02; // 绕Z轴旋转 (垂直于地图)

    // 更新控制器
    controls.update();

    renderer.render(scene, camera);
};

onMounted(async () => {
    initThreeScene();
    createBackgroundParticles();
    
    // 创建地形
    createTerrain();
    
    // 获取数据
    const res = await getDatavData();
    if(res.data && res.data.routes) {
        transportRoutes = res.data.routes;
    }
    
    // 创建地图边框并获取投影
    const projection = await createMapBorder();
    
    // 生成飞线
    if (projection) {
        createFlyLines(projection);
    }
    
    loading.value = false;
    animate();
});

onUnmounted(() => {
    if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
    }
    window.removeEventListener('resize', onWindowResize);
    
    // 清理地形
    if (terrainMesh) {
        terrainMesh.geometry.dispose();
        if (terrainMesh.material instanceof THREE.Material) {
            terrainMesh.material.dispose();
        }
    }
    
    // 清理边框
    mapBorderGroup.traverse((child) => {
        if (child instanceof THREE.Mesh || child instanceof THREE.Line) {
            child.geometry.dispose();
            if (child.material instanceof THREE.Material) {
                child.material.dispose();
            }
        }
    });
    
    // 清理飞线
    flyLineGroup.traverse((child) => {
        if (child instanceof THREE.Mesh || child instanceof THREE.Line) {
            child.geometry.dispose();
            if (child.material instanceof THREE.Material) {
                child.material.dispose();
            }
        }
    });
    
    if (renderer) {
        renderer.dispose();
    }
});
</script>

<style scoped lang="scss">
.datav-container {
    width: 100vw;
    height: 100vh;
    position: relative;
    background: radial-gradient(circle at center, #050505 0%, #0b0b10 100%);
    overflow: hidden;
}

.canvas-container {
    width: 100%;
    height: 100%;
}

.header {
    position: absolute;
    top: 20px;
    left: 40px;
    z-index: 10;
    pointer-events: none;
}

.title {
    font-size: 2.5rem;
    font-weight: bold;
    color: #00ffff;
    letter-spacing: 5px;
    text-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
    margin-bottom: 5px;
}

.subtitle {
    font-size: 1rem;
    color: #c5a059;
    letter-spacing: 3px;
    font-family: 'Arial', sans-serif;
}

.controls {
    position: absolute;
    bottom: 40px;
    right: 40px;
    z-index: 10;
}

button {
    background: transparent;
    border: 1px solid rgba(197, 160, 89, 0.3);
    color: #c5a059;
    padding: 12px 30px;
    font-size: 0.8rem;
    cursor: pointer;
    transition: all 0.4s ease;
    text-transform: uppercase;
    letter-spacing: 2px;
    backdrop-filter: blur(5px);

    &:hover {
        background: rgba(197, 160, 89, 0.1);
        border-color: #c5a059;
        box-shadow: 0 0 15px rgba(197, 160, 89, 0.2);
    }
}

.loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.9);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 20;
}

.loading-text {
    color: #c5a059;
    font-size: 1.2rem;
    letter-spacing: 3px;
    animation: pulse 1.5s infinite;
}

@keyframes pulse {
    0% { opacity: 0.5; }
    50% { opacity: 1; }
    100% { opacity: 0.5; }
}
</style>
