// AERO SIMULATOR — wind tunnel with rotatable car using proper silhouettes
(function() {
  const useS = React.useState;
  const useE = React.useEffect;
  const useR = React.useRef;
  const useCb = React.useCallback;

  const AERO = {
    open_wheel: { cd: 0.92, cl: 3.20, dragN: 780, dfTotal: 1850, topSpeed: 340, label: "F1 SPEC", dfFront: 45, dfRear: 55 },
    gt:         { cd: 0.35, cl: 1.20, dragN: 420, dfTotal: 680,  topSpeed: 295, label: "GT3", dfFront: 42, dfRear: 58 },
    stock:      { cd: 0.38, cl: 0.55, dragN: 460, dfTotal: 340,  topSpeed: 290, label: "STOCK", dfFront: 38, dfRear: 62 },
    prototype:  { cd: 0.73, cl: 2.80, dragN: 650, dfTotal: 1520, topSpeed: 330, label: "LMH", dfFront: 44, dfRear: 56 },
    e_spec:     { cd: 0.28, cl: 0.90, dragN: 310, dfTotal: 520,  topSpeed: 260, label: "E-SPEC", dfFront: 48, dfRear: 52 },
  };

  const W = 800, H = 500;
  const CX = W / 2, CY = H * 0.44;
  const GROUND_Y = CY + 70;

  // F1 car side profile — accurate proportions: long nose, high airbox, low body, big rear wing
  const SIDE_PTS = [
    // Front wing tip
    [130, 10],
    [125, 6],
    // Front wing main plane
    [120, 4],
    [110, 2],
    // Nose cone — low and tapered
    [100, 0],
    [90, -4],
    [80, -8],
    // Front suspension area
    [60, -10],
    [50, -12],
    // Sidepod leading edge
    [30, -14],
    [20, -18],
    // Halo top
    [5, -24],
    [-5, -30],
    // Airbox / intake
    [-10, -38],
    [-15, -42],
    // Engine cover spine — highest point
    [-25, -44],
    [-35, -42],
    [-45, -38],
    // Engine cover taper down to rear
    [-55, -34],
    [-65, -30],
    [-75, -26],
    // Rear wing mounting
    [-80, -24],
    // Rear crash structure
    [-85, -20],
    [-90, -16],
    // Diffuser exit
    [-95, -8],
    [-98, 0],
    // Rear floor / plank
    [-95, 8],
    [-90, 10],
    // Underfloor — flat bottom
    [-80, 12],
    [-50, 12],
    [-20, 12],
    [20, 12],
    [50, 12],
    [80, 12],
    // Front floor edge
    [100, 10],
    [115, 10],
    [125, 10],
    [130, 10],
  ];

  // F1 front view — wide and low with visible front wing endplates
  const FRONT_PTS = [
    // Front wing endplate left
    [-55, 8],
    [-50, 4],
    // Body side
    [-38, 0],
    [-35, -8],
    [-30, -16],
    // Sidepod top
    [-25, -22],
    [-18, -28],
    // Halo side
    [-12, -34],
    [-8, -40],
    // Airbox
    [-5, -46],
    [0, -48],
    [5, -46],
    // Halo other side
    [8, -40],
    [12, -34],
    // Sidepod
    [18, -28],
    [25, -22],
    [30, -16],
    [35, -8],
    [38, 0],
    // Front wing endplate right
    [50, 4],
    [55, 8],
    // Floor
    [50, 12],
    [-50, 12],
    [-55, 8],
  ];

  function drawCarShape(ctx, angle, primary, secondary, accentCol, number) {
    const norm = ((angle % 360) + 360) % 360;
    const rad = (norm * Math.PI) / 180;
    const cosA = Math.cos(rad);
    const sinA = Math.sin(rad);
    const absS = Math.abs(sinA);

    // Interpolate between side and front profiles based on angle
    // 0°/180° = full side, 90°/270° = full front
    const sideFactor = Math.abs(cosA);
    const frontFactor = absS;

    // Car apparent width (foreshortening)
    const scaleX = sideFactor * 1.0 + frontFactor * 0.35;
    const flipX = cosA >= 0 ? 1 : -1;

    // Choose which profile to interpolate toward
    const pts = [];
    if (frontFactor < 0.5) {
      // Mostly side view — use side profile with X compression
      for (const [x, y] of SIDE_PTS) {
        pts.push([x * scaleX * flipX, y]);
      }
    } else {
      // Mostly front view — use front profile
      const blend = (frontFactor - 0.5) * 2; // 0 to 1
      for (let i = 0; i < FRONT_PTS.length; i++) {
        const [fx, fy] = FRONT_PTS[i];
        // If we also have a side point to blend from
        const si = Math.min(i, SIDE_PTS.length - 1);
        const [sx, sy] = SIDE_PTS[si];
        const x = sx * scaleX * flipX * (1 - blend) + fx * blend;
        const y = sy * (1 - blend) + fy * blend;
        pts.push([x, y]);
      }
    }

    // Draw the car body
    ctx.beginPath();
    ctx.moveTo(pts[0][0], pts[0][1]);
    for (let i = 1; i < pts.length; i++) {
      ctx.lineTo(pts[i][0], pts[i][1]);
    }
    ctx.closePath();
    ctx.fillStyle = primary;
    ctx.fill();
    ctx.strokeStyle = accentCol;
    ctx.lineWidth = 1.5;
    ctx.stroke();

    // Livery stripe
    ctx.save();
    ctx.globalAlpha = 0.5;
    ctx.strokeStyle = secondary || "#333";
    ctx.lineWidth = 4;
    ctx.beginPath();
    ctx.moveTo(pts[0][0] * 0.7, -2);
    ctx.lineTo(-pts[0][0] * 0.7, -2);
    ctx.stroke();
    ctx.globalAlpha = 0.3;
    ctx.strokeStyle = accentCol;
    ctx.lineWidth = 1.5;
    ctx.beginPath();
    ctx.moveTo(pts[0][0] * 0.7, 2);
    ctx.lineTo(-pts[0][0] * 0.7, 2);
    ctx.stroke();
    ctx.restore();

    // Cockpit
    if (sideFactor > 0.3) {
      ctx.fillStyle = "rgba(0,0,0,0.8)";
      ctx.beginPath();
      ctx.ellipse(-10 * flipX, -20, 15 * scaleX, 10, 0, 0, Math.PI * 2);
      ctx.fill();
      ctx.strokeStyle = "rgba(255,255,255,0.1)";
      ctx.lineWidth = 0.5;
      ctx.stroke();
    }

    // Wheels — F1 has exposed wheels
    const wheelY = 10;
    if (sideFactor > 0.4) {
      // Side view — big exposed tyres
      const fwX = 75 * scaleX * flipX;
      const rwX = -70 * scaleX * flipX;
      // Front tyre
      ctx.fillStyle = "#1a1a1a";
      ctx.beginPath(); ctx.ellipse(fwX, wheelY, 12 * scaleX, 18, 0, 0, Math.PI * 2); ctx.fill();
      ctx.strokeStyle = "#333"; ctx.lineWidth = 1.5; ctx.stroke();
      ctx.fillStyle = "#0a0a0a";
      ctx.beginPath(); ctx.ellipse(fwX, wheelY, 6 * scaleX, 10, 0, 0, Math.PI * 2); ctx.fill();
      // Rear tyre — bigger
      ctx.fillStyle = "#1a1a1a";
      ctx.beginPath(); ctx.ellipse(rwX, wheelY, 14 * scaleX, 22, 0, 0, Math.PI * 2); ctx.fill();
      ctx.strokeStyle = "#333"; ctx.lineWidth = 1.5; ctx.stroke();
      ctx.fillStyle = "#0a0a0a";
      ctx.beginPath(); ctx.ellipse(rwX, wheelY, 7 * scaleX, 12, 0, 0, Math.PI * 2); ctx.fill();
      // Wheel nut
      ctx.fillStyle = accentCol;
      ctx.beginPath(); ctx.arc(fwX, wheelY, 2.5, 0, Math.PI * 2); ctx.fill();
      ctx.beginPath(); ctx.arc(rwX, wheelY, 2.5, 0, Math.PI * 2); ctx.fill();
    } else {
      // Front/rear view — all 4 wheels visible
      ctx.fillStyle = "#1a1a1a";
      [-42, -18, 18, 42].forEach(xOff => {
        ctx.beginPath(); ctx.ellipse(xOff, wheelY + 2, 10, 10, 0, 0, Math.PI * 2); ctx.fill();
        ctx.strokeStyle = "#333"; ctx.lineWidth = 1; ctx.stroke();
      });
    }

    // Rear wing — tall, prominent (F1 signature element)
    if (sideFactor > 0.25) {
      const rwingX = -90 * scaleX * flipX;
      // Wing pylons
      ctx.fillStyle = "#222";
      ctx.fillRect(rwingX - 2 * Math.abs(flipX), -24, 3, 20);
      // Main plane
      ctx.fillStyle = secondary || accentCol;
      ctx.fillRect(rwingX - 16 * scaleX, -50, 30 * scaleX, 5);
      // DRS flap
      ctx.fillStyle = accentCol;
      ctx.globalAlpha = 0.7;
      ctx.fillRect(rwingX - 14 * scaleX, -44, 26 * scaleX, 3);
      ctx.globalAlpha = 1;
      // Endplates
      ctx.fillStyle = primary;
      ctx.fillRect(rwingX - 16 * scaleX, -52, 3 * scaleX, 30);
      ctx.fillRect(rwingX + 12 * scaleX, -52, 3 * scaleX, 30);
    }

    // Front wing
    if (sideFactor > 0.4) {
      const fwingX = 115 * scaleX * flipX;
      ctx.strokeStyle = accentCol;
      ctx.lineWidth = 2;
      // Main plane
      ctx.beginPath();
      ctx.moveTo(fwingX - 5 * flipX, 8);
      ctx.lineTo(fwingX + 15 * flipX, 6);
      ctx.stroke();
      // Endplate
      ctx.beginPath();
      ctx.moveTo(fwingX + 14 * flipX, 2);
      ctx.lineTo(fwingX + 14 * flipX, 12);
      ctx.stroke();
      // Flap elements
      ctx.lineWidth = 1;
      ctx.globalAlpha = 0.5;
      ctx.beginPath();
      ctx.moveTo(fwingX - 5 * flipX, 5);
      ctx.lineTo(fwingX + 12 * flipX, 3);
      ctx.stroke();
      ctx.globalAlpha = 1;
    }

    // Halo — the distinctive F1 safety device
    if (sideFactor > 0.3) {
      ctx.strokeStyle = "#444";
      ctx.lineWidth = 4;
      ctx.beginPath();
      ctx.moveTo(20 * scaleX * flipX, -14);
      ctx.quadraticCurveTo(0, -32, -15 * scaleX * flipX, -14);
      ctx.stroke();
      ctx.strokeStyle = accentCol;
      ctx.lineWidth = 1;
      ctx.stroke();
    }

    // Sidepod undercut detail
    if (sideFactor > 0.5) {
      ctx.strokeStyle = "rgba(255,255,255,0.08)";
      ctx.lineWidth = 1;
      ctx.beginPath();
      ctx.moveTo(30 * scaleX * flipX, -10);
      ctx.quadraticCurveTo(10 * scaleX * flipX, -6, -20 * scaleX * flipX, -8);
      ctx.stroke();
    }

    // Number
    ctx.fillStyle = accentCol;
    ctx.globalAlpha = 0.6;
    ctx.font = "bold 24px Geist, sans-serif";
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillText(String(number), 0, -8);
    ctx.globalAlpha = 1;
  }

  function AeroSimulator({ car, carClass, speed }) {
    const cls = (carClass && carClass.id) || "open_wheel";
    const aero = AERO[cls] || AERO.open_wheel;
    const accent = car.livery.accent === "#FFFFFF" ? "#E8E4DC" : car.livery.accent;
    const speedFrac = Math.min(1, (speed || 200) / aero.topSpeed);

    const [yaw, setYaw] = useS(0);
    const [dragging, setDragging] = useS(false);
    const canvasRef = useR(null);
    const dragRef = useR({ x: 0, a: 0 });
    const timeRef = useR(0);
    const rafRef = useR(null);

    const onPD = useCb((e) => {
      setDragging(true);
      dragRef.current = { x: e.clientX, a: yaw };
      e.target.setPointerCapture(e.pointerId);
    }, [yaw]);
    const onPM = useCb((e) => {
      if (!dragging) return;
      const dx = e.clientX - dragRef.current.x;
      setYaw(dragRef.current.a + dx * 0.5);
    }, [dragging]);
    const onPU = useCb(() => setDragging(false), []);

    const norm = ((yaw % 360) + 360) % 360;
    const yawRad = (norm * Math.PI) / 180;
    const cosY = Math.cos(yawRad);
    const sinY = Math.abs(Math.sin(yawRad));
    const carHalfW = Math.abs(cosY) * 110 + sinY * 40;
    const carHalfH = 40 + sinY * 10;
    const yawDragMult = 1 + sinY * 2.5;
    const df = Math.round(aero.dfTotal * speedFrac * speedFrac * Math.max(0.2, Math.abs(cosY)));
    const drag = Math.round(aero.dragN * speedFrac * speedFrac * yawDragMult);

    useE(() => {
      const canvas = canvasRef.current;
      if (!canvas) return;
      const ctx = canvas.getContext("2d");
      let cW = 0, cH = 0;
      let running = true;
      let lastTime = performance.now();

      const draw = (now) => {
        if (!running) return;
        const dt = (now - lastTime) / 1000;
        lastTime = now;
        timeRef.current += dt;
        const t = timeRef.current;
        const flow = t * (40 + speedFrac * 100);

        const clientW = canvas.clientWidth;
        const clientH = canvas.clientHeight || 400;
        if (clientW > 0 && clientH > 0 && (clientW !== cW || clientH !== cH)) {
          cW = clientW; cH = clientH;
          const dpr = window.devicePixelRatio || 1;
          canvas.width = cW * dpr;
          canvas.height = cH * dpr;
          ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
        }
        if (cW === 0) { rafRef.current = requestAnimationFrame(draw); return; }

        // Uniform scaling
        const scale = Math.min(cW / W, cH / H);
        const offX = (cW - W * scale) / 2;
        const offY = (cH - H * scale) / 2;
        ctx.save();
        ctx.translate(offX, offY);
        ctx.scale(scale, scale);

        // Background
        ctx.fillStyle = "#040608";
        ctx.fillRect(-10, -10, W + 20, H + 20);

        // Subtle grid
        ctx.strokeStyle = "rgba(91,183,226,0.025)";
        ctx.lineWidth = 0.5;
        for (let i = 0; i <= W; i += 40) {
          ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, H); ctx.stroke();
        }
        for (let i = 0; i <= H; i += 40) {
          ctx.beginPath(); ctx.moveTo(0, i); ctx.lineTo(W, i); ctx.stroke();
        }

        // Ground
        ctx.strokeStyle = "rgba(232,228,220,0.1)";
        ctx.lineWidth = 0.5;
        ctx.beginPath(); ctx.moveTo(0, GROUND_Y); ctx.lineTo(W, GROUND_Y); ctx.stroke();

        // Ground reflection
        const gGrad = ctx.createRadialGradient(CX, GROUND_Y + 10, 5, CX, GROUND_Y + 10, 150);
        gGrad.addColorStop(0, "rgba(91,183,226,0.04)");
        gGrad.addColorStop(1, "rgba(0,0,0,0)");
        ctx.fillStyle = gGrad;
        ctx.fillRect(0, GROUND_Y, W, H - GROUND_Y);

        // =========== WIND LINES ===========
        const LINE_COUNT = 40;
        for (let i = 0; i < LINE_COUNT; i++) {
          const baseY = CY - 130 + (i / (LINE_COUNT - 1)) * 260;
          if (baseY > GROUND_Y - 5) continue;

          const dy = baseY - CY;
          const relY = dy / carHalfH;
          const dist = Math.abs(relY);

          let r, g, b, alpha;
          if (dist < 0.8) {
            r = 240; g = 100 + dist * 120; b = 60 + dist * 160; alpha = 0.5 - dist * 0.1;
          } else if (dist < 1.5) {
            const f = (dist - 0.8) / 0.7;
            r = 50; g = 170 + f * 30; b = 210 + f * 30; alpha = 0.35 - f * 0.1;
          } else {
            r = 60; g = 130; b = 190; alpha = 0.12;
          }

          ctx.strokeStyle = `rgba(${r},${g},${b},${alpha})`;
          ctx.lineWidth = dist < 0.6 ? 2.2 : dist < 1.2 ? 1.4 : 0.7;
          ctx.beginPath();

          let started = false;
          for (let x = 0; x <= W; x += 4) {
            const dx = x - CX;
            const relX = dx / carHalfW;
            const ellipseDist = Math.sqrt(relX * relX + relY * relY);

            let deflY = 0;
            if (ellipseDist < 2.2) {
              const influence = Math.max(0, 1 - ellipseDist / 2.2);
              const pushDir = relY < 0 ? -1 : 1;
              if (ellipseDist < 1.0) {
                deflY = pushDir * (carHalfH * 1.2 - Math.abs(dy)) * 0.9;
              } else {
                deflY = pushDir * influence * influence * carHalfH * 1.1;
              }
              // Wake turbulence
              if (relX < -0.5 && ellipseDist < 1.8) {
                const wakeX = Math.max(0, (-relX - 0.5) / 1.3);
                deflY += wakeX * (6 + sinY * 12) * Math.sin(baseY * 0.25 + t * 2.5 + i * 0.6);
              }
            }

            const py = baseY + deflY;
            if (!started) { ctx.moveTo(x, py); started = true; }
            else ctx.lineTo(x, py);
          }
          ctx.stroke();

          // Flowing particles
          if (dist < 1.3) {
            const pCount = 3;
            for (let p = 0; p < pCount; p++) {
              const px = ((flow * (0.8 + dist * 0.3) + p * (W / pCount) + i * 19) % (W + 20)) - 10;
              const relXp = (px - CX) / carHalfW;
              const edp = Math.sqrt(relXp * relXp + relY * relY);
              let pdY = 0;
              if (edp < 2.2) {
                const inf = Math.max(0, 1 - edp / 2.2);
                const dir = relY < 0 ? -1 : 1;
                pdY = edp < 1.0 ? dir * (carHalfH * 1.2 - Math.abs(dy)) * 0.9 : dir * inf * inf * carHalfH * 1.1;
                if (relXp < -0.5 && edp < 1.8) {
                  pdY += Math.max(0, (-relXp - 0.5) / 1.3) * (6 + sinY * 12) * Math.sin(baseY * 0.25 + t * 2.5 + i * 0.6);
                }
              }
              ctx.fillStyle = `rgba(${r+40},${g+40},${b+40},${alpha + 0.15})`;
              ctx.beginPath();
              ctx.arc(px, baseY + pdY, dist < 0.7 ? 2.5 : 1.5, 0, Math.PI * 2);
              ctx.fill();
            }
          }
        }

        // =========== CAR BODY ===========
        ctx.save();
        ctx.translate(CX, CY);

        // Shadow
        ctx.fillStyle = "rgba(0,0,0,0.3)";
        ctx.beginPath();
        ctx.ellipse(0, GROUND_Y - CY + 4, carHalfW * 0.8, 6, 0, 0, Math.PI * 2);
        ctx.fill();

        // Draw the actual car shape
        drawCarShape(ctx, yaw, car.livery.primary, car.livery.secondary, accent, car.no);

        ctx.restore();

        // =========== CAR REFLECTION ===========
        ctx.save();
        ctx.translate(CX, GROUND_Y + 6);
        ctx.scale(1, -0.2);
        ctx.globalAlpha = 0.06;
        drawCarShape(ctx, yaw, car.livery.primary, car.livery.secondary, accent, car.no);
        ctx.restore();

        // =========== HUD ===========
        ctx.fillStyle = "rgba(239,68,68,0.5)";
        ctx.font = "bold 9px JetBrains Mono, monospace";
        ctx.textAlign = "left";
        ctx.fillText("DRAG", 30, CY - 25);
        ctx.fillStyle = "rgba(239,68,68,0.4)";
        ctx.fillText(drag + "N", 30, CY - 12);
        ctx.strokeStyle = "rgba(239,68,68,0.35)";
        ctx.lineWidth = 1.5;
        for (let a = 0; a < 3; a++) {
          const ay = CY - 5 + a * 12;
          ctx.beginPath(); ctx.moveTo(30, ay); ctx.lineTo(75, ay); ctx.stroke();
        }

        ctx.fillStyle = "rgba(59,130,246,0.5)";
        ctx.textAlign = "center";
        ctx.fillText("DOWNFORCE", CX, CY - carHalfH - 50);
        ctx.fillStyle = "rgba(59,130,246,0.4)";
        ctx.fillText(df + "N", CX, CY - carHalfH - 38);

        // Speed
        ctx.fillStyle = "rgba(232,228,220,0.25)";
        ctx.font = "700 9px JetBrains Mono, monospace";
        ctx.textAlign = "left";
        ctx.fillText("AIRSPEED", 30, H - 50);
        ctx.fillStyle = "#E8E4DC";
        ctx.font = "900 24px Geist, sans-serif";
        ctx.fillText(speed + "", 30, H - 28);
        ctx.fillStyle = "rgba(232,228,220,0.35)";
        ctx.font = "700 10px JetBrains Mono, monospace";
        ctx.fillText("KPH", 30 + ctx.measureText(speed + "").width + 5, H - 28);

        // Compass
        const compX = W - 50, compY = H - 50, compR = 22;
        ctx.strokeStyle = "rgba(232,228,220,0.08)";
        ctx.lineWidth = 0.5;
        ctx.beginPath(); ctx.arc(compX, compY, compR, 0, Math.PI * 2); ctx.stroke();
        const needleAngle = (norm - 90) * Math.PI / 180;
        ctx.strokeStyle = accent;
        ctx.lineWidth = 2;
        ctx.lineCap = "round";
        ctx.beginPath();
        ctx.moveTo(compX, compY);
        ctx.lineTo(compX + Math.cos(needleAngle) * 16, compY + Math.sin(needleAngle) * 16);
        ctx.stroke();
        ctx.fillStyle = accent;
        ctx.beginPath(); ctx.arc(compX, compY, 3, 0, Math.PI * 2); ctx.fill();
        ctx.fillStyle = "rgba(232,228,220,0.3)";
        ctx.font = "700 9px JetBrains Mono, monospace";
        ctx.textAlign = "center";
        ctx.fillText(Math.round(norm) + "°", compX, compY + compR + 16);

        // Hint
        ctx.fillStyle = "rgba(232,228,220,0.1)";
        ctx.font = "700 9px JetBrains Mono, monospace";
        ctx.textAlign = "center";
        ctx.fillText("DRAG LEFT / RIGHT TO ROTATE", W / 2, H - 12);

        // Crosswind warning
        if (sinY > 0.15) {
          ctx.fillStyle = "rgba(239,68,68,0.4)";
          ctx.fillText("CROSSWIND · YAW " + Math.round(norm > 180 ? 360 - norm : norm) + "°", W / 2, 20);
        }

        ctx.restore();
        rafRef.current = requestAnimationFrame(draw);
      };

      rafRef.current = requestAnimationFrame(draw);
      return () => { running = false; cancelAnimationFrame(rafRef.current); };
    }, [yaw, speedFrac, car.no, cls, car.livery.primary, car.livery.secondary, accent, sinY, cosY, carHalfW, carHalfH, yawDragMult, df, drag, speed, norm]);

    return (
      <div className="aero-wrap aero-wrap-full">
        <div className="aero-header">
          <span className="aero-label">WIND TUNNEL · DRAG TO ROTATE</span>
          <span className="aero-class" style={{color: accent}}>{aero.label} · #{car.no}</span>
        </div>

        <canvas ref={canvasRef}
          style={{ width: "100%", height: "400px", cursor: dragging ? "grabbing" : "grab", touchAction: "none", display: "block", background: "#040608" }}
          onPointerDown={onPD} onPointerMove={onPM} onPointerUp={onPU}/>

        <div className="aero-stats">
          <div className="aero-stat">
            <span className="aero-stat-label">Cd</span>
            <span className="aero-stat-val">{(aero.cd * yawDragMult).toFixed(2)}</span>
          </div>
          <div className="aero-stat">
            <span className="aero-stat-label">Cl</span>
            <span className="aero-stat-val">{(aero.cl * Math.max(0.2, Math.abs(cosY))).toFixed(2)}</span>
          </div>
          <div className="aero-stat">
            <span className="aero-stat-label">DOWNFORCE</span>
            <span className="aero-stat-val aero-val-blue">{df}<small>N</small></span>
          </div>
          <div className="aero-stat">
            <span className="aero-stat-label">DRAG</span>
            <span className="aero-stat-val aero-val-red">{drag}<small>N</small></span>
          </div>
          <div className="aero-stat">
            <span className="aero-stat-label">L/D</span>
            <span className="aero-stat-val">{(df / Math.max(1, drag)).toFixed(2)}</span>
          </div>
          <div className="aero-stat">
            <span className="aero-stat-label">YAW</span>
            <span className="aero-stat-val">{Math.round(norm > 180 ? 360 - norm : norm)}°</span>
          </div>
        </div>
      </div>
    );
  }

  window.AeroSimulator = AeroSimulator;
})();
