(() => {
  'use strict';
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;

  const canvas = document.createElement('canvas');
  canvas.className = 'seasonal-petals';
  canvas.setAttribute('aria-hidden', 'true');
  document.body.append(canvas);
  const context = canvas.getContext('2d', {alpha: true});
  if (!context) return;

  let width = 0;
  let height = 0;
  let ratio = 1;
  let petals = [];
  let frame = 0;
  let createdCount = 0;
  let previous = performance.now();
  const palette = ['#ffd5dc', '#f9bec9', '#f3a8b7', '#ffe2dc', '#efb0bd'];

  const createPetal = (initial = false) => {
    const progress = initial ? Math.random() : 0;
    const isLeaf = createdCount++ % 30 === 29;
    const fromTop = Math.random() < .5;
    const startX = fromTop ? width * (.5 + Math.random() * .5) : width + 18 + Math.random() * 28;
    const startY = fromTop ? -18 - Math.random() * 28 : height * Math.random() * .5;
    const destinationX = width * (-.08 + Math.random() * .38);
    const destinationY = height * (.78 + Math.random() * .3);
    const journey = 18 + Math.random() * 10;
    return {
      x: initial
        ? startX + (destinationX - startX) * progress + (Math.random() - .5) * width * .08
        : startX,
      y: initial
        ? startY + (destinationY - startY) * progress + (Math.random() - .5) * height * .06
        : startY,
      size: (isLeaf ? 6 : 5) + Math.random() * (isLeaf ? 5 : 6),
      fall: (destinationY - startY) / journey,
      left: (startX - destinationX) / journey,
      sway: 11 + Math.random() * 24,
      velocityX: (Math.random() - .5) * 24,
      velocityY: (Math.random() - .5) * 10,
      phase: Math.random() * Math.PI * 2,
      spin: (Math.random() - .5) * 2.4,
      angle: Math.random() * Math.PI * 2,
      opacity: (isLeaf ? .13 : .2) + Math.random() * .19,
      color: isLeaf ? '#b8d79a' : palette[Math.floor(Math.random() * palette.length)],
      isLeaf,
      age: initial ? progress * journey : 0,
      lifetime: Math.random() < .22 ? journey * (.38 + Math.random() * .42) : journey + 5 + Math.random() * 8,
      squash: .48 + Math.random() * .34
    };
  };

  const resize = () => {
    ratio = Math.min(window.devicePixelRatio || 1, 2);
    width = window.innerWidth;
    height = window.innerHeight;
    canvas.width = Math.round(width * ratio);
    canvas.height = Math.round(height * ratio);
    canvas.style.width = `${width}px`;
    canvas.style.height = `${height}px`;
    context.setTransform(ratio, 0, 0, ratio, 0, 0);
    const count = Math.min(52, Math.max(20, Math.round(width / 30)));
    petals = Array.from({length: count}, (_, index) => petals[index] || createPetal(true));
  };

  const drawPetal = petal => {
    context.save();
    context.translate(petal.x, petal.y);
    context.rotate(petal.angle);
    context.scale(1, petal.squash);
    context.beginPath();
    if (petal.isLeaf) {
      context.moveTo(0, -petal.size * 1.15);
      context.bezierCurveTo(petal.size * .92, -petal.size * .55, petal.size * .78, petal.size * .62, 0, petal.size * 1.2);
      context.bezierCurveTo(-petal.size * .78, petal.size * .62, -petal.size * .92, -petal.size * .55, 0, -petal.size * 1.15);
    } else {
      // 共通サイトと同じ、上下非対称の細長い「一枚花弁」。ハート形の切れ込みは作らない。
      context.moveTo(0, -petal.size);
      context.bezierCurveTo(petal.size * .85, -petal.size * .45, petal.size * .7, petal.size * .55, 0, petal.size);
      context.bezierCurveTo(-petal.size * .7, petal.size * .55, -petal.size * .85, -petal.size * .45, 0, -petal.size);
    }
    context.closePath();
    context.fillStyle = petal.color;
    context.globalAlpha = petal.opacity;
    context.shadowColor = petal.isLeaf ? 'rgba(169, 207, 137, .24)' : 'rgba(255, 176, 191, .32)';
    context.shadowBlur = 4;
    context.fill();
    if (petal.isLeaf) {
      context.beginPath();
      context.moveTo(0, -petal.size * .82);
      context.lineTo(0, petal.size * .88);
      context.strokeStyle = 'rgba(92, 132, 72, .48)';
      context.lineWidth = .7;
      context.stroke();
    }
    context.restore();
  };

  const animate = now => {
    const elapsed = Math.min((now - previous) / 1000, .05);
    previous = now;
    context.clearRect(0, 0, width, height);
    for (let index = 0; index < petals.length; index += 1) {
      const petal = petals[index];
      petal.phase += elapsed * (.65 + petal.sway / 45);
      petal.age += elapsed;
      // ゆらぎを速度へ積み重ね、局所的には向きが定まらなくても全体として左下へ流す。
      petal.velocityX += Math.sin(petal.phase) * petal.sway * elapsed * .72;
      petal.velocityY += Math.cos(petal.phase * .83) * petal.sway * elapsed * .3;
      petal.velocityX *= Math.pow(.9, elapsed);
      petal.velocityY *= Math.pow(.88, elapsed);
      petal.x += (-petal.left + petal.velocityX) * elapsed;
      petal.y += (petal.fall + petal.velocityY) * elapsed;
      petal.angle += petal.spin * elapsed;
      if (petal.age > petal.lifetime || petal.y > height + 28 || petal.x < -45) petals[index] = createPetal();
      else drawPetal(petal);
    }
    frame = requestAnimationFrame(animate);
  };

  resize();
  addEventListener('resize', resize, {passive: true});
  document.addEventListener('visibilitychange', () => {
    if (document.hidden) cancelAnimationFrame(frame);
    else { previous = performance.now(); frame = requestAnimationFrame(animate); }
  });
  frame = requestAnimationFrame(animate);
})();
