// Collapsible walkthrough player for Suite tool pages. // // Placement reasoning (Marty's call): the video belongs at the TOP of the tool, // because a video in a separate library never gets watched — but it must not be // an embedded player, because after the first week most visits are returning // members who came to USE the tool, and a player pushes the tool below the fold // on mobile every single time. // // So: a one-line bar that expands inline, auto-opened on the member's FIRST // visit to that specific tool and collapsed on every visit after. The state is // per-tool, per-browser. localStorage can throw outright in some contexts // (private windows, blocked site data), so every access is guarded and the bar // falls back to "collapsed but present" rather than breaking the page. (function () { 'use strict'; var el = document.currentScript; var SRC = el && el.getAttribute('data-video'); var TITLE = (el && el.getAttribute('data-title')) || 'Watch the walkthrough'; var KEY = 'rmc.tv.' + ((el && el.getAttribute('data-key')) || (location.pathname.replace(/\W+/g, '') || 'tool')); var SECS = (el && el.getAttribute('data-secs')) || ''; if (!SRC) return; function seen() { try { return localStorage.getItem(KEY) === '1'; } catch (e) { return true; } } function markSeen() { try { localStorage.setItem(KEY, '1'); } catch (e) {} } function build() { var host = document.querySelector('main') || document.body; var wrap = document.createElement('div'); wrap.className = 'tv-wrap'; var bar = document.createElement('button'); bar.type = 'button'; bar.className = 'tv-bar'; bar.setAttribute('aria-expanded', 'false'); bar.innerHTML = '▶' + TITLE + (SECS ? ' ' + SECS + '' : '') + '⌄'; var body = document.createElement('div'); body.className = 'tv-body'; body.hidden = true; var vid = document.createElement('video'); vid.controls = true; // Poster lives beside the video (same slug, .jpg). Without it the browser // shows frame zero, and frame zero is the instant before the page painted // — a blank white rectangle that reads as a broken player. vid.poster = SRC.replace(/\.mp4$/, '.jpg'); // Nothing is fetched until the panel is actually opened; open() then bumps // this to 'metadata' so an expanded panel shows a real first frame rather // than a black rectangle. vid.preload = 'none'; vid.playsInline = true; vid.src = SRC; body.appendChild(vid); function open() { body.hidden = false; wrap.classList.add('on'); bar.setAttribute('aria-expanded', 'true'); // Deliberately NOT autoplaying. Browsers only permit autoplay when the // video is muted, and a silent walkthrough is worthless here — the // narration IS the training. So on first visit the panel opens with the // video paused and the play button showing; pressing it is a user // gesture, which means it plays with sound, every time. vid.preload = 'metadata'; } function close() { body.hidden = true; wrap.classList.remove('on'); bar.setAttribute('aria-expanded', 'false'); vid.pause(); } bar.addEventListener('click', function () { if (body.hidden) { open(); markSeen(); } else close(); }); wrap.appendChild(bar); wrap.appendChild(body); // Sit directly under the page heading if there is one, otherwise at the top. var h1 = host.querySelector('h1'); var lede = h1 && h1.nextElementSibling && /lede|sub/.test(h1.nextElementSibling.className || '') ? h1.nextElementSibling : h1; if (lede && lede.parentNode) lede.parentNode.insertBefore(wrap, lede.nextSibling); else host.insertBefore(wrap, host.firstChild); if (!seen()) { open(); markSeen(); } } function style() { if (document.getElementById('tv-style')) return; var s = document.createElement('style'); s.id = 'tv-style'; s.textContent = [ '.tv-wrap{margin:0 0 18px}', '.tv-bar{display:flex;align-items:center;gap:10px;width:100%;text-align:left;cursor:pointer;', ' background:rgba(212,175,55,.08);border:1px solid var(--gold,#d4af37);border-radius:12px;', ' color:var(--text,#e8eef4);padding:11px 15px;font:inherit;font-size:14.5px;font-weight:700}', '.tv-bar:hover{background:rgba(212,175,55,.14)}', '.tv-bar:focus-visible{outline:2px solid var(--teal,#4ed6cb);outline-offset:2px}', '.tv-play{color:var(--gold,#d4af37);font-size:12px}', '.tv-t{flex:1}', '.tv-secs{color:var(--muted,#8fa6bb);font-weight:600;font-size:12.5px}', '.tv-chev{color:var(--muted,#8fa6bb);transition:transform .18s}', '.tv-wrap.on .tv-chev{transform:rotate(180deg)}', '.tv-body{margin-top:10px;border:1px solid var(--line,#24425d);border-radius:12px;overflow:hidden;line-height:0}', '.tv-body video{width:100%;height:auto;display:block;background:#000}', '@media (prefers-reduced-motion:reduce){.tv-chev{transition:none}}' ].join(''); document.head.appendChild(s); } function go() { style(); build(); } if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', go); else go(); })();