{
  "version": 3,
  "sources": ["/cdn/shop/t/7/assets/je-mike-player-cbaea23b0082.js?mike_rollout=20260811hqa"],
  "sourcesContent": ["/* je-john-pdp-20260808 \u2014 Mike, the product-page avatar.\n\n   Provenance: derived from the Codex \"johns-john-web\" bundle (john-pet.js, a\n   generic 9-state / 16-look-direction player against an 8x11 atlas). The PDP\n   needs three states and no look directions, so this is the reduced player and\n   it reads assets/je-john.webp \u2014 a 7x3 crop of the approved 3x HQ web master.\n   The resulting ~438 KB WebP stays lazy-loaded and gives every 192x208 logical\n   frame 576x624 source pixels for crisp high-DPI rendering. If you ever need running / jumping /\n   look-directions, re-cut the atlas AND update GEOMETRY below; do not point\n   this player at the full 8x11 sheet, the row indices differ.\n\n   Atlas geometry (assets/je-john.webp, 7 columns x 3 rows):\n     row 0 : idle  6 frames (cols 0-5), col 6 = neutral standing frame\n     row 1 : wave  4 frames\n     row 2 : talk  6 frames\n\n   Cell pixels are derived from the loaded atlas. That keeps the player compatible\n   with both the original 192x208 cells and the HQ replacement, and makes a staged\n   asset/player rollout fail-safe instead of briefly reading across sprite cells.\n\n   Performance contract \u2014 every one of these is load-bearing, not polish:\n     - The HQ atlas is fetched at LOW priority and only once Mike is within\n       300px of the viewport. Before then he costs one empty canvas.\n     - His box is sized by CSS aspect-ratio in the section, so the late image\n       causes zero layout shift.\n     - Ticking is setTimeout(1000/fps) -> rAF, NOT rAF-every-frame. At the idle\n       rate that is 2 wake-ups a second, not 60. The rAF leg still means a\n       hidden tab paints nothing.\n     - Ticking stops entirely when Mike scrolls out of view or the tab is\n       hidden, and never starts under prefers-reduced-motion (static frame).\n*/\n(function () {\n  'use strict';\n  if (window.customElements && customElements.get('je-john')) return;\n\n  var ATLAS_COLS = 7;\n  var ATLAS_ROWS = 3;\n  var FALLBACK_CELL_W = 192;\n  var FALLBACK_CELL_H = 208;\n  var NEUTRAL = { row: 0, col: 6 };\n\n  /* Frame rates are TUNED, not guessed (Will: \"slower, less erratic, smoother\",\n     2026-08-08). Measured mean per-pixel delta between consecutive frames:\n\n       idle  1.6-2.7   loop wrap 1.9 \u2014 SMALLER than the average in-sequence step\n       wave  4.8-15.7  frame 3 is already back to arms-at-rest\n       talk  9.4-18.5  loop wrap 9.4, also the smallest step\n\n     Two things follow, and both are the opposite of the instinctive fix:\n       - Every sequence is already cyclic, and its wrap is its SMOOTHEST step. So\n         ping-ponging a loop would make it worse \u2014 it doubles the run length and\n         re-traverses the big steps backwards to avoid a seam that isn't there.\n       - Cross-fading adjacent frames GHOSTS badly. These are drawn poses, not\n         offsets of one pose: at 50% blend the wave and talk frames show two heads\n         and two arms. Rendered the blend to check before writing any of it.\n\n     What was actually wrong was speed. talk carries the largest deltas and ran at\n     the same rate as idle, which is why it read as the erratic one. Rates below are\n     multiplied by the `speed` attribute so this is tunable from the theme editor\n     without a code push.\n\n     2026-08-10 (Will: \"slow Mike's animations down further... he should just move\n     between his sets slowly\"): every rate halved again -- idle 2.0->1.0, wave\n     3.5->2.0, talk 2.5->1.25 -- and the rest before handing back to idle lengthened\n     420->700ms so the change of state is unhurried too. One pose per second at idle\n     is the point, not a stall: idle carries the smallest deltas on the sheet\n     (1.6-2.7), so slow reads there as breathing. Full loop lengths are now idle 6.0s,\n     wave 2.0s, talk 4.8s. */\n  var STATES = {\n    idle: { row: 0, frames: 6, fps: 1.0, loop: true },\n    wave: { row: 1, frames: 4, fps: 2.0, loop: false },\n    talk: { row: 2, frames: 6, fps: 1.25, loop: true }\n  };\n  /* Beat of stillness on the last frame of a one-shot before handing back to idle.\n     Without it the wave's final arms-down frame is replaced the instant it lands and\n     the greeting reads as a twitch rather than a gesture. */\n  var HANDOVER_MS = 700;\n\n  /* One Image per src for the whole document. There is only one Mike per page\n     today, but a shared cache means adding a second costs no extra bytes and\n     no second decode. */\n  var sheets = {};\n  function loadSheet(src) {\n    if (sheets[src]) return sheets[src];\n    var entry = {\n      img: new Image(),\n      ready: false,\n      waiting: [],\n      cellW: FALLBACK_CELL_W,\n      cellH: FALLBACK_CELL_H\n    };\n    entry.img.decoding = 'async';\n    if ('fetchPriority' in entry.img) entry.img.fetchPriority = 'low';\n    entry.img.onload = function () {\n      var cellW = entry.img.naturalWidth / ATLAS_COLS;\n      var cellH = entry.img.naturalHeight / ATLAS_ROWS;\n      if (cellW > 0 && cellH > 0 && cellW === Math.floor(cellW) && cellH === Math.floor(cellH)) {\n        entry.cellW = cellW;\n        entry.cellH = cellH;\n      }\n      entry.ready = true;\n      var q = entry.waiting;\n      entry.waiting = [];\n      for (var i = 0; i < q.length; i++) q[i]();\n    };\n    entry.img.onerror = function () { entry.waiting = []; };\n    entry.img.src = src;\n    sheets[src] = entry;\n    return entry;\n  }\n\n  var reduceQuery = window.matchMedia('(prefers-reduced-motion: reduce)');\n\n  function JeJohn() { return Reflect.construct(HTMLElement, [], JeJohn); }\n  JeJohn.prototype = Object.create(HTMLElement.prototype);\n  JeJohn.prototype.constructor = JeJohn;\n  Object.setPrototypeOf(JeJohn, HTMLElement);\n\n  JeJohn.prototype.connectedCallback = function () {\n    if (this._built) return;\n    this._built = true;\n\n    this._canvas = document.createElement('canvas');\n    this._canvas.width = FALLBACK_CELL_W;\n    this._canvas.height = FALLBACK_CELL_H;\n    this._canvas.setAttribute('role', 'img');\n    this._canvas.setAttribute('aria-label', this.getAttribute('label') || 'Mike from Johns Electrical');\n    this._canvas.style.cssText = 'display:block;width:100%;height:auto;';\n    this.appendChild(this._canvas);\n    this._ctx = this._canvas.getContext('2d', { alpha: true });\n\n    this._state = 'idle';\n    this._frame = 0;\n    this._then = null;\n    this._timer = 0;\n    this._raf = 0;\n    this._hold = 0;\n    this._inView = false;\n    this._sheet = null;\n    /* Global pace multiplier, set from the theme editor. Clamped so a bad value\n       can never stall Mike outright or spin him. */\n    var speed = parseFloat(this.getAttribute('speed'));\n    this._speed = (isFinite(speed) && speed > 0) ? Math.min(3, Math.max(0.3, speed)) : 1;\n\n    var self = this;\n    this._onVisibility = function () { self._sync(); };\n    document.addEventListener('visibilitychange', this._onVisibility);\n\n    this._onReduce = function () { self._frame = 0; self._sync(); self._draw(); };\n    if (reduceQuery.addEventListener) reduceQuery.addEventListener('change', this._onReduce);\n\n    /* Lazy fetch + viewport gating in one observer. */\n    if ('IntersectionObserver' in window) {\n      this._io = new IntersectionObserver(function (entries) {\n        self._inView = entries[entries.length - 1].isIntersecting;\n        if (self._inView && !self._sheet) self._attachSheet();\n        self._sync();\n      }, { rootMargin: '300px 0px' });\n      this._io.observe(this);\n    } else {\n      this._inView = true;\n      this._attachSheet();\n    }\n  };\n\n  JeJohn.prototype.disconnectedCallback = function () {\n    this._stop();\n    if (this._hold) { window.clearTimeout(this._hold); this._hold = 0; }\n    document.removeEventListener('visibilitychange', this._onVisibility);\n    if (reduceQuery.removeEventListener) reduceQuery.removeEventListener('change', this._onReduce);\n    if (this._io) { this._io.disconnect(); this._io = null; }\n  };\n\n  JeJohn.prototype._attachSheet = function () {\n    var src = this.getAttribute('src');\n    if (!src) return;\n    var self = this;\n    this._sheet = loadSheet(src);\n    if (this._sheet.ready) {\n      this._syncCanvasToSheet();\n      this._draw();\n      this._sync();\n    } else this._sheet.waiting.push(function () {\n      self._syncCanvasToSheet();\n      self._draw();\n      self._sync();\n    });\n  };\n\n  JeJohn.prototype._syncCanvasToSheet = function () {\n    if (!this._sheet || !this._canvas) return;\n    var width = this._sheet.cellW || FALLBACK_CELL_W;\n    var height = this._sheet.cellH || FALLBACK_CELL_H;\n    if (this._canvas.width !== width) this._canvas.width = width;\n    if (this._canvas.height !== height) this._canvas.height = height;\n  };\n\n  /* Read-only current state, so callers can avoid restarting an animation that is\n     already running (a re-triggered wave restarting from frame 0 is a visible jerk). */\n  Object.defineProperty(JeJohn.prototype, 'state', {\n    get: function () { return this._state; }\n  });\n\n  /* Public: play a state. `then` is the state to fall back to when a one-shot\n     finishes (wave -> idle). Looping states ignore it. */\n  JeJohn.prototype.play = function (name, then) {\n    if (!STATES[name]) return this;\n    if (this._hold) { window.clearTimeout(this._hold); this._hold = 0; }\n    this._state = name;\n    this._frame = 0;\n    this._then = STATES[name].loop ? null : (then || null);\n    this._draw();\n    this._sync();\n    return this;\n  };\n\n  JeJohn.prototype._shouldRun = function () {\n    return !!this._sheet && this._sheet.ready && this._inView &&\n      !document.hidden && !reduceQuery.matches && STATES[this._state].frames > 1;\n  };\n\n  JeJohn.prototype._sync = function () {\n    if (this._shouldRun()) this._schedule();\n    else this._stop();\n  };\n\n  JeJohn.prototype._schedule = function () {\n    if (this._timer || this._raf) return;\n    var self = this;\n    this._timer = window.setTimeout(function () {\n      self._timer = 0;\n      /* rAF leg: a hidden or fully-throttled tab simply never advances. */\n      self._raf = window.requestAnimationFrame(function () {\n        self._raf = 0;\n        self._advance();\n      });\n    }, 1000 / (STATES[this._state].fps * this._speed));\n  };\n\n  JeJohn.prototype._stop = function () {\n    if (this._timer) { window.clearTimeout(this._timer); this._timer = 0; }\n    if (this._raf) { window.cancelAnimationFrame(this._raf); this._raf = 0; }\n  };\n\n  JeJohn.prototype._advance = function () {\n    var cfg = STATES[this._state];\n    if (this._frame + 1 < cfg.frames) {\n      this._frame += 1;\n    } else if (cfg.loop) {\n      this._frame = 0;\n    } else {\n      /* One-shot finished: rest on the last frame, THEN hand over. */\n      this.dispatchEvent(new CustomEvent('je-john-done', { bubbles: true, detail: { state: this._state } }));\n      this._stop();\n      if (this._then) {\n        var next = this._then, self = this;\n        this._then = null;\n        this._hold = window.setTimeout(function () { self._hold = 0; self.play(next); }, HANDOVER_MS);\n      }\n      return;\n    }\n    this._draw();\n    this._sync();\n  };\n\n  JeJohn.prototype._draw = function () {\n    if (!this._sheet || !this._sheet.ready || !this._ctx) return;\n    var row, col;\n    var cellW = this._sheet.cellW || FALLBACK_CELL_W;\n    var cellH = this._sheet.cellH || FALLBACK_CELL_H;\n    this._syncCanvasToSheet();\n    if (reduceQuery.matches) { row = NEUTRAL.row; col = NEUTRAL.col; }\n    else { row = STATES[this._state].row; col = this._frame; }\n    this._ctx.clearRect(0, 0, cellW, cellH);\n    this._ctx.drawImage(this._sheet.img, col * cellW, row * cellH, cellW, cellH, 0, 0, cellW, cellH);\n  };\n\n  customElements.define('je-john', JeJohn);\n})();\n"],
  "mappings": "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",
  "names": []
}
