// WHO AM I tab — info on Karate Wiener, voiced welcome + testimonial gallery + a chat
// modal. Tutorial STEP 1: the rail tab pulses on first start until opened.
(function () {
var TKEY = 'kimodoTutorial';
function load() { try { return JSON.parse(localStorage.getItem(TKEY) || '{}') || {}; } catch (e) { return {}; } }
function save(o) { try { localStorage.setItem(TKEY, JSON.stringify(o)); } catch (e) {} }
function tab() { return document.getElementById('kimodo-whoami-toggle'); }
function setPulse(on) { var t = tab(); if (t) t.classList.toggle('kimodo-whoami-pulse', !!on); }
function seen() { return !!load().whoamiSeen; }
function applyState() { setPulse(!seen()); }
function markSeen() { var o = load(); if (!o.whoamiSeen) { o.whoamiSeen = true; save(o); } setPulse(false); }
function whoamiBase() {
var b = (typeof DATASET_BASE !== 'undefined' && DATASET_BASE) ? DATASET_BASE : '';
return b + '/viewer/whoami/';
}
var TESTIMONIALS = 4;
var built = false;
var galleryImages = []; // testimonial srcs (lightbox swipes through these)
var welcomeBtn = null; // the welcome speak/stop button (right of the hero image)
var welcomePlayedThisSession = false; // auto-play the welcome voice only once per page load
var topChatBtn = null; // the top-right "tap to chat" shortcut (beside the volume button)
// Toggle the loading shimmer on the top-right chat shortcut while a reply (text) or its
// voice (TTS) is being generated — mirrors the dojo "generating" overlay.
function refreshTopChat() {
if (topChatBtn) topChatBtn.classList.toggle('loading', chatBusy || speakActive);
}
// Top-right chat shortcut so you can talk to Karate Wiener from anywhere (no WHO AM I tab).
function installTopChat() {
if (document.getElementById('kw-topchat')) return;
// On *.hf.space the HF header (like / community / links) lives at the top-right, so push our
// floating buttons down below it (see .kw-on-space rules in whoami.tab.css).
if (/\.hf\.space$/i.test(location.hostname)) document.documentElement.classList.add('kw-on-space');
topChatBtn = document.createElement('button');
topChatBtn.id = 'kw-topchat'; topChatBtn.className = 'kw-topchat'; topChatBtn.type = 'button';
topChatBtn.title = 'Chat with Karate Wiener';
topChatBtn.innerHTML = '💬';
topChatBtn.addEventListener('click', function () { openChat(); });
document.body.appendChild(topChatBtn);
}
function buildWhoami() {
if (built) return;
var base = whoamiBase();
var hero = document.getElementById('kimodo-whoami-hero-img');
if (hero && !hero.getAttribute('src')) hero.src = base + 'weiner.webp';
welcomeBtn = document.getElementById('kimodo-whoami-wspeak');
if (welcomeBtn && !welcomeBtn._wired) { welcomeBtn._wired = true; wireSpeak(welcomeBtn, '', false, base + 'wiener-welcome.wav'); }
var gal = document.getElementById('kimodo-whoami-gallery');
if (gal && !gal.childNodes.length) {
galleryImages = [];
for (var i = 1; i <= TESTIMONIALS; i++) {
var src = base + 'testimonial-' + i + '.webp';
galleryImages.push(src);
var img = document.createElement('img');
img.src = src; img.alt = 'Student testimonial ' + i; img.loading = 'lazy';
img.addEventListener('click', (function (idx) { return function () { openLightbox(idx); }; })(i - 1));
gal.appendChild(img);
}
}
var chatBtn = document.getElementById('kimodo-whoami-chatbtn');
if (chatBtn && !chatBtn._wired) {
chatBtn._wired = true;
var av = document.getElementById('kimodo-whoami-chatav');
if (av && !av.getAttribute('src')) av.src = base + 'wiener-meditate.webp';
chatBtn.addEventListener('click', openChat);
}
built = true;
}
// ---- Shared voice player ---------------------------------------------------
// ONE