// ── Job title slot machine: click the role pill ───────────────
(function () {
  const pill = document.getElementById('heroRole');
  if (!pill) return;

  const WORDS = [
    ['Software', 'Backend', 'Data', 'Computer', 'Frontend', 'Full-Stack', 'Tech', 'Server', 'It Project', 'Cloud'],
    ['Developer', 'Scientist', 'Engineer', 'Enthusiast', 'Wizard', 'Programmer', 'Manager'],
  ];
  const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
  const slots = [...pill.querySelectorAll('.slot')];

  // Width of a word in this mono font: 1ch + letter-spacing per character.
  // Slots hug their current word at rest and expand to their widest word
  // while spinning (the CSS width transition animates both moves).
  const widthFor = (word) => `calc(${word.length}ch + ${word.length * 0.08}em)`;
  slots.forEach((slot) => {
    slot.style.width = widthFor(slot.textContent.trim());
  });

  let busy = false;
  pill.addEventListener('click', () => {
    if (window.achv) window.achv.mark('slot');
    if (busy) return;
    busy = true;

    const spins = slots.map((slot, i) => {
      const list = WORDS[i];
      const reel = slot.querySelector('.reel');
      const from = Math.max(list.indexOf(reel.textContent.trim()), 0);
      // Random pick that's never the word already showing
      let target = Math.floor(Math.random() * (list.length - 1));
      if (target >= from) target++;

      if (reduceMotion.matches) {
        reel.innerHTML = `<span>${list[target]}</span>`;
        slot.style.width = widthFor(list[target]);
        return Promise.resolve();
      }

      // Expand to fit the reel's widest word for the duration of the spin
      const longest = list.reduce((a, b) => (b.length > a.length ? b : a));
      slot.style.width = widthFor(longest);

      // Walk the reel in list order: a couple of full revolutions, then
      // land on the target (the second reel spins one revolution longer)
      const steps = ((target - from + list.length) % list.length) + list.length * (2 + i);

      // Build the strip top-down ending at the current word, so the column
      // slides downward and words enter from above. One extra word sits
      // above the target to back the overshoot.
      reel.innerHTML = '';
      for (let k = 0; k <= steps + 1; k++) {
        const w = document.createElement('span');
        w.textContent = list[(from + steps + 1 - k) % list.length];
        reel.appendChild(w);
      }

      const h = reel.firstChild.getBoundingClientRect().height;
      const land = -h;              // row where the target word sits
      const over = land + h * 0.35; // spin runs slightly past the stop
      const anim = reel.animate(
        [
          { transform: `translateY(${-(steps + 1) * h}px)` },
          { transform: `translateY(${over}px)` },
        ],
        { duration: 900 + i * 500, easing: 'cubic-bezier(0.15, 0.85, 0.25, 1)', fill: 'forwards' }
      );
      return anim.finished.then(() => {
        const settle = reel.animate(
          [{ transform: `translateY(${over}px)` }, { transform: `translateY(${land}px)` }],
          { duration: 200, easing: 'ease', fill: 'forwards' }
        );
        return settle.finished.then(() => {
          reel.innerHTML = `<span>${list[target]}</span>`;
          settle.cancel();
          anim.cancel();   // drop the forward-filled transforms after the swap
          slot.style.width = widthFor(list[target]);   // shrink back to fit
        });
      });
    });

    Promise.all(spins).finally(() => { busy = false; });
  });
})();
