/* PROJECT 1804 · motion layer v2 (2026-11-03): sticky names find their card by name, page locked under the phone menu. Loaded at the end of the site footer, after Lenis 1.3, GSAP 3 + ScrollTrigger and SplitType. Every effect sits behind a flag in F: set it to 0, upload the file again and point the footer at the new URL. Page transitions, the no-flash rules and the preloader-once rule live in the head code, not here. */ (function () { var F = { lenis: 1, // smooth scroll, one clock with GSAP header: 1, // header hides on the way down, returns on the way up, paper under it cursor: 1, // "View case" label over case cards (mouse only) names: 1, // giant case names fill with ink as their card scrolls past reveal: 1, // case gallery images open from the bottom parallax: 1, // full-width case photos drift inside their frame (desktop) next: 1, // "Next project" block at the end of each case lines: 1, // one line-by-line heading per page (pages without case cards) sound: 1, // equaliser bars next to SOUND: ON while the track plays wordmark: 1, // footer wordmark rises out of its slot hover: 1, // one underline hover for text links grain: 1, // static paper grain on the first screen video: 1 // heavy GIFs play as MP4 }; var d = document, html = d.documentElement, W = window; if (html.classList.contains('w-editor')) return; var RM = matchMedia('(prefers-reduced-motion: reduce)').matches; var FINE = matchMedia('(hover: hover) and (pointer: fine)').matches; var WIDE = matchMedia('(min-width: 992px)').matches; var EASE = 'cubic-bezier(.22,1,.36,1)'; var gsap = W.gsap, ST = W.ScrollTrigger; if (gsap && ST) gsap.registerPlugin(ST); var $$ = function (s, root) { return [].slice.call((root || d).querySelectorAll(s)); }; var path = location.pathname.replace(/\/$/, '') || '/'; var isCase = /^\/projects\/[^/]+$/.test(path); try { sessionStorage.setItem('p18-seen', '1'); } catch (e) {} if (path === '/') return; // the preloader page only forwards to /agency var css = ''; function style() { var s = d.createElement('style'); s.id = 'p18-motion'; s.textContent = css; d.head.appendChild(s); } /* Smooth scroll. lerp .09 answers the wheel at once and settles in ~0.4 s; the old build eased every wheel tick over 1.5 s. */ var lenis = null; if (F.lenis && W.Lenis) { lenis = new W.Lenis({ lerp: 0.09, anchors: true, stopInertiaOnNavigate: true }); W.p18lenis = lenis; if (gsap && ST) { lenis.on('scroll', ST.update); gsap.ticker.add(function (t) { lenis.raf(t * 1000); }); gsap.ticker.lagSmoothing(0); } else { requestAnimationFrame(function raf(t) { lenis.raf(t); requestAnimationFrame(raf); }); } css += '.lenis.lenis-stopped{overflow:clip}.lenis [data-lenis-prevent]{overscroll-behavior:contain}.lenis.lenis-smooth iframe{pointer-events:none}'; } function onScroll(fn) { if (lenis) lenis.on('scroll', function (e) { fn(e.scroll); }); else W.addEventListener('scroll', function () { fn(W.scrollY); }, { passive: true }); } /* Header: out of the way while reading down, back on the first move up. Paper fades in under it once the page has moved, so text no longer runs through the logo and menu. Never hides over the first screen (the asterisk becomes the logo there) or while the phone menu is open. */ if (F.header) { var paper = d.createElement('div'); paper.className = 'p18-paper'; paper.setAttribute('aria-hidden', 'true'); d.body.appendChild(paper); var last = W.scrollY, hidden = false, menu = d.querySelector('.menu-main'); var setHidden = function (h) { if (h !== hidden) { hidden = h; html.classList.toggle('p18-hide', h); } }; onScroll(function (y) { var dy = y - last; last = y; html.classList.toggle('p18-scrolled', y > 40); // .menu-main is the desktop nav row too; on phones it is the menu sheet, 0 px tall while closed. var menuOpen = W.innerWidth < 992 && menu && menu.getBoundingClientRect().height > 40; if (menuOpen || y < Math.max(W.innerHeight * 0.9, 320)) setHidden(false); else if (dy > 3) setHidden(true); else if (dy < -3) setHidden(false); }); d.addEventListener('focusin', function (e) { if (e.target.closest && e.target.closest('.navbar, .navbar-logo-div')) setHidden(false); }); // Phone menu open: the page underneath stays where it was (it used to scroll behind the sheet). if (menu && 'ResizeObserver' in W) { var locked = false; new ResizeObserver(function () { var open = W.innerWidth < 992 && menu.getBoundingClientRect().height > 40; if (open === locked) return; locked = open; html.classList.toggle('p18-menu-open', open); if (lenis) open ? lenis.stop() : lenis.start(); }).observe(menu); css += 'html.p18-menu-open,html.p18-menu-open body{overflow:hidden;overscroll-behavior:none}'; } css += '.navbar,.navbar-logo-div,.div-logo-lottie{transition:translate .7s ' + EASE + '}' + 'html.p18-hide .navbar,html.p18-hide .navbar-logo-div{translate:0 -140%}' + 'html.p18-hide .div-logo-lottie{translate:0 -100vh}' + '.p18-paper{position:fixed;left:0;right:0;top:0;height:150px;z-index:9998;pointer-events:none;background:linear-gradient(#f6f6f6 58%,rgba(246,246,246,0));opacity:0;transition:opacity .5s,translate .7s ' + EASE + '}' + 'html.p18-scrolled .p18-paper{opacity:1}html.p18-hide .p18-paper{translate:0 -100%}' + 'body:has(.rich-para) .p18-paper{display:none}' + '@media (prefers-reduced-motion:reduce){.navbar,.navbar-logo-div,.div-logo-lottie,.p18-paper{transition:opacity .2s}}' + '@media (max-width:767px){.p18-paper{height:92px}}'; } /* Contextual cursor over case cards: the photos become one big link to the case. Mouse and trackpad only. */ if (F.cursor && FINE && gsap) { var cards = $$('.single-card').filter(function (c) { return c.querySelector('a[href*="/projects/"]'); }); if (cards.length) { var cur = d.createElement('div'); cur.className = 'p18-cursor'; cur.setAttribute('aria-hidden', 'true'); cur.innerHTML = 'View case→'; d.body.appendChild(cur); var xTo = gsap.quickTo(cur, 'x', { duration: 0.5, ease: 'power3' }), yTo = gsap.quickTo(cur, 'y', { duration: 0.5, ease: 'power3' }); W.addEventListener('pointermove', function (e) { xTo(e.clientX); yTo(e.clientY); }, { passive: true }); cards.forEach(function (c) { var href = c.querySelector('a[href*="/projects/"]').getAttribute('href'); $$('img', c).forEach(function (img) { img.classList.add('p18-card-img'); img.addEventListener('pointerenter', function () { cur.classList.add('is-on'); }); img.addEventListener('pointerleave', function () { cur.classList.remove('is-on'); }); img.addEventListener('click', function () { location.href = href; }); }); }); d.addEventListener('pointerleave', function () { cur.classList.remove('is-on'); }); css += '.p18-card-img{cursor:none}' + '.p18-cursor{position:fixed;left:0;top:0;z-index:99990;pointer-events:none}' + '.p18-cursor-in{position:absolute;left:0;top:0;display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:5px;background:#1f1c1c;color:#f6f6f6;font:500 11px/1 Ppneuemontrealmono,ui-monospace,monospace;letter-spacing:-.02em;text-transform:uppercase;white-space:nowrap;transform:translate(-50%,-50%) scale(.5);opacity:0;transition:opacity .25s,transform .45s ' + EASE + '}' + '.p18-cursor.is-on .p18-cursor-in{opacity:1;transform:translate(-50%,-50%)}.p18-cursor i{font-style:normal}'; } } /* Giant case names: ink runs left to right while their card passes through the middle of the screen. Desktop shows one sticky name per card (.text-big._N), phones show the name inside each card. This is the text moment on these pages. */ var hasNames = !!d.querySelector('.single-card'); if (F.names && gsap && ST && hasNames && !RM) { // Sticky names (.text-big._N) are not numbered in card order, so they find their card by the name each card carries. var byName = {}, key = function (e) { return e.textContent.trim().toLowerCase(); }; $$('.wrap-cards .single-card').forEach(function (c) { var t = c.querySelector('.text-big'); if (t) byName[key(t)] = c; }); $$('.text-big').forEach(function (el) { var card = el.closest('.single-card') || byName[key(el)]; if (!card) Object.keys(byName).forEach(function (k) { if (!card && (k.indexOf(key(el)) === 0 || key(el).indexOf(k) === 0)) card = byName[k]; }); if (!card) return; el.classList.add('p18-ink'); // In while the card arrives, out again while it leaves: the sticky name hands over to the next card while still pale, // so dark ink never sits on top of the next card's captions. gsap.fromTo(el, { '--p18ink': '0%' }, { '--p18ink': '100%', ease: 'none', scrollTrigger: { trigger: card, start: 'top 85%', end: 'top 30%', scrub: 0.4 } }); gsap.fromTo(el, { '--p18ink': '100%' }, { '--p18ink': '0%', ease: 'none', immediateRender: false, scrollTrigger: { trigger: card, start: 'bottom 80%', end: 'bottom 40%', scrub: 0.4 } }); }); css += '.p18-ink{background:linear-gradient(90deg,#1f1c1c var(--p18ink,0%),rgba(31,28,28,.1) var(--p18ink,0%));-webkit-background-clip:text;background-clip:text;color:transparent!important}'; } /* One line-by-line heading per page, on pages without case cards: the first big heading below the first screen. Everything else that used to split into lines now just stands still (the site head no longer hides it). */ if (F.lines && W.SplitType && gsap && ST && !hasNames && !RM) { var moment = $$('h1[js-line-animation]').filter(function (e) { return e.offsetWidth && e.getBoundingClientRect().top + W.scrollY > W.innerHeight * 0.9; })[0]; if (moment) { var text = moment.innerHTML, played = false, tl; var split = function () { new W.SplitType(moment, { types: 'lines', tagName: 'span' }); $$('.line', moment).forEach(function (l) { l.style.overflow = 'hidden'; l.innerHTML = '' + l.innerHTML + ''; }); if (played) return; tl = gsap.fromTo($$('.line-inner', moment), { yPercent: 105 }, { yPercent: 0, duration: 1.1, ease: 'expo.out', stagger: 0.09, scrollTrigger: { trigger: moment, start: 'top 82%', once: true, onEnter: function () { played = true; } } }); }; split(); var ww = W.innerWidth; W.addEventListener('resize', function () { if (ww === W.innerWidth) return; ww = W.innerWidth; if (tl) { tl.scrollTrigger && tl.scrollTrigger.kill(); tl.kill(); } moment.innerHTML = text; split(); }); } } /* Case galleries. Images below the first screen open from the bottom and settle from a slight zoom. Full-width photos on desktop also drift inside a still frame: the photo moves, its clip keeps the original box. */ if (isCase && gsap && ST && !RM) { var skip = '.navbar, .navbar-logo-div, .container.footer, .p18-next'; var imgs = $$('img').filter(function (i) { return !i.closest(skip) && i.getBoundingClientRect().width >= 160 && i.getBoundingClientRect().top > W.innerHeight; }); imgs.forEach(function (img) { var drift = F.parallax && WIDE && img.classList.contains('full-image'); if (drift) return frame(img); if (!F.reveal) return; gsap.set(img, { clipPath: 'inset(100% 0% 0% 0%)', scale: 1.06 }); ST.create({ trigger: img, start: 'top 90%', once: true, onEnter: function () { gsap.to(img, { clipPath: 'inset(0% 0% 0% 0%)', scale: 1, duration: 1.3, ease: 'expo.out', clearProps: 'clipPath,scale' }); } }); }); } function frame(img) { var s = 1.12, st = { r: F.reveal ? 0 : 1, p: 0.5 }; var draw = function () { var H = img.offsetHeight, Wd = img.offsetWidth, y = (st.p - 0.5) * H * 0.16, c = H / 2; var top = c + ((1 - st.r) * H - c - y) / s, bottom = H - (c + (H - c - y) / s), side = Wd / 2 * (1 - 1 / s); img.style.transform = 'translateY(' + y.toFixed(1) + 'px) scale(' + s + ')'; img.style.clipPath = 'inset(' + top.toFixed(1) + 'px ' + side.toFixed(1) + 'px ' + bottom.toFixed(1) + 'px ' + side.toFixed(1) + 'px)'; }; ST.create({ trigger: img, start: 'top bottom', end: 'bottom top', onUpdate: function (t) { st.p = t.progress; draw(); }, onRefresh: function (t) { st.p = t.progress; draw(); } }); if (st.r < 1) ST.create({ trigger: img, start: 'top 90%', once: true, onEnter: function () { gsap.to(st, { r: 1, duration: 1.4, ease: 'expo.out', onUpdate: draw }); } }); draw(); } /* Next project: the case after this one in the /projects order, with its cover. Click it, or keep scrolling at the very end of the page (mouse wheel or trackpad) and the bar fills and opens it. */ var CASES = [ ['lavarice', 'LAVARICE', 'Los Angeles · 2024', '6ae7bcc714a0aeeec4477889_og-lavarice.jpg'], ['glam', 'Glam Monte Carlo', 'Monte Carlo · 2024', '6ae7bcc57e6c65460192dfd6_og-glam.jpg'], ['saint-pierre', 'Saint Pierre', 'Saint Petersburg · 2022', '6ae7bcc80ebf16266cd86ea0_og-saint-pierre.jpg'], ['pose', 'POSE', 'London · 2024', '6ae7bcc7522bb0c8cb9229d8_og-pose.jpg'], ['eyes-platform', 'EYES PLATFORM', 'Worldwide · 2024', '6ae7bcc5090a7742ca0627cc_og-eyes-platform.jpg'], ['darlen', 'Darlen Studio', 'Milan · 2024', '6ae7bcc5b08d03148ac06913_og-darlen.jpg'], ['project-1804', 'PROJECT 1804', 'Paris · 2024', '6ae7bcc753ae0c83a599f159_og-project-1804.jpg'], ['ton', 'TON', 'Saint Petersburg · 2024', '6ae7bcc8dde1963f81b3f163_og-ton.jpg'], ['maison25', 'MAISON25', 'Saint Petersburg · 2021', '6ae7bcc7282296bdd5e4e71c_og-maison25.jpg'], ['talli-beauty', 'Talli Beauty', 'Astana · 2023', '6ae7bcc853ae0c83a599f1ca_og-talli-beauty.jpg'], ['moyen', 'Moyen', 'Saint Petersburg · 2023', '6ae7bcc7b08d03148ac069e1_og-moyen.jpg'] ]; var footer = d.querySelector('.container.footer'); if (F.next && isCase && footer) { var at = -1; CASES.forEach(function (c, i) { if (path === '/projects/' + c[0]) at = i; }); if (at > -1) { var nx = CASES[(at + 1) % CASES.length]; var sec = d.createElement('section'); sec.className = 'p18-next'; sec.innerHTML = '' + 'Next project' + (at + 2 > CASES.length ? 1 : at + 2) + ' / ' + CASES.length + '' + '' + nx[1] + ' →' + '' + nx[2] + '' + '' + nx[1] + ', cover' + ''; footer.parentNode.insertBefore(sec, footer); css += '.p18-next{padding:14vh 3vw 10vh}' + '.p18-next-a{display:grid;grid-template-columns:1fr 1fr;column-gap:3vw;align-items:end;color:#1f1c1c;text-decoration:none}' + '.p18-next-k{grid-column:1/-1;display:flex;justify-content:space-between;padding-bottom:14px;margin-bottom:4vh;border-bottom:1px solid #1f1c1c26;font:500 11px/1.2 Ppneuemontrealmono,ui-monospace,monospace;letter-spacing:-.02em;text-transform:uppercase;color:#1f1c1c99}' + '.p18-next-n{grid-column:1;font:600 clamp(40px,6vw,96px)/.92 Ppmori,sans-serif;letter-spacing:-.03em;text-transform:uppercase}' + '.p18-next-n i{display:inline-block;font-style:normal;transition:translate .6s ' + EASE + '}' + '.p18-next-m{grid-column:1;margin-top:18px;font:500 11px/1.2 Ppneuemontrealmono,ui-monospace,monospace;letter-spacing:-.02em;text-transform:uppercase;color:#1f1c1c99}' + '.p18-next-f{grid-column:2;grid-row:2/4;display:block;overflow:hidden;border-radius:3px;aspect-ratio:1200/630;background:#e9e7e7}' + '.p18-next-f img{display:block;width:100%;height:100%;object-fit:cover;transition:scale 1.2s ' + EASE + '}' + '@media (hover:hover) and (pointer:fine){.p18-next-a:hover .p18-next-f img{scale:1.04}.p18-next-a:hover .p18-next-n i{translate:12px 0}}' + '.p18-next-a:focus-visible{outline:1px solid #1f1c1c;outline-offset:8px}' + '@media (max-width:767px){.p18-next{padding:10vh 16px 8vh}.p18-next-a{grid-template-columns:1fr;row-gap:0}.p18-next-f{grid-column:1;grid-row:auto;margin-top:28px}}'; // Pull to the next case: wheel past the end of the page fills a bar at the bottom; 0.8 s without wheel lets it drain. if (FINE && lenis) { var bar = d.createElement('div'); bar.className = 'p18-pull'; bar.setAttribute('aria-hidden', 'true'); bar.innerHTML = 'Keep scrolling · ' + nx[1] + ''; d.body.appendChild(bar); var acc = 0, idle, gone = false, NEED = 900; var fill = function () { bar.style.setProperty('--p', Math.min(acc / NEED, 1)); bar.classList.toggle('is-on', acc > 0); }; W.addEventListener('wheel', function (e) { // Native check: Lenis' own limit can lag behind lazy images by a few dozen px. if (gone || e.deltaY <= 0 || W.innerHeight + W.scrollY < d.documentElement.scrollHeight - 2) { if (e.deltaY < 0 && acc) { acc = 0; fill(); } return; } acc += Math.min(e.deltaY, 120); fill(); clearTimeout(idle); idle = setTimeout(function () { acc = 0; fill(); }, 800); if (acc >= NEED) { gone = true; location.href = '/projects/' + nx[0]; } }, { passive: true }); css += '.p18-pull{position:fixed;left:50%;bottom:24px;z-index:99980;translate:-50% 20px;opacity:0;pointer-events:none;display:flex;flex-direction:column;gap:9px;min-width:240px;padding:12px 16px 14px;border-radius:5px;background:#1f1c1c;color:#f6f6f6;font:500 11px/1 Ppneuemontrealmono,ui-monospace,monospace;letter-spacing:-.02em;text-transform:uppercase;transition:opacity .3s,translate .5s ' + EASE + '}' + '.p18-pull.is-on{opacity:1;translate:-50% 0}' + '.p18-pull b{display:block;height:1px;background:#f6f6f640;position:relative}.p18-pull b:after{content:"";position:absolute;inset:0;background:#f6f6f6;transform-origin:left;transform:scaleX(var(--p,0));transition:transform .2s linear}'; } } } /* Footer wordmark rises out of its slot as the footer comes up: it moves down by d and is clipped by d at the bottom, so the edge of the slot stays put. */ if (F.wordmark && gsap && ST && footer && !RM) { var wm = footer.querySelector(':scope > img.main-image'); if (wm) { gsap.fromTo(wm, { yPercent: 100, clipPath: 'inset(0% 0% 100% 0%)' }, { yPercent: 0, clipPath: 'inset(0% 0% 0% 0%)', ease: 'none', scrollTrigger: { trigger: footer, start: 'top bottom', end: 'bottom bottom', scrub: 0.5 } }); } } /* SOUND: ON gets three small bars that move while the track plays. */ if (F.sound) { var audio = d.getElementById('myAudio'); $$('.play .nav-link-child > p').forEach(function (c) { var eq = d.createElement('span'); eq.className = 'p18-eq'; eq.setAttribute('aria-hidden', 'true'); eq.innerHTML = ''; c.appendChild(eq); }); if (audio) { var u = function () { html.classList.toggle('p18-playing', !audio.paused); }; audio.addEventListener('play', u); audio.addEventListener('pause', u); u(); } css += // Out of the flow: the word ON and its neighbours never move. Phones show SOUND: ON • OFF in one tight row, so no bars there. '.play .nav-link-child>p{position:relative}' + '.p18-eq{position:absolute;left:100%;bottom:.12em;display:flex;align-items:flex-end;gap:1.5px;height:.72em;margin-left:5px;opacity:0;transition:opacity .3s}' + '@media (max-width:767px){.p18-eq{display:none}}' + 'html.p18-playing .p18-eq{opacity:1}' + '.p18-eq i{width:1.5px;height:100%;background:currentColor;transform-origin:bottom;transform:scaleY(.35)}' + 'html.p18-playing .p18-eq i{animation:p18eq 1s ease-in-out infinite}' + '.p18-eq i:nth-child(2){animation-duration:.8s!important;animation-delay:-.4s!important}.p18-eq i:nth-child(3){animation-duration:1.2s!important;animation-delay:-.7s!important}' + '@keyframes p18eq{0%,100%{transform:scaleY(.35)}50%{transform:scaleY(1)}}' + '@media (prefers-reduced-motion:reduce){html.p18-playing .p18-eq i{animation:none;transform:scaleY(.7)}}'; } /* Text links (menu, footer): an underline draws in from the left and leaves to the right. */ if (F.hover) { css += '@media (hover:hover) and (pointer:fine){' + '.nav-link .nav-link-child>p{background:linear-gradient(currentColor,currentColor) no-repeat 100% 100%/0 1px;transition:background-size .5s ' + EASE + '}' + '.nav-link:hover .nav-link-child>p,.nav-link:focus-visible .nav-link-child>p{background-position:0 100%;background-size:100% 1px}}'; } /* Paper grain on the first screen only: static, under the header, fades out towards the bottom of the screen. */ if (F.grain) { var g = d.createElement('div'); g.className = 'p18-grain'; g.setAttribute('aria-hidden', 'true'); d.body.appendChild(g); css += '.p18-grain{position:absolute;left:0;top:0;width:100%;height:100vh;z-index:9997;pointer-events:none;opacity:.07;' + '-webkit-mask-image:linear-gradient(#000 55%,transparent);mask-image:linear-gradient(#000 55%,transparent);' + // Sparse dark specks (only the top third of the noise shows): tooth on the paper, its average tone moves by about 1 %. "background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .12 0 0 0 0 .11 0 0 0 0 .11 6 0 0 0 -3.3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")}"; } /* Heavy GIFs play as MP4 (about half the bytes). The video takes the image's classes and aspect, loads when it nears the screen. */ if (F.video) { var C = 'https://cdn.prod.website-files.com/66befd61cfe1b91f20ffdb64/'; var PROD = [C + '6aea04cfc7e4e652c1a224d3_p18-production-hero.mp4', 1178, 1500, C + '6aea04cf8ab45aba0b8aac34_p18-production-hero-poster.jpg']; var V = {}; // image src -> [mp4, width, height, poster] V[C + '68fa4253c27b8c68d59a2fed_SATO-%E2%80%94-01-1.gif'] = [C + '6aea04cec7e4e652c1a224af_p18-sato-01.mp4', 884, 996]; V[C + '68fa43d155a6267b59952cf5_Frame-160.gif'] = [C + '6aea04cf20c18b429a47823e_p18-frame-160.mp4', 958, 700]; V[C + '69032e00c4405290b612a945_Frame-186.gif'] = [C + '6aea04cf20c18b429a47825d_p18-frame-186.mp4', 870, 600]; V[PROD[3]] = PROD; // /services/production hero: the page now ships the poster frame, the video takes over V['https://cdn.prod.website-files.com/69b830f4fbeae5085f401251/699576d71871260bee66be9e_Untitled-1.gif'] = PROD; var io = 'IntersectionObserver' in W && new IntersectionObserver(function (es) { es.forEach(function (e) { if (e.isIntersecting) { io.unobserve(e.target); e.target.src = e.target.dataset.src; e.target.play && e.target.play().catch(function () {}); } }); }, { rootMargin: '600px 0px' }); $$('img').forEach(function (img) { var m = V[img.getAttribute('src')]; if (!m) return; var v = d.createElement('video'); v.className = img.className; if (img.id) v.id = img.id; v.muted = v.loop = v.autoplay = v.playsInline = true; v.setAttribute('muted', ''); v.setAttribute('playsinline', ''); v.setAttribute('role', 'img'); v.setAttribute('aria-label', img.alt || ''); v.preload = 'none'; v.style.aspectRatio = m[1] + '/' + m[2]; // the image's own proportions; its class still sets width or height v.style.objectFit = 'cover'; if (m[3]) v.poster = m[3]; v.dataset.src = m[0]; img.replaceWith(v); io ? io.observe(v) : (v.src = v.dataset.src); }); } style(); if (ST) W.addEventListener('load', function () { ST.refresh(); }); })();