{"id":908,"date":"2026-09-30T07:26:32","date_gmt":"2026-09-30T07:26:32","guid":{"rendered":"https:\/\/www.visionpros.ca\/pro\/?p=908"},"modified":"2026-09-30T07:50:47","modified_gmt":"2026-09-30T07:50:47","slug":"how-to-remove-contact-lenses","status":"publish","type":"post","link":"https:\/\/www.visionpros.ca\/pro\/how-to-remove-contact-lenses\/","title":{"rendered":"How to Remove Contact Lenses: A Simple Animated Guide"},"content":{"rendered":"\n<style>[class*=\"vpa-\"]{box-sizing:border-box}.vpa-quick,.vpa-jump,.vpa-prep,.vpa-video,.vpa-card,.vpa-note,.vpa-list,.vpa-cta{--s:#34495e;--b:#4a76b7;--bd:#3a629b;--pb:#f4f8ff;--ln:#dbe5f3;--warn:#d9635a;max-width:1200px}.vpa-w{max-width:1200px}p.vpa-w{line-height:1.65}.wp-block-heading.vpa-w{margin:38px auto 14px!important;scroll-margin-top:150px}h3.wp-block-heading.vpa-w{margin-top:34px!important}p.vpa-lead{font-size:1.15em;line-height:1.6}p.vpa-mini{font-size:15px;color:#4b5563}p.vpa-ref{font-size:14px;line-height:1.5;color:#374151;padding-bottom:6px!important}p.vpa-fine{font-size:14px;line-height:1.55;color:#4b5563;margin-top:18px}.vpa-w a,.vpa-note a,.vpa-list a{color:#3a629b;text-decoration:underline;text-underline-offset:2px}.vpa-w a:hover,.vpa-note a:hover,.vpa-list a:hover{color:#34495e}.vpa-quick{margin:1.4em auto;padding:16px 20px;background:var(--pb);border:1.5px solid var(--ln);border-radius:12px;box-shadow:3px 4px 0 rgba(160,185,225,.38)}.vpa-quick p{margin:0!important;padding:0!important;line-height:1.6}.vpa-jump{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:1.2em auto}.vpa-jump span{font-weight:700;color:var(--s);margin-right:2px}.vpa-jump a{display:inline-block;padding:7px 15px;border-radius:999px;background:#fff;border:1px solid var(--ln);color:var(--bd);text-decoration:none;font-weight:700;font-size:15px;line-height:1.25}.vpa-jump a:hover,.vpa-jump a:focus-visible{background:var(--b);border-color:var(--b);color:#fff}.vpa-prep{margin:1.4em auto;border:1px solid var(--ln);border-radius:10px;overflow:hidden;background:#fff;box-shadow:0 2px 8px rgba(0,0,0,.05)}.vpa-prep-h{background:var(--s);color:#fff;font-size:13px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;padding:9px 16px}.vpa-prep ul{list-style:none;margin:0!important;padding:0!important;display:grid;grid-template-columns:repeat(3,1fr)}.vpa-prep li{list-style:none;margin:0;padding:14px 16px;display:flex;gap:12px;align-items:flex-start;border-left:1px solid var(--ln)}.vpa-prep li:first-child{border-left:0}.vpa-prep svg{flex:0 0 30px;width:30px;height:30px}.vpa-prep b{display:block;color:var(--s);line-height:1.3}.vpa-prep small{display:block;font-size:14px;line-height:1.4;color:#4b5563;margin-top:2px}.vpa-video{margin:1.2em auto;padding:0;max-width:860px}.vpa-video>div{aspect-ratio:16\/9;border-radius:16px;overflow:hidden;background:#fdf4ea;box-shadow:0 6px 22px rgba(52,73,94,.18)}.vpa-video svg{display:block;width:100%;height:auto}.vpa-video noscript{display:block;padding:24px;line-height:1.5;color:#4b5563}.vpa-card{margin:1.2em auto;border:1px solid var(--ln);border-radius:10px;overflow:hidden;background:#fff;box-shadow:0 2px 8px rgba(0,0,0,.06)}.vpa-card-h{background:var(--s);color:#fff;font-size:13px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;padding:9px 16px}.vpa-ol{list-style:none;counter-reset:vs;margin:0!important;padding:0!important}.vpa-ol li{list-style:none;counter-increment:vs;display:flex;gap:14px;align-items:flex-start;margin:0;padding:13px 16px;line-height:1.5}.vpa-ol li:nth-child(even){background:var(--pb)}.vpa-ol li::before{content:counter(vs);flex:0 0 28px;height:28px;border-radius:50%;background:var(--b);color:#fff;font-weight:700;font-size:15px;display:flex;align-items:center;justify-content:center;margin-top:-1px}.vpa-note{margin:1.2em auto;padding:14px 18px;background:#fff6d9;border:1.5px solid #f3d98d;border-radius:12px;box-shadow:3px 4px 0 rgba(240,207,168,.55)}.vpa-note p{margin:0!important;padding:0!important;font-size:15px;line-height:1.6;color:#2a2a2a}.vpa-note b{color:#8a5210}.vpa-warn{background:#ffeceb;border-color:#f3b8b1;box-shadow:3px 4px 0 rgba(243,184,177,.5)}.vpa-warn b{color:#b4463e}.vpa-list{list-style:none;margin:.6em auto 1.2em!important;padding:0!important}.vpa-list li{list-style:none;position:relative;margin:0;padding:7px 0 7px 34px;line-height:1.55}.vpa-list li::before{content:\"\";position:absolute;left:2px;top:11px;width:20px;height:20px;border-radius:50%;background:#4a76b7 url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.6 6.3l2.3 2.3 4.5-4.9' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'\/%3E%3C\/svg%3E\") center\/12px no-repeat}.vpa-alert li::before{background:#d9635a url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' viewBox='0 0 12 12'%3E%3Cpath d='M6 2.6v4' stroke='%23fff' stroke-width='1.8' stroke-linecap='round'\/%3E%3Ccircle cx='6' cy='9.2' r='1' fill='%23fff'\/%3E%3C\/svg%3E\") center\/12px no-repeat}.vpa-cta{display:flex;flex-wrap:wrap;gap:12px;margin:1em auto 1.4em}.vpa-btn{display:inline-block;padding:13px 24px;border-radius:999px;background:var(--bd);color:#fff!important;font-weight:700;text-decoration:none!important;line-height:1.2;border:2px solid var(--bd)}.vpa-btn:hover,.vpa-btn:focus-visible{background:var(--s);border-color:var(--s)}.vpa-btn.alt{background:#fff;color:var(--bd)!important}.vpa-btn.alt:hover,.vpa-btn.alt:focus-visible{background:var(--pb);border-color:var(--s);color:var(--s)!important}.vpa-w,.vpa-quick,.vpa-jump,.vpa-prep,.vpa-video,.vpa-card,.vpa-note,.vpa-list,.vpa-cta{margin-left:auto!important;margin-right:auto!important}.vpa-jump a:focus-visible,.vpa-btn:focus-visible,.vpa-w a:focus-visible,.vpa-note a:focus-visible,.vpa-list a:focus-visible{outline:3px solid #4a76b7;outline-offset:2px}@media (max-width:700px){.vpa-prep ul{grid-template-columns:1fr}.vpa-prep li{border-left:0;border-top:1px solid var(--ln)}.vpa-prep li:first-child{border-top:0}.vpa-video>div{border-radius:12px}.vpa-ol li{padding:12px 14px}}<\/style>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-lead\">Taking out contacts shouldn\u2019t feel like a wrestling match. With the right technique, it takes a few seconds and doesn\u2019t hurt. Pick your lens type below, watch the short animation, then try it in the mirror. Every clip loops, so you can leave it playing while you practise.<\/p>\n\n\n\n<div class=\"vpa-quick\"><p><strong>The gist (soft lenses):<\/strong> wash and dry your hands, look up, pull your lower lid down, slide the lens to the white of your eye, then gently pinch and lift it out.<\/p><\/div>\n<nav class=\"vpa-jump\" aria-label=\"Jump to a method\"><span>Jump to:<\/span><a href=\"#pinch\">Pinch method<\/a><a href=\"#slide\">Long nails<\/a><a href=\"#stuck\">Stuck or dry lens<\/a><a href=\"#rigid\">Rigid lenses<\/a><\/nav>\n<div class=\"vpa-prep\"><div class=\"vpa-prep-h\">Before you start<\/div><ul>\n<li><svg viewBox=\"0 0 30 30\" fill=\"none\" stroke=\"#4a76b7\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><circle cx=\"11\" cy=\"18\" r=\"7\"><\/circle><circle cx=\"21.5\" cy=\"9\" r=\"4.5\"><\/circle><circle cx=\"23\" cy=\"21.5\" r=\"3\"><\/circle><path d=\"M8 15.5a4 4 0 0 1 3-2\"><\/path><\/svg><span><b>Clean, dry hands<\/b><small>Mild, cream-free soap and a lint-free towel.<\/small><\/span><\/li>\n<li><svg viewBox=\"0 0 30 30\" fill=\"none\" stroke=\"#4a76b7\" stroke-width=\"2\" stroke-linecap=\"round\" aria-hidden=\"true\"><circle cx=\"15\" cy=\"15\" r=\"11\"><\/circle><circle cx=\"15\" cy=\"15\" r=\"3\"><\/circle><path d=\"M15 4v8M15 18v8M4 15h8M18 15h8\"><\/path><\/svg><span><b>Covered drain<\/b><small>So a dropped lens can\u2019t escape.<\/small><\/span><\/li>\n<li><svg viewBox=\"0 0 30 30\" fill=\"none\" stroke=\"#4a76b7\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M9 27V13a6 6 0 0 1 12 0v14\"><\/path><path d=\"M11.5 14.5v-2a3.5 3.5 0 0 1 7 0v2z\"><\/path><\/svg><span><b>Short nails<\/b><small>Use your finger pads, never your nails.<\/small><\/span><\/li>\n<\/ul><\/div>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-mini\">New to contacts? Our guide to <a href=\"https:\/\/www.visionpros.ca\/pro\/how-to-put-in-and-take-out-contact-lenses\/\">putting in and taking out contact lenses<\/a> covers the basics, including putting them in.<\/p>\n\n\n\n<h2 id=\"pinch\" class=\"wp-block-heading vpa-w\">Soft Lenses: The Pinch Method<\/h2>\n\n\n\n<p class=\"wp-block-paragraph vpa-w\">The classic technique. Slide the lens off the centre of your eye first, then pinch it gently with your finger pads.<\/p>\n\n\n\n<figure class=\"vpa-video\"><div data-vp=\"pinch\"><noscript>The animation needs JavaScript. The quick steps below cover the same technique.<\/noscript><\/div><\/figure>\n<div class=\"vpa-card\"><div class=\"vpa-card-h\">Quick steps<\/div><ol class=\"vpa-ol\">\n<li>Look up. Hold your upper lid open and pull your lower lid down with your middle finger.<\/li>\n<li>Slide the lens down to the white of your eye with your index finger.<\/li>\n<li>Gently pinch it between your thumb and index finger pads.<\/li>\n<li>Lift it out. Rinse and store it in fresh solution, or toss it if it\u2019s a daily.<\/li>\n<\/ol><\/div>\n<div class=\"vpa-note\"><p><b>Tip:<\/b> Start with the same eye every time so your left and right lenses never get mixed up. Lens tearing? You may be pinching too hard: slide it to the white of your eye first, then use a light touch.<\/p><\/div>\n\n\n\n<h2 id=\"slide\" class=\"wp-block-heading vpa-w\">Can You Take Out Contacts With Long Nails?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph vpa-w\">Yes. Use the slide method: instead of pinching the lens where it sits, slide it out to the corner of your eye first.<\/p>\n\n\n\n<figure class=\"vpa-video\"><div data-vp=\"slide\"><noscript>The animation needs JavaScript. The quick steps below cover the same technique.<\/noscript><\/div><\/figure>\n<div class=\"vpa-card\"><div class=\"vpa-card-h\">Quick steps<\/div><ol class=\"vpa-ol\">\n<li>Look toward your nose. Hold your upper lid open and pull your lower lid down.<\/li>\n<li>Keep your index finger flat, with the nail facing away from your eye.<\/li>\n<li>Use the soft pad to slide the lens out to the outer corner.<\/li>\n<li>Pinch it gently there and lift it away.<\/li>\n<\/ol><\/div>\n\n\n\n<h2 id=\"stuck\" class=\"wp-block-heading vpa-w\">Contact Lens Stuck or Feeling Dry?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph vpa-w\">Don\u2019t pull. A dry lens can cling to your eye, and a little moisture usually sets it free.<\/p>\n\n\n\n<figure class=\"vpa-video\"><div data-vp=\"stuck\"><noscript>The animation needs JavaScript. The quick steps below cover the same technique.<\/noscript><\/div><\/figure>\n<div class=\"vpa-card\"><div class=\"vpa-card-h\">Quick steps<\/div><ol class=\"vpa-ol\">\n<li>Wash and dry your hands.<\/li>\n<li>Add a few drops of sterile saline or rewetting drops, then blink several times.<\/li>\n<li>Gently massage your closed upper lid with a finger pad.<\/li>\n<li>Once the lens moves freely, remove it as usual.<\/li>\n<\/ol><\/div>\n<div class=\"vpa-note vpa-warn\"><p><b>Heads up:<\/b> Never use tap water, saliva or tweezers. If the lens still won\u2019t budge, or your eye is red, sore or blurry, stop and call your optometrist.<\/p><\/div>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-mini\">Contacts feel dry every day? See <a href=\"https:\/\/www.visionpros.ca\/pro\/why-do-my-contacts-feel-dry-and-how-to-fix-it\/\">why it happens and how to fix it<\/a>.<\/p>\n\n\n\n<h2 id=\"lost\" class=\"wp-block-heading vpa-w\">Can a Contact Lens Get Lost Behind Your Eye?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph vpa-w\">No. A lens can only travel as far as the fold under your eyelids, so it can\u2019t slip behind your eye. If a soft lens seems to have vanished, it may have folded and tucked under your upper lid. Add sterile saline, blink, and gently massage your closed lid. Still can\u2019t find it? Call your eye doctor.<\/p>\n\n\n\n<h2 id=\"rigid\" class=\"wp-block-heading vpa-w\">Rigid (Gas Permeable) Lenses: The Blink Method<\/h2>\n\n\n\n<p class=\"wp-block-paragraph vpa-w\">Wear rigid gas permeable (RGP) lenses? They come out with a blink instead of a pinch.<\/p>\n\n\n\n<figure class=\"vpa-video\"><div data-vp=\"blink\"><noscript>The animation needs JavaScript. The quick steps below cover the same technique.<\/noscript><\/div><\/figure>\n<div class=\"vpa-card\"><div class=\"vpa-card-h\">Quick steps<\/div><ol class=\"vpa-ol\">\n<li>Lean over a clean towel or soft surface, and cover the sink drain.<\/li>\n<li>Look straight ahead with your eye wide open.<\/li>\n<li>Rest a finger at the outer corner of your eye and pull gently toward your ear.<\/li>\n<li>Blink. The lens should pop out onto the towel.<\/li>\n<\/ol><\/div>\n<div class=\"vpa-note\"><p><b>Good to know:<\/b> A small suction holder can help if a lens won\u2019t budge. Ask your eye doctor to show you how to use one.<\/p><\/div>\n\n\n\n<h2 id=\"after\" class=\"wp-block-heading vpa-w\">After You Take Them Out<\/h2>\n\n\n\n<ul class=\"vpa-list\">\n<li><b>Daily lenses:<\/b> throw them away. Never reuse them.<\/li>\n<li><b>Reusable lenses:<\/b> rub and rinse with fresh solution, then store them in a clean case filled with fresh solution. Never top up old solution. Out of solution? <a href=\"https:\/\/www.visionpros.ca\/pro\/what-can-you-use-if-you-run-out-of-contact-solution\/\">See what\u2019s safe to use<\/a>.<\/li>\n<li><b>Water:<\/b> keep your lenses away from tap water. Showered with them in? <a href=\"https:\/\/www.visionpros.ca\/pro\/accidentally-showered-with-contact-lenses-here-is-what-to-do\/\">Here\u2019s what to do<\/a>.<\/li>\n<li><b>Your case:<\/b> replace it every one to three months.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-mini\">Not sure which schedule suits you? <a href=\"https:\/\/www.visionpros.ca\/pro\/daily-bi-weekly-or-monthly-how-to-choose-your-contact-lenses\/\">Compare daily, bi-weekly and monthly lenses<\/a>.<\/p>\n\n\n\n<h2 id=\"night\" class=\"wp-block-heading vpa-w\">Do You Need to Take Contacts Out Every Night?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph vpa-w\">Usually, yes. Sleeping in lenses raises the risk of eye infections, even with lenses approved for overnight wear. Only sleep in yours if your eye doctor has said it\u2019s right for you.<\/p>\n\n\n\n<h2 id=\"help\" class=\"wp-block-heading vpa-w\">When to Call Your Eye Doctor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph vpa-w\">Book a visit if a lens won\u2019t come out, or if you notice any of these after taking your lenses out:<\/p>\n\n\n\n<ul class=\"vpa-list vpa-alert\">\n<li>Redness that doesn\u2019t settle down<\/li>\n<li>Pain or discomfort<\/li>\n<li>Blurry or fuzzy vision<\/li>\n<li>Sensitivity to light, or discharge<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph vpa-w\">For severe pain or sudden vision loss, go to an emergency room.<\/p>\n\n\n\n<h2 id=\"shop\" class=\"wp-block-heading vpa-w\">Stock Up on Contacts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph vpa-w\">VisionPros is a Canadian company that makes it simple to reorder your lenses. Browse <a href=\"https:\/\/www.visionpros.ca\/contact-lenses\/daily\/\">daily<\/a>, <a href=\"https:\/\/www.visionpros.ca\/contact-lenses\/weekly\/\">weekly<\/a> or <a href=\"https:\/\/www.visionpros.ca\/contact-lenses\/monthly\/\">monthly<\/a> contacts, with free shipping on orders over $99.<\/p>\n\n\n\n<div class=\"vpa-cta\"><a class=\"vpa-btn\" href=\"https:\/\/www.visionpros.ca\/contact-lenses\/daily\/\">Shop Daily Contacts<\/a><a class=\"vpa-btn alt\" href=\"https:\/\/www.visionpros.ca\/contact-lenses\/monthly\/\">Shop Monthly Contacts<\/a><\/div>\n\n\n\n<h3 class=\"wp-block-heading vpa-w\"><strong>References<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-ref\">Canadian Association of Optometrists. Wear and Care for Contact Lenses. opto.ca. Accessed 2026.<\/p>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-ref\">American Optometric Association. Contact Lens Care. aoa.org. Accessed 2026.<\/p>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-ref\">American Academy of Ophthalmology. How Do I Get a Contact Lens Out From the Top of My Eye? aao.org. Accessed 2026.<\/p>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-ref\">Moorfields Eye Hospital. Care of Your Rigid Gas Permeable Contact Lenses. moorfields.nhs.uk. Accessed 2026.<\/p>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-ref\">Centers for Disease Control and Prevention. Corneal Infections Associated With Sleeping in Contact Lenses. MMWR. cdc.gov. 2018.<\/p>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-ref\">All About Vision. How Do You Take Out Contacts With Long Nails? allaboutvision.com. Accessed 2026.<\/p>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-ref\">All About Vision. How To Remove a Contact Lens Stuck in Your Eye or Eyelid. allaboutvision.com. Accessed 2026.<\/p>\n\n\n\n<p class=\"wp-block-paragraph vpa-w vpa-fine\">This guide is for general information only and isn\u2019t medical advice. Always follow the instructions from your eye care professional and your lens manufacturer.<\/p>\n\n\n\n<script>(0,Function)(\"\/* VisionPros.ca \u2013 contact lens removal animations. Usage: add an empty div with data-vp set to pinch, slide, blink or stuck, then load this file with a deferred script tag. *\/\\n(function(){\\n(function (g) {\\n'use strict';\\nconst VP = (g.VP = g.VP || {});\\nconst NS = 'http:\/\/www.w3.org\/2000\/svg';\\nVP.el = function (tag, attrs, parent) {\\nconst e = document.createElementNS(NS, tag);\\nif (attrs) for (const k in attrs) e.setAttribute(k, attrs[k]);\\nif (parent) parent.appendChild(e);\\nreturn e;\\n};\\nVP.set = function (e, attrs) { for (const k in attrs) e.setAttribute(k, attrs[k]); return e; };\\nconst clamp = (x, a, b) => (x \\u003c (a = a === undefined ? 0 : a) ? a : x > (b = b === undefined ? 1 : b) ? b : x);\\nVP.clamp = clamp;\\nVP.lerp = (a, b, t) => a + (b - a) * t;\\nVP.n1 = v => Math.round(v * 10) \/ 10;\\nconst E = (VP.ease = {\\nlin: t => t,\\ni: t => t * t * t,\\no: t => 1 - Math.pow(1 - t, 3),\\nio: t => (t \\u003c 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) \/ 2),\\nsio: t => 0.5 - Math.cos(Math.PI * t) \/ 2,\\nback: t => { const c = 1.7; return 1 + (c + 1) * Math.pow(t - 1, 3) + c * Math.pow(t - 1, 2); },\\nstep: t => (t >= 1 ? 1 : 0),\\nsnap: t => 1 - Math.pow(1 - t, 5),\\n});\\nconst mix = (VP.mix = function (a, b, u) {\\nif (typeof a === 'number') return a + (b - a) * u;\\nif (Array.isArray(a)) return a.map((v, i) => mix(v, b[i], u));\\nif (a \\u0026\\u0026 typeof a === 'object') { const o = {}; for (const k in a) o[k] = mix(a[k], b[k], u); return o; }\\nreturn u \\u003c 1 ? a : b;\\n});\\nVP.track = function (keys, t) {\\nconst n = keys.length;\\nif (t \\u003c= keys[0][0]) return keys[0][1];\\nfor (let i = 1; i \\u003c n; i++) {\\nconst k = keys[i];\\nif (t \\u003c= k[0]) {\\nconst p = keys[i - 1];\\nconst u = (t - p[0]) \/ (k[0] - p[0] || 1);\\nreturn mix(p[1], k[1], (k[2] || E.io)(u));\\n}\\n}\\nreturn keys[n - 1][1];\\n};\\nVP.win = function (t, a, b, c, d) {\\nif (t \\u003c= a || t >= d) return 0;\\nif (t \\u003c b) return E.sio((t - a) \/ (b - a));\\nif (t \\u003c= c) return 1;\\nreturn 1 - E.sio((t - c) \/ (d - c));\\n};\\nVP.hash = function (n) { const s = Math.sin(n * 127.1 + 311.7) * 43758.5453; return s - Math.floor(s); };\\nVP.skins = {\\nlight:  { skin: '#ffd8c2', shade: '#f6b99c', face: '#ffe6d6', lid: '#f9c5aa', blush: '#ffb8b0' },\\nmedium: { skin: '#f0c19c', shade: '#dfa27c', face: '#f7d3b4', lid: '#e6ae88', blush: '#f2a597' },\\ndeep:   { skin: '#d6a27f', shade: '#bf805e', face: '#e2b493', lid: '#cb906c', blush: '#de8f7c' },\\n};\\nVP.C = {\\nink: '#5b4b70', inkSoft: '#9986b3', nail: '#fff0f3', nailLine: '#eaa8b8',\\nbgA: '#fdf4ea', mint: '#d6f1e4', sky: '#d5e8fb', peach: '#ffe3d2', lav: '#e6ddfa', butter: '#fff1c9',\\nsclera: '#fffefd', scleraSh: '#e7eaf6', iris: '#93cfdb', iris2: '#5faec3', pupil: '#3d3352',\\nlens: '#bfe1ff', lensEdge: '#6fb1ee', water: '#bfe4fb', coral: '#ff9c9c', coral2: '#ffc2bc',\\ntext: '#4a3f66', textSoft: '#7b6d99',\\n};\\n})(typeof window !== 'undefined' ? window : globalThis);\\n(function (VP) {\\n'use strict';\\nconst M = Math, PI = M.PI, D = PI \/ 180, sin = M.sin, cos = M.cos, sqrt = M.sqrt;\\nconst mx = a => { const c = cos(a), s = sin(a); return [1, 0, 0, 0, c, -s, 0, s, c]; };\\nconst my = a => { const c = cos(a), s = sin(a); return [c, 0, s, 0, 1, 0, -s, 0, c]; };\\nconst mz = a => { const c = cos(a), s = sin(a); return [c, -s, 0, s, c, 0, 0, 0, 1]; };\\nconst mm = (A, B) => { const r = []; for (let i = 0; i \\u003c 3; i++) for (let j = 0; j \\u003c 3; j++) r.push(A[i * 3] * B[j] + A[i * 3 + 1] * B[3 + j] + A[i * 3 + 2] * B[6 + j]); return r; };\\nconst mv = (A, v) => [A[0] * v[0] + A[1] * v[1] + A[2] * v[2], A[3] * v[0] + A[4] * v[1] + A[5] * v[2], A[6] * v[0] + A[7] * v[1] + A[8] * v[2]];\\nconst add = (a, b) => [a[0] + b[0], a[1] + b[1], a[2] + b[2]];\\nconst f = v => M.round(v * 10) \/ 10;\\nconst P2 = p => f(p[0]) + ' ' + f(p[1]);\\nconst PO = p => f(p.x) + ' ' + f(p.y);\\nlet uid = 0;\\nconst FING = {\\nindex:  { b: [-3.0, 8.9, 0],   L: [4.0, 2.4, 1.9], r: [0.92, 0.85, 0.78, 0.67], fan: -2.5 },\\nmiddle: { b: [-1.0, 9.3, 0],   L: [4.5, 2.7, 2.0], r: [0.94, 0.87, 0.80, 0.69], fan: 0 },\\nring:   { b: [1.0, 8.8, 0],    L: [4.2, 2.6, 1.9], r: [0.88, 0.81, 0.74, 0.63], fan: 2.5 },\\npinky:  { b: [2.9, 7.8, 0],    L: [3.3, 1.9, 1.7], r: [0.78, 0.69, 0.62, 0.53], fan: 6 },\\nthumb:  { b: [-2.0, 2.3, -0.6], L: [4.3, 3.3, 2.4], r: [1.18, 1.02, 0.94, 0.78], fan: 0 },\\n};\\nconst NAMES = ['thumb', 'index', 'middle', 'ring', 'pinky'];\\nconst PALM = [[-1.5, 0.0], [-2.2, 2.6], [-2.55, 5.2], [-2.75, 7.6], [-3.0, 8.8], [-1.0, 9.15], [1.0, 8.65], [2.9, 7.7], [2.75, 5.4], [2.65, 3.0], [1.6, 0.0]];\\nconst PALM_R = 1.15;\\nVP.HAND_REST = {\\npos: [0, 0], rot: [0, 0, 0], scale: 22, spread: 1,\\nindex: [0, 6, 8, 5], middle: [0, 8, 10, 6], ring: [0, 10, 12, 7], pinky: [0, 12, 14, 8],\\nthumb: [-28, 20, -50, 8, 8], layers: {},\\n};\\nfunction fk(base, R0, L, flex) {\\nlet R = R0, p = base; const P = [p], F = [];\\nfor (let i = 0; i \\u003c L.length; i++) {\\nR = mm(R, mx(-flex[i]));\\nF.push(R);\\np = add(p, mv(R, [0, L[i], 0]));\\nP.push(p);\\n}\\nreturn { P, F };\\n}\\nfunction circ(x, y, r) { return 'M' + f(x + r) + ' ' + f(y) + 'A' + f(r) + ' ' + f(r) + ' 0 1 0 ' + f(x - r) + ' ' + f(y) + 'A' + f(r) + ' ' + f(r) + ' 0 1 0 ' + f(x + r) + ' ' + f(y) + 'Z'; }\\nfunction capsule(a, b) {\\nconst dx = b.x - a.x, dy = b.y - a.y, d = sqrt(dx * dx + dy * dy), r1 = a.r, r2 = b.r;\\nif (d \\u003c 0.01 || d \\u003c= M.abs(r1 - r2)) return r1 >= r2 ? circ(a.x, a.y, r1) : circ(b.x, b.y, r2);\\nconst an = M.atan2(dy, dx), be = M.acos((r1 - r2) \/ d), a1 = an + be, a2 = an - be;\\nconst c1 = cos(a1), s1 = sin(a1), c2 = cos(a2), s2 = sin(a2);\\nreturn 'M' + P2([a.x + r1 * c1, a.y + r1 * s1]) + 'L' + P2([b.x + r2 * c1, b.y + r2 * s1]) +\\n'A' + f(r2) + ' ' + f(r2) + ' 0 ' + (2 * be > PI ? 1 : 0) + ' 0 ' + P2([b.x + r2 * c2, b.y + r2 * s2]) +\\n'L' + P2([a.x + r1 * c2, a.y + r1 * s2]) +\\n'A' + f(r1) + ' ' + f(r1) + ' 0 ' + (2 * be \\u003c PI ? 1 : 0) + ' 0 ' + P2([a.x + r1 * c1, a.y + r1 * s1]) + 'Z';\\n}\\nfunction smoothClosed(p) {\\nconst n = p.length; let d = 'M' + P2(p[0]);\\nfor (let i = 0; i \\u003c n; i++) {\\nconst p0 = p[(i - 1 + n) % n], p1 = p[i], p2 = p[(i + 1) % n], p3 = p[(i + 2) % n];\\nd += 'C' + P2([p1[0] + (p2[0] - p0[0]) \/ 6, p1[1] + (p2[1] - p0[1]) \/ 6]) + ' ' + P2([p2[0] - (p3[0] - p1[0]) \/ 6, p2[1] - (p3[1] - p1[1]) \/ 6]) + ' ' + P2(p2);\\n}\\nreturn d + 'Z';\\n}\\nfunction smoothOpen(p) {\\nconst n = p.length; let d = 'M' + P2(p[0]);\\nfor (let i = 0; i \\u003c n - 1; i++) {\\nconst p0 = p[M.max(i - 1, 0)], p1 = p[i], p2 = p[i + 1], p3 = p[M.min(i + 2, n - 1)];\\nd += 'C' + P2([p1[0] + (p2[0] - p0[0]) \/ 6, p1[1] + (p2[1] - p0[1]) \/ 6]) + ' ' + P2([p2[0] - (p3[0] - p1[0]) \/ 6, p2[1] - (p3[1] - p1[1]) \/ 6]) + ' ' + P2(p2);\\n}\\nreturn d;\\n}\\nfunction nearest(poly, x, y) {\\nlet best = null;\\nfor (let i = 0; i \\u003c poly.length - 1; i++) {\\nconst a = poly[i], b = poly[i + 1], dx = b.x - a.x, dy = b.y - a.y, l2 = dx * dx + dy * dy || 1;\\nconst t = M.max(0, M.min(1, ((x - a.x) * dx + (y - a.y) * dy) \/ l2));\\nconst px = a.x + dx * t, py = a.y + dy * t, d = M.hypot(px - x, py - y);\\nif (!best || d \\u003c best.d) best = { x: px, y: py, d, r: a.r + (b.r - a.r) * t };\\n}\\nreturn best;\\n}\\nconst lerpJ = (a, b, t) => ({ x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t, r: a.r + (b.r - a.r) * t, z: (a.z + b.z) \/ 2 });\\nVP.Hand = function (parent, opts) {\\nopts = Object.assign({ mirror: false, skin: VP.skins.light, ow: 3.2, line: 2, nails: true, shade: true, shadow: null }, opts);\\nconst C = VP.C, S = opts.skin, id = 'hm' + ++uid;\\nconst root = VP.el('g', null, parent);\\nconst defs = VP.el('defs', null, root);\\nconst mask = VP.el('mask', { id, maskUnits: 'userSpaceOnUse', x: -3000, y: -3000, width: 8000, height: 8000 }, defs);\\nVP.el('rect', { x: -3000, y: -3000, width: 8000, height: 8000, fill: '#fff' }, mask);\\nconst maskP = VP.el('path', { fill: '#000' }, mask);\\nconst strokeInk = { fill: 'none', stroke: C.ink, 'stroke-linejoin': 'round', 'stroke-linecap': 'round' };\\nconst mkLayer = (masked) => {\\nconst g = VP.el('g', null, root);\\nconst l = {\\ng,\\npalmO: VP.el('path', { fill: C.ink, stroke: C.ink, 'stroke-linejoin': 'round' }, g),\\nwebO: VP.el('path', { fill: C.ink, stroke: C.ink, 'stroke-linejoin': 'round' }, g),\\no: VP.el('path', Object.assign({}, strokeInk, { 'stroke-width': opts.ow * 2 }), g),\\npalmF: VP.el('path', { fill: S.skin, stroke: S.skin, 'stroke-linejoin': 'round' }, g),\\nwebF: VP.el('path', { fill: S.skin, stroke: S.skin, 'stroke-linejoin': 'round' }, g),\\nf: VP.el('path', { fill: S.skin }, g),\\nshade: VP.el('path', Object.assign({}, strokeInk, { stroke: S.shade, 'stroke-width': 3, opacity: 0.55 }), g),\\nsep: VP.el('path', Object.assign({}, strokeInk, { 'stroke-width': opts.line }), g),\\ncr: VP.el('path', Object.assign({}, strokeInk, { stroke: S.shade, 'stroke-width': 1.5 }), g),\\nnails: NAMES.reduce((o, n) => { o[n] = VP.el('path', { fill: C.nail, stroke: C.nailLine, 'stroke-width': 1.4, 'stroke-linejoin': 'round' }, g); return o; }, {}),\\n};\\nif (masked) l.o.setAttribute('mask', 'url(#' + id + ')');\\nreturn l;\\n};\\nlet shg = null, shPalm = null, shWeb = null, shFin = null;\\nif (opts.shadow) {\\nshg = VP.el('g', { opacity: opts.shadow.opacity || 0.16, transform: 'translate(' + (opts.shadow.dx || 5) + ' ' + (opts.shadow.dy || 8) + ')' }, root);\\nshPalm = VP.el('path', { fill: C.ink, stroke: C.ink, 'stroke-linejoin': 'round' }, shg);\\nshWeb = VP.el('path', { fill: C.ink, stroke: C.ink, 'stroke-linejoin': 'round' }, shg);\\nshFin = VP.el('path', { fill: C.ink }, shg);\\n}\\nconst L = { back: mkLayer(), base: mkLayer(), front: mkLayer(true) };\\nconst geo = {};\\nlet cur = null;\\nfunction solve(pose) {\\nconst s = pose.scale, ox = pose.pos[0], oy = pose.pos[1];\\nconst Rh = mm(mm(mz(pose.rot[0] * D), mx(pose.rot[1] * D)), my(pose.rot[2] * D));\\nconst refl = v => (opts.mirror ? [-v[0], v[1], v[2]] : v);\\nconst dir = v => mv(Rh, refl(v));\\nconst proj = p => { const q = dir(p); return { x: ox + s * q[0], y: oy - s * q[1], z: q[2] }; };\\nconst sol = {}, fin = {};\\nfor (const n of NAMES) {\\nconst F = FING[n], a = pose[n];\\nif (n === 'thumb') sol[n] = fk(F.b, mm(mm(mz(-a[0] * D), mx(-a[1] * D)), my(a[2] * D)), F.L, [0, a[3] * D, a[4] * D]);\\nelse sol[n] = fk(F.b, mz(-(F.fan * pose.spread + a[0]) * D), F.L, [a[1] * D, a[2] * D, a[3] * D]);\\nconst J = sol[n].P.map((p, k) => { const q = proj(p); q.r = F.r[k] * s; return q; });\\nconst axes = sol[n].F.map(m => ({ x: dir(mv(m, [1, 0, 0])), y: dir(mv(m, [0, 1, 0])), z: dir(mv(m, [0, 0, 1])) }));\\nfin[n] = { J, axes };\\n}\\nreturn { s, ox, oy, Rh, dir, proj, sol, fin };\\n}\\nfunction update(pose) {\\npose = Object.assign({}, VP.HAND_REST, pose);\\ncur = pose;\\nconst G = solve(pose), { s, ox, oy, Rh, dir, proj, sol, fin } = G;\\nconst palmPts = PALM.map(p => proj([p[0], p[1], 0]));\\nconst layersOf = n => (pose.layers \\u0026\\u0026 pose.layers[n]) || ['base', 'base', 'base'];\\nfor (const n of NAMES) geo[n] = fin[n];\\ngeo.palm = palmPts;\\nfor (const k in L) { const l = L[k]; l._o = ''; l._f = ''; l._sep = ''; l._cr = ''; l._sh = ''; l._np = {}; }\\nlet maskD = '';\\nfor (const n of NAMES) {\\nconst q = fin[n], J = q.J, ly = layersOf(n);\\nfor (let k = 0; k \\u003c 3; k++) {\\nconst c = capsule(J[k], J[k + 1]), l = L[ly[k]];\\nl._o += c; l._f += c;\\nif (ly[k] === 'front' \\u0026\\u0026 k > 0 \\u0026\\u0026 ly[k - 1] !== 'front') maskD += capsule(J[k - 1], J[k]);\\n}\\nconst nl = L[ly[2]];\\nif (opts.nails) {\\nconst A = q.axes[2], vis = A.z[2];\\nif (vis > 0.06) {\\nconst base = dir(sol[n].P[2]);\\nconst Lw = FING[n].L[2], r2 = FING[n].r[2], r3 = FING[n].r[3];\\nconst w = 0.74 * r3, v0 = 0.10 * Lw, v1 = Lw + 0.62 * r3, pts = [];\\nfor (let i = 0; i \\u003c 20; i++) {\\nconst th = i \/ 20 * 2 * PI, cu = cos(th), su = sin(th);\\nconst u = (cu \\u003c 0 ? -1 : 1) * M.pow(M.abs(cu), 0.62) * w;\\nconst vv = (v0 + v1) \/ 2 + (su \\u003c 0 ? -1 : 1) * M.pow(M.abs(su), 0.62) * (v1 - v0) \/ 2 * (su > 0 ? 1 : 0.94);\\nlet sr = r2 + (r3 - r2) * M.min(vv \/ Lw, 1);\\nif (vv > Lw) sr = sqrt(M.max(r3 * r3 - (vv - Lw) * (vv - Lw), 0.01));\\nconst dome = sqrt(M.max(1 - (u \/ sr) * (u \/ sr), 0.04));\\npts.push([ox + s * (base[0] + A.x[0] * u + A.y[0] * vv + A.z[0] * sr * dome), oy - s * (base[1] + A.x[1] * u + A.y[1] * vv + A.z[1] * sr * dome)]);\\n}\\nnl._np[n] = { d: smoothClosed(pts), o: M.min(1, (vis - 0.06) \/ 0.3) };\\n}\\n}\\nif (n !== 'thumb' \\u0026\\u0026 pose[n][1] \\u003c 50) {\\nfor (let k = 1; k \\u003c= 2; k++) {\\nconst A = q.axes[k === 1 ? 1 : 2], vis = A.z[2];\\nif (vis > 0.25) {\\nconst base = dir(sol[n].P[k]), r = FING[n].r[k];\\nconst line = (off, wd) => smoothOpen([-1, 0, 1].map(i => {\\nconst u = i * wd * r, v = off * r + (1 - i * i) * 0.10 * r, w = r * sqrt(M.max(1 - (u \/ r) * (u \/ r), 0.1));\\nreturn [ox + s * (base[0] + A.x[0] * u + A.y[0] * v + A.z[0] * w), oy - s * (base[1] + A.x[1] * u + A.y[1] * v + A.z[1] * w)];\\n}));\\nnl._cr += k === 1 ? line(-0.22, 0.42) + line(0.12, 0.34) : line(0, 0.34);\\n}\\n}\\n}\\nif (opts.shade \\u0026\\u0026 (n === 'thumb' || pose[n][1] \\u003c 50)) {\\nconst pts = [];\\nfor (let k = 0; k \\u003c 4; k++) {\\nconst a = J[M.max(k - 1, 0)], b = J[M.min(k + 1, 3)];\\nlet tx = b.x - a.x, ty = b.y - a.y; const tl = M.hypot(tx, ty) || 1; tx \/= tl; ty \/= tl;\\nlet nx = -ty, ny = tx; if (nx + ny \\u003c 0) { nx = -nx; ny = -ny; }\\nconst off = J[k].r * 0.55;\\npts.push([J[k].x + nx * off, J[k].y + ny * off]);\\n}\\nconst tip = pts[3]; pts[3] = [pts[2][0] + (tip[0] - pts[2][0]) * 0.55, pts[2][1] + (tip[1] - pts[2][1]) * 0.55];\\nnl._sh += smoothOpen(pts.slice(0, 4));\\n}\\n}\\nconst order = ['index', 'middle', 'ring', 'pinky'];\\nfor (let i = 0; i \\u003c 3; i++) {\\nconst A = fin[order[i]], B = fin[order[i + 1]];\\nconst a = lerpJ(A.J[0], A.J[1], 0.3), b = lerpJ(B.J[0], B.J[1], 0.3);\\na.r = b.r = M.min(a.r, b.r) * 0.72;\\nconst c = capsule(a, b);\\nL.base._o += c; L.base._f += c;\\n}\\nfor (let i = 0; i \\u003c 3; i++) {\\nconst A = fin[order[i]], B = fin[order[i + 1]];\\nif (pose[order[i]][1] > 50 || pose[order[i + 1]][1] > 50) continue;\\nconst shorter = A.J[3].y \\u003c B.J[3].y ? B : A, longer = shorter === A ? B : A;\\nconst cl = shorter.J, samples = [lerpJ(cl[0], cl[1], 0.36)];\\nfor (let k = 1; k \\u003c 4; k++) for (let j = 1; j \\u003c= 3; j++) { if (k === 1 \\u0026\\u0026 j \/ 3 \\u003c 0.4) continue; samples.push(lerpJ(cl[k - 1], cl[k], j \/ 3)); }\\nconst pts = [];\\nfor (const sp of samples) {\\nconst nn = nearest(longer.J, sp.x, sp.y);\\nif (nn.d > (sp.r + nn.r) * 1.12) break;\\nconst t = sp.r \/ (sp.r + nn.r);\\npts.push([sp.x + (nn.x - sp.x) * t, sp.y + (nn.y - sp.y) * t]);\\n}\\nif (pts.length > 1) L.base._sep += smoothOpen(pts);\\n}\\n{\\nconst t = fin.thumb.J, ix = fin.index.J, wr = 0.62 * s;\\nconst wp = [t[0], t[1], lerpJ(t[1], t[2], 0.3), lerpJ(ix[0], ix[1], 0.45), ix[0], palmPts[3]];\\nconst wd = 'M' + wp.map(PO).join('L') + 'Z';\\nVP.set(L.base.webO, { d: wd, 'stroke-width': wr * 2 + opts.ow * 2 });\\nVP.set(L.base.webF, { d: wd, 'stroke-width': wr * 2 });\\n}\\nconst pd = smoothClosed(palmPts.map(p => [p.x, p.y])), pw = PALM_R * s * 2;\\nVP.set(L.base.palmO, { d: pd, 'stroke-width': pw + opts.ow * 2 });\\nVP.set(L.base.palmF, { d: pd, 'stroke-width': pw });\\nVP.set(maskP, { d: maskD });\\nif (shg) {\\nVP.set(shPalm, { d: pd, 'stroke-width': pw });\\nVP.set(shWeb, { d: L.base.webF.getAttribute('d') || '', 'stroke-width': L.base.webF.getAttribute('stroke-width') });\\nVP.set(shFin, { d: L.back._f + L.base._f + L.front._f });\\n}\\nfor (const k in L) {\\nconst l = L[k];\\nVP.set(l.o, { d: l._o }); VP.set(l.f, { d: l._f });\\nVP.set(l.sep, { d: l._sep }); VP.set(l.cr, { d: l._cr }); VP.set(l.shade, { d: l._sh });\\nfor (const n of NAMES) {\\nconst np = l._np[n];\\nif (np) { VP.set(l.nails[n], { d: np.d, opacity: f(np.o) }); l.nails[n].removeAttribute('display'); } else l.nails[n].setAttribute('display', 'none');\\n}\\nif (k !== 'base') { l.palmO.setAttribute('d', ''); l.palmF.setAttribute('d', ''); l.webO.setAttribute('d', ''); l.webF.setAttribute('d', ''); }\\n}\\n}\\nconst padPx = (G, name, scale) => {\\nif (name === 'mid') { const a = padPx(G, 'thumb', scale), b = padPx(G, 'index', scale); return { x: (a.x + b.x) \/ 2, y: (a.y + b.y) \/ 2, tip: a.tip }; }\\nconst q = G.fin[name], j = q.J[3], a = q.axes[2], r = FING[name].r[3] * scale;\\nreturn { x: j.x - a.z[0] * r * 0.85, y: j.y + a.z[1] * r * 0.85, tip: j };\\n};\\nfunction padAt(pose, name) { pose = Object.assign({}, VP.HAND_REST, pose); return padPx(solve(pose), name, pose.scale); }\\nfunction anchor(pose, name, x, y) { const p0 = padAt(Object.assign({}, pose, { pos: [0, 0] }), name); return [x - p0.x, y - p0.y]; }\\nconst cp = p => { const o = Object.assign({}, VP.HAND_REST, p); for (const k in o) if (Array.isArray(o[k])) o[k] = o[k].slice(); return o; };\\nfunction ik(pose0, targets, free, iters) {\\nconst pose = cp(pose0), nF = free.length;\\nconst arr = fp => (fp.k === 'pos' ? pose.pos : pose[fp.k]);\\nconst resid = () => { const G = solve(pose), out = []; for (const t of targets) { const p = padPx(G, t.n, pose.scale); out.push((p.x - t.x) * t.w, (p.y - t.y) * t.w); } return out; };\\nfor (let it = 0; it \\u003c (iters || 4); it++) {\\nconst r0 = resid(), m = r0.length;\\nconst Jc = free.map(fp => { const a = arr(fp), old = a[fp.i]; a[fp.i] = old + fp.e; const r1 = resid(); a[fp.i] = old; return r1.map((v, i) => (v - r0[i]) \/ fp.e); });\\nconst A = [], b = [];\\nfor (let i = 0; i \\u003c nF; i++) {\\nA.push(new Array(nF).fill(0));\\nfor (let j = 0; j \\u003c nF; j++) { let v = 0; for (let k = 0; k \\u003c m; k++) v += Jc[i][k] * Jc[j][k]; A[i][j] = v; }\\nA[i][i] += free[i].w; let v = 0; for (let k = 0; k \\u003c m; k++) v -= Jc[i][k] * r0[k]; b.push(v);\\n}\\nfor (let c = 0; c \\u003c nF; c++) {\\nlet p = c; for (let r = c + 1; r \\u003c nF; r++) if (M.abs(A[r][c]) > M.abs(A[p][c])) p = r;\\n[A[c], A[p]] = [A[p], A[c]]; [b[c], b[p]] = [b[p], b[c]];\\nconst d = A[c][c] || 1e-9;\\nfor (let r = c + 1; r \\u003c nF; r++) { const k = A[r][c] \/ d; for (let j = c; j \\u003c nF; j++) A[r][j] -= k * A[c][j]; b[r] -= k * b[c]; }\\n}\\nconst dx = new Array(nF).fill(0);\\nfor (let r = nF - 1; r >= 0; r--) { let v = b[r]; for (let j = r + 1; j \\u003c nF; j++) v -= A[r][j] * dx[j]; dx[r] = v \/ (A[r][r] || 1e-9); }\\nfree.forEach((fp, i) => { const a = arr(fp); let v = a[fp.i] + dx[i]; if (fp.lo !== undefined) v = M.max(fp.lo, v); if (fp.hi !== undefined) v = M.min(fp.hi, v); a[fp.i] = v; });\\n}\\nreturn pose;\\n}\\nreturn { g: root, update, geo, padAt, anchor, ik, opts };\\n};\\nVP.handKit = { FING, PALM, fk, mx, my, mz, mm, mv, capsule, circ, smoothOpen, smoothClosed };\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst M = Math, C = VP.C, f = v => M.round(v * 10) \/ 10;\\nconst bez = (a, b, c, d, t) => { const u = 1 - t; return [u * u * u * a[0] + 3 * u * u * t * b[0] + 3 * u * t * t * c[0] + t * t * t * d[0], u * u * u * a[1] + 3 * u * u * t * b[1] + 3 * u * t * t * c[1] + t * t * t * d[1]]; };\\nconst dbez = (a, b, c, d, t) => { const u = 1 - t; return [3 * u * u * (b[0] - a[0]) + 6 * u * t * (c[0] - b[0]) + 3 * t * t * (d[0] - c[0]), 3 * u * u * (b[1] - a[1]) + 6 * u * t * (c[1] - b[1]) + 3 * t * t * (d[1] - c[1])]; };\\nconst P = p => f(p[0]) + ',' + f(p[1]);\\nlet uid = 0;\\nconst HALF = 125, R_IRIS = 52, R_PUPIL = 20, R_LENS = 63;\\nVP.EYE = { HALF, R_IRIS, R_LENS };\\nVP.EYE_REST = { open: 1, low: 0, up: 0, gx: 0, gy: 0, pullOut: 0, brow: 0, lx: 0, ly: 0, ls: 1, fold: 0, lrot: 0, lift: 0, la: 1, glow: 0, squeeze: 0, rigid: 0, red: 0 };\\nfunction geom(st) {\\nconst open = M.max(0, st.open), k = M.min(open, 1);\\nconst follow = M.max(0, -st.gy) * 0.22;\\nconst I = [-HALF, 10], O = [HALF + st.pullOut, -6 - st.pullOut * 0.06];\\nconst closedY = 24;\\nconst Uy = closedY + (-50 - follow - st.up - closedY) * open;\\nconst Dy0 = 40 + st.low, Dy = closedY + 5 + (Dy0 - closedY - 5) * M.min(1, 0.15 + k * 0.85);\\nconst sq = st.squeeze;\\nconst U = [-16, Uy + sq * 6], D = [14, Dy - sq * 4];\\nconst hy = 34 * k, ly = 24 * k;\\nconst c = {\\nI, O, U, D,\\nu1: [I[0] + 34, I[1] - hy], u2: [U[0] - 74, U[1]], u3: [U[0] + 84, U[1]], u4: [O[0] - 52, O[1] - 24 * k],\\nl1: [O[0] - 42, O[1] + ly], l2: [D[0] + 64, D[1]], l3: [D[0] - 70, D[1]], l4: [I[0] + 30, I[1] + 22 * k],\\n};\\nc.upper1 = 'M' + P(I) + 'C' + P(c.u1) + ' ' + P(c.u2) + ' ' + P(U);\\nc.upper2 = 'C' + P(c.u3) + ' ' + P(c.u4) + ' ' + P(O);\\nc.lower1 = 'C' + P(c.l1) + ' ' + P(c.l2) + ' ' + P(D);\\nc.lower2 = 'C' + P(c.l3) + ' ' + P(c.l4) + ' ' + P(I) + 'Z';\\nc.open = c.upper1 + c.upper2 + c.lower1 + c.lower2;\\nc.lash = c.upper1 + c.upper2;\\nc.lowerEdge = 'M' + P(O) + c.lower1.replace(\/^C\/, 'C') + c.lower2.replace('Z', '');\\nreturn c;\\n}\\nfunction upperPts(g, n, u0, u1) {\\nconst segs = [[g.I, g.u1, g.u2, g.U], [g.U, g.u3, g.u4, g.O]], out = [];\\nfor (let i = 0; i \\u003c n; i++) {\\nconst u = u0 + (u1 - u0) * i \/ (n - 1), si = u \\u003c 0.5 ? 0 : 1, t = si === 0 ? u * 2 : (u - 0.5) * 2, s = segs[si];\\nconst p = bez(s[0], s[1], s[2], s[3], t), tg = dbez(s[0], s[1], s[2], s[3], t), tl = M.hypot(tg[0], tg[1]) || 1;\\nout.push({ u, p, nx: tg[1] \/ tl, ny: -tg[0] \/ tl, tx: tg[0] \/ tl, ty: tg[1] \/ tl });\\n}\\nreturn out;\\n}\\nconst smooth = pts => { let d = 'M' + P(pts[0]); for (let i = 0; i \\u003c pts.length - 1; i++) { const a = pts[M.max(i - 1, 0)], b = pts[i], c = pts[i + 1], e = pts[M.min(i + 2, pts.length - 1)]; d += 'C' + P([b[0] + (c[0] - a[0]) \/ 6, b[1] + (c[1] - a[1]) \/ 6]) + ' ' + P([c[0] - (e[0] - b[0]) \/ 6, c[1] - (e[1] - b[1]) \/ 6]) + ' ' + P(c); } return d; };\\nVP.Eye = function (parent, opts) {\\nopts = Object.assign({ skin: VP.skins.light, cx: 0, cy: 0, iris: null }, opts);\\nconst S = opts.skin, id = 'eye' + ++uid, irisA = (opts.iris \\u0026\\u0026 opts.iris[0]) || C.iris, irisB = (opts.iris \\u0026\\u0026 opts.iris[1]) || C.iris2;\\nconst root = VP.el('g', { transform: 'translate(' + opts.cx + ' ' + opts.cy + ')' }, parent);\\nconst defs = VP.el('defs', null, root);\\nconst clip = VP.el('clipPath', { id: id + 'c' }, defs), clipP = VP.el('path', null, clip);\\nconst grad = VP.el('radialGradient', { id: id + 'g', cx: 0.5, cy: 0.5, r: 0.62 }, defs);\\nVP.el('stop', { offset: 0.5, 'stop-color': '#fff', 'stop-opacity': 0 }, grad);\\nVP.el('stop', { offset: 1, 'stop-color': C.scleraSh, 'stop-opacity': 1 }, grad);\\nconst rg = VP.el('radialGradient', { id: id + 'i', cx: 0.5, cy: 0.5, r: 0.5 }, defs);\\nVP.el('stop', { offset: 0.35, 'stop-color': irisB }, rg);\\nVP.el('stop', { offset: 0.8, 'stop-color': irisA }, rg);\\nVP.el('stop', { offset: 1, 'stop-color': irisB }, rg);\\nconst face = VP.el('g', null, root);\\nconst nose = VP.el('path', { fill: S.shade, opacity: 0.32 }, face);\\nconst noseLine = VP.el('path', { fill: 'none', stroke: S.shade, 'stroke-width': 4, 'stroke-linecap': 'round' }, face);\\nconst blush = VP.el('ellipse', { rx: 44, ry: 26, fill: S.blush, opacity: 0.35 }, face);\\nconst fold = VP.el('path', { fill: 'none', stroke: S.shade, 'stroke-width': 3.5, 'stroke-linecap': 'round', opacity: 0.85 }, face);\\nconst crease = VP.el('path', { fill: 'none', stroke: S.shade, 'stroke-width': 4, 'stroke-linecap': 'round' }, face);\\nconst lidTint = VP.el('path', { fill: S.lid, opacity: 0.55 }, face);\\nconst brow = VP.el('path', { fill: 'none', stroke: '#8a7597', 'stroke-width': 15, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, face);\\nconst browHi = VP.el('path', { fill: 'none', stroke: '#a290ae', 'stroke-width': 5, 'stroke-linecap': 'round', opacity: 0.7 }, face);\\nconst crow = VP.el('path', { fill: 'none', stroke: S.shade, 'stroke-width': 3, 'stroke-linecap': 'round', opacity: 0 }, face);\\nconst ball = VP.el('g', { 'clip-path': 'url(#' + id + 'c)' }, root);\\nconst sclera = VP.el('path', { fill: C.sclera }, ball);\\nconst redTint = VP.el('path', { fill: '#ff9d9d', opacity: 0 }, ball);\\nconst veins = VP.el('path', { fill: 'none', stroke: '#ff8585', 'stroke-width': 2.2, 'stroke-linecap': 'round', opacity: 0, d: 'M-120 12C-104 2 -88 -6 -70 -8M-114 22C-96 24 -80 18 -66 18M-100 -4C-88 -12 -76 -20 -64 -22M121 -4C104 0 90 -8 72 -12M114 10C98 14 86 8 74 6M108 -16C96 -10 84 -18 70 -24M-46 46C-32 40 -24 34 -18 30M52 44C40 40 32 34 26 30' }, ball);\\nconst scleraSh = VP.el('rect', { x: -170, y: -90, width: 340, height: 180, fill: 'url(#' + id + 'g)' }, ball);\\nconst glow = VP.el('path', { fill: 'none', stroke: '#9fe6c6', 'stroke-width': 0, opacity: 0, 'stroke-linecap': 'round' }, ball);\\nconst caruncle = VP.el('ellipse', { rx: 17, ry: 12, fill: '#f6a9a8' }, ball);\\nconst caruncleHi = VP.el('ellipse', { rx: 6, ry: 3.5, fill: '#ffd2cd' }, ball);\\nconst iris = VP.el('g', null, ball);\\nVP.el('circle', { r: R_IRIS, fill: 'url(#' + id + 'i)' }, iris);\\nlet rays = ''; for (let i = 0; i \\u003c 18; i++) { const a = i \/ 18 * M.PI * 2 + (i % 3) * 0.05, r0 = R_PUPIL + 4, r1 = R_IRIS - 5 - (i % 2) * 6; rays += 'M' + f(M.cos(a) * r0) + ' ' + f(M.sin(a) * r0) + 'L' + f(M.cos(a) * r1) + ' ' + f(M.sin(a) * r1); }\\nVP.el('path', { d: rays, stroke: '#fff', 'stroke-width': 1.8, opacity: 0.38, 'stroke-linecap': 'round' }, iris);\\nVP.el('circle', { r: R_IRIS - 1, fill: 'none', stroke: '#3f8299', 'stroke-width': 4.5, opacity: 0.85 }, iris);\\nVP.el('circle', { r: R_PUPIL, fill: C.pupil }, iris);\\nVP.el('circle', { cx: -15, cy: -17, r: 9, fill: '#fff' }, iris);\\nVP.el('circle', { cx: 11, cy: 10, r: 4.2, fill: '#fff', opacity: 0.9 }, iris);\\nconst shadeA = VP.el('path', { fill: 'none', stroke: C.ink, 'stroke-width': 30, opacity: 0.09 }, ball);\\nconst shadeB = VP.el('path', { fill: 'none', stroke: C.ink, 'stroke-width': 14, opacity: 0.10 }, ball);\\nconst lensOn = VP.el('g', null, ball);\\nconst mkLens = (g) => {\\nconst body = VP.el('circle', { r: R_LENS, fill: C.lens, opacity: 0.32 }, g);\\nconst rim = VP.el('circle', { r: R_LENS, fill: 'none', stroke: C.lensEdge, 'stroke-width': 2.6, opacity: 0.95 }, g);\\nconst rim2 = VP.el('circle', { r: R_LENS - 6, fill: 'none', stroke: '#fff', 'stroke-width': 2, opacity: 0.55 }, g);\\nconst hi = VP.el('path', { d: 'M-46 -30A56 56 0 0 1 -14 -54', fill: 'none', stroke: '#fff', 'stroke-width': 5, 'stroke-linecap': 'round', opacity: 0.95 }, g);\\nconst hi2 = VP.el('path', { d: 'M38 34A50 50 0 0 1 20 50', fill: 'none', stroke: '#fff', 'stroke-width': 3.5, 'stroke-linecap': 'round', opacity: 0.8 }, g);\\nconst ridge = VP.el('path', { d: 'M0 -' + R_LENS + 'L0 ' + R_LENS, fill: 'none', stroke: C.lensEdge, 'stroke-width': 3.4, 'stroke-linecap': 'round', opacity: 0 }, g);\\nreturn { body, rim, rim2, hi, hi2, ridge };\\n};\\nconst lo = mkLens(lensOn);\\nconst lashLine = VP.el('path', { fill: 'none', stroke: C.ink, 'stroke-width': 6.5, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, root);\\nconst lashes = VP.el('path', { fill: 'none', stroke: C.ink, 'stroke-width': 3.6, 'stroke-linecap': 'round' }, root);\\nconst lowerWater = VP.el('path', { fill: 'none', stroke: '#f4b0ac', 'stroke-width': 6, 'stroke-linecap': 'round', opacity: 0.9 }, root);\\nconst lowerLine = VP.el('path', { fill: 'none', stroke: C.ink, 'stroke-width': 3.2, 'stroke-linecap': 'round' }, root);\\nconst lowerLashes = VP.el('path', { fill: 'none', stroke: C.inkSoft, 'stroke-width': 2.4, 'stroke-linecap': 'round' }, root);\\nconst lensFree = VP.el('g', null, root);\\nconst lf = mkLens(lensFree);\\nconst shadow = VP.el('ellipse', { rx: 26, ry: 6, fill: C.ink, opacity: 0 }, root);\\nroot.insertBefore(shadow, lensFree);\\nfunction lensTransform(st, cx, cy) {\\nconst sx = 1 - 0.68 * st.fold, sy = 1 + 0.10 * st.fold;\\nconst s = st.ls;\\nreturn 'translate(' + f(cx) + ' ' + f(cy) + ') rotate(' + f(st.lrot) + ') scale(' + f(sx * s * 1000) \/ 1000 + ' ' + f(sy * s * 1000) \/ 1000 + ')';\\n}\\nlet last = null;\\nfunction update(st) {\\nst = Object.assign({}, VP.EYE_REST, st);\\nconst g = geom(st); last = { st, g };\\nconst gx = st.gx + (st.tt ? 1.5 * M.sin(st.tt * 0.9) : 0), gy = st.gy + (st.tt ? 1.1 * M.cos(st.tt * 1.3) : 0);\\nconst lowShift = st.low * 0.55;\\nVP.set(nose, { d: 'M-150 -70C-178 -20 -190 40 -175 110L-230 110L-230 -120Z' });\\nVP.set(noseLine, { d: 'M-146 -66C-150 -30 -152 -6 -140 8' });\\nVP.set(blush, { cx: 96, cy: 86 + lowShift });\\nVP.set(fold, { d: 'M-96 ' + f(70 + lowShift) + 'Q-6 ' + f(96 + lowShift * 1.2) + ' 96 ' + f(64 + lowShift) });\\nconst cp = upperPts(g, 16, 0.10, 1.0).map(o => { const off = 9 + (26 + st.up * 0.3) * M.pow(M.sin(M.PI * (0.05 + o.u * 0.95)), 0.85) * M.min(1, st.open + 0.25); return [o.p[0] + o.nx * off + o.tx * 4, o.p[1] + o.ny * off + o.ty * 4]; });\\nconst ep = upperPts(g, 16, 0.10, 1.0).map(o => o.p);\\nVP.set(crease, { d: smooth(cp) });\\nVP.set(lidTint, { d: smooth(cp) + 'L' + ep.slice().reverse().map(P).join('L') + 'Z' });\\nconst bo = -st.brow + (st.up > 0 ? -st.up * 0.5 : 0);\\nVP.set(brow, { d: 'M-128 ' + f(-96 + bo * 0.7) + 'C-70 ' + f(-136 + bo) + ' 20 ' + f(-148 + bo) + ' 68 ' + f(-140 + bo) + 'S128 ' + f(-118 + bo * 0.8) + ' 156 ' + f(-104 + bo * 0.7) });\\nVP.set(browHi, { d: 'M-90 ' + f(-114 + bo * 0.8) + 'C-40 ' + f(-138 + bo) + ' 20 ' + f(-146 + bo) + ' 60 ' + f(-139 + bo) });\\nconst cr = st.pullOut \/ 40;\\nVP.set(crow, { opacity: f(M.min(1, M.max(0, cr))), d: 'M' + f(g.O[0] + 8) + ' ' + f(g.O[1] - 4) + 'L' + f(g.O[0] + 44) + ' ' + f(g.O[1] - 22) + 'M' + f(g.O[0] + 10) + ' ' + f(g.O[1] + 8) + 'L' + f(g.O[0] + 52) + ' ' + f(g.O[1] + 6) + 'M' + f(g.O[0] + 6) + ' ' + f(g.O[1] + 18) + 'L' + f(g.O[0] + 42) + ' ' + f(g.O[1] + 34) });\\nVP.set(clipP, { d: g.open });\\nVP.set(sclera, { d: g.open });\\nVP.set(redTint, { d: g.open, opacity: f(st.red * 0.34) }); veins.setAttribute('opacity', f(M.min(1, st.red * 1.1)));\\nVP.set(caruncle, { cx: g.I[0] + 15, cy: g.I[1] + 3 });\\nVP.set(caruncleHi, { cx: g.I[0] + 14, cy: g.I[1] - 2 });\\nVP.set(iris, { transform: 'translate(' + f(gx) + ' ' + f(gy) + ')' });\\nVP.set(shadeA, { d: g.lash, transform: 'translate(0 -6)' });\\nVP.set(shadeB, { d: g.lash, transform: 'translate(0 -1)' });\\nif (st.glow > 0.01) {\\nconst by = g.D[1] - 26;\\nVP.set(glow, { d: 'M-70 ' + f(by) + 'Q10 ' + f(by + 22) + ' 84 ' + f(by - 2), 'stroke-width': f(30 * st.glow + 8), opacity: f(0.55 * st.glow) });\\n} else glow.setAttribute('opacity', 0);\\nconst lx = gx + st.lx, ly = gy + st.ly, onEye = st.lift \\u003c 0.02;\\nconst rigid = st.rigid;\\nconst rs = rigid ? 0.72 : 1;\\nconst T = lensTransform(Object.assign({}, st, { ls: st.ls * rs }), lx, ly);\\nlensOn.setAttribute('display', onEye \\u0026\\u0026 st.la > 0.01 ? 'inline' : 'none');\\nlensOn.setAttribute('opacity', f(st.la));\\nlensOn.setAttribute('transform', T);\\nfor (const L of [lo, lf]) {\\nL.ridge.setAttribute('opacity', f(st.fold * 0.9));\\nL.body.setAttribute('opacity', rigid ? 0.5 : 0.32);\\nL.rim.setAttribute('stroke-width', rigid ? 4.6 : 2.6); L.rim.setAttribute('stroke', rigid ? '#4f9be0' : C.lensEdge); L.rim2.setAttribute('opacity', rigid ? 0.9 : 0.55);\\n}\\nlensFree.setAttribute('display', !onEye \\u0026\\u0026 st.la > 0.01 ? 'inline' : 'none');\\nlensFree.setAttribute('opacity', f(st.la));\\nlensFree.setAttribute('transform', lensTransform(Object.assign({}, st, { ls: st.ls * rs }), st.fx === undefined ? lx : st.fx, st.fy === undefined ? ly : st.fy));\\nshadow.setAttribute('opacity', f(M.min(0.16, st.lift * 0.16)));\\nshadow.setAttribute('cx', (st.fx === undefined ? lx : st.fx) + 6); shadow.setAttribute('cy', (st.fy === undefined ? ly : st.fy) + 30 * st.ls + 12);\\nVP.set(lashLine, { d: g.lash });\\nVP.set(lowerLine, { d: g.lowerEdge });\\nVP.set(lowerWater, { d: g.lowerEdge, transform: 'translate(0 -3)' });\\nconst segs = [[g.I, g.u1, g.u2, g.U], [g.U, g.u3, g.u4, g.O]];\\nlet d = '';\\nconst n = 11;\\nfor (let i = 0; i \\u003c n; i++) {\\nconst u = 0.04 + i \/ (n - 1) * 0.94, si = u \\u003c 0.5 ? 0 : 1, t = si === 0 ? u * 2 : (u - 0.5) * 2, s = segs[si];\\nconst p = bez(s[0], s[1], s[2], s[3], t), tg = dbez(s[0], s[1], s[2], s[3], t), tl = M.hypot(tg[0], tg[1]) || 1;\\nconst shut = M.max(0, M.min(1, 1 - st.open \/ 0.3)), flip = 1 - 2 * shut;\\nconst nx = tg[1] \/ tl * flip, ny = -tg[0] \/ tl * flip;\\nconst tx = tg[0] \/ tl, ty = tg[1] \/ tl;\\nconst len = (10 + 16 * M.sin(u * M.PI * 0.95) * (0.55 + 0.6 * u)) * (1 - 0.3 * shut);\\nconst sweep = 0.25 + 0.6 * u;\\nconst tip = [p[0] + nx * len + tx * len * sweep, p[1] + ny * len + ty * len * sweep];\\nconst ctl = [p[0] + nx * len * 0.55, p[1] + ny * len * 0.55 + 0];\\nd += 'M' + P(p) + 'Q' + P(ctl) + ' ' + P(tip);\\n}\\nVP.set(lashes, { d });\\nconst ls = [[g.O, g.l1, g.l2, g.D], [g.D, g.l3, g.l4, g.I]];\\nlet dl = '';\\nfor (let i = 0; i \\u003c 6; i++) {\\nconst u = 0.12 + i \/ 5 * 0.6, si = u \\u003c 0.5 ? 0 : 1, t = si === 0 ? u * 2 : (u - 0.5) * 2, s = ls[si];\\nconst p = bez(s[0], s[1], s[2], s[3], t), tg = dbez(s[0], s[1], s[2], s[3], t), tl = M.hypot(tg[0], tg[1]) || 1;\\nconst nx = -tg[1] \/ tl, ny = tg[0] \/ tl, l = 7 + (i % 2) * 3;\\ndl += 'M' + P(p) + 'L' + P([p[0] + nx * l * (ny > 0 ? 1 : -1) * 0.2 + 3, p[1] + M.abs(ny) * l + 3]);\\n}\\nVP.set(lowerLashes, { d: dl, opacity: f(M.min(1, st.open * 1.4)) });\\n}\\nconst toScene = (x, y) => [opts.cx + x, opts.cy + y];\\nreturn {\\ng: root, update, toScene, face, opts,\\nstate: () => last \\u0026\\u0026 last.st, geom: () => last \\u0026\\u0026 last.g,\\nlensCentre: () => { const st = last.st; return toScene(st.gx + st.lx, st.gy + st.ly); },\\n};\\n};\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst FREE = [\\n{ k: 'pos', i: 0, e: 0.6, w: 0.05 }, { k: 'pos', i: 1, e: 0.6, w: 0.05 },\\n{ k: 'index', i: 0, e: 0.5, w: 7, lo: -12, hi: 12 }, { k: 'index', i: 1, e: 0.5, w: 4, lo: 0, hi: 75 }, { k: 'index', i: 2, e: 0.5, w: 4, lo: 0, hi: 80 },\\n{ k: 'middle', i: 1, e: 0.5, w: 6, lo: 0, hi: 85 }, { k: 'middle', i: 2, e: 0.5, w: 6, lo: 0, hi: 90 },\\n{ k: 'thumb', i: 3, e: 0.5, w: 4, lo: 0, hi: 50 }, { k: 'thumb', i: 4, e: 0.5, w: 4, lo: 0, hi: 55 },\\n];\\nVP._seed = VP._seed || 0;\\nVP.FREE_POS = [{ k: 'pos', i: 0, e: 0.6, w: 0.05 }, { k: 'pos', i: 1, e: 0.6, w: 0.05 }];\\nVP.HandActor = function (parent, handOpts, cfg) {\\nconst hand = VP.Hand(parent, handOpts), M = Math, ph = cfg.seed || (VP.hash(++VP._seed) * 6.28), sway = cfg.sway === undefined ? 1.1 : cfg.sway;\\nlet padsNow = {};\\nfunction update(t, alpha) {\\nconst pose = VP.track(cfg.pose, t), targets = [];\\nfor (const n in (cfg.tg || {})) {\\nconst v = VP.track(cfg.tg[n], t);\\nif (v.w > 0.02) targets.push({ n, x: v.x + sway * M.sin(t * 1.9 + ph), y: v.y + sway * M.sin(t * 2.6 + ph * 1.7), w: v.w });\\n}\\nlet fin = pose;\\nif (targets.length) {\\nconst free = (typeof cfg.free === 'function' ? cfg.free(t) : cfg.free) || FREE;\\nfin = hand.ik(Object.assign({}, pose, { pos: cfg.pos ? VP.track(cfg.pos, t).slice() : [0, 0] }), targets, free, 4);\\n} else if (cfg.pos) fin = Object.assign({}, pose, { pos: VP.track(cfg.pos, t) });\\nhand.update(fin);\\npadsNow = {};\\nfor (const n of ['thumb', 'index', 'middle', 'mid']) padsNow[n] = hand.padAt(fin, n);\\nhand.g.setAttribute('opacity', alpha === undefined ? 1 : alpha);\\nhand.g.setAttribute('display', alpha === 0 ? 'none' : 'inline');\\nreturn fin;\\n}\\nreturn { hand, update, pads: () => padsNow };\\n};\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst M = Math, C = VP.C, K = VP.handKit, f = v => M.round(v * 10) \/ 10;\\nVP.Pincer = function (parent, opts) {\\nopts = Object.assign({ skin: VP.skins.medium, scale: 23.4, ow: 3.2 }, opts);\\nconst S = opts.skin, s = opts.scale, ow = opts.ow;\\nconst g = VP.el('g', { opacity: 0 }, parent);\\nconst ink = { fill: 'none', stroke: C.ink, 'stroke-linejoin': 'round', 'stroke-linecap': 'round' };\\nconst mk = () => ({\\ng: VP.el('g', null, g),\\n});\\nconst mkFinger = () => {\\nconst fg = VP.el('g', null, g);\\nreturn {\\no: VP.el('path', Object.assign({}, ink, { 'stroke-width': ow * 2 }), fg),\\nf: VP.el('path', { fill: S.skin }, fg),\\nsh: VP.el('path', Object.assign({}, ink, { stroke: S.shade, 'stroke-width': 3, opacity: 0.55 }), fg),\\ncr: VP.el('path', Object.assign({}, ink, { stroke: S.shade, 'stroke-width': 1.6 }), fg),\\nnail: VP.el('path', { fill: C.nail, stroke: C.nailLine, 'stroke-width': 1.4, 'stroke-linejoin': 'round' }, fg),\\n};\\n};\\nconst I = mkFinger(), T = mkFinger();\\nconst P = (x, y, r) => ({ x, y, r });\\nconst rr = (cx, cy, hw, hl, r) => 'M' + f(cx - hw + r) + ' ' + f(cy - hl) + 'H' + f(cx + hw - r) + 'Q' + f(cx + hw) + ' ' + f(cy - hl) + ' ' + f(cx + hw) + ' ' + f(cy - hl + r) + 'V' + f(cy + hl - r) + 'Q' + f(cx + hw) + ' ' + f(cy + hl) + ' ' + f(cx + hw - r) + ' ' + f(cy + hl) + 'H' + f(cx - hw + r) + 'Q' + f(cx - hw) + ' ' + f(cy + hl) + ' ' + f(cx - hw) + ' ' + f(cy + hl - r) + 'V' + f(cy - hl + r) + 'Q' + f(cx - hw) + ' ' + f(cy - hl) + ' ' + f(cx - hw + r) + ' ' + f(cy - hl) + 'Z';\\nfunction build(gap) {\\nconst ri = 0.67 * s, rt = 0.79 * s, xi = -(gap \/ 2 + ri), xt = gap \/ 2 + rt;\\nconst ji = [P(xi, 0, ri), P(xi + 1.5, 1.9 * s, 0.78 * s), P(xi + 1.0, 4.3 * s, 0.85 * s), P(xi - 3, 8.3 * s, 0.92 * s), P(xi - 12, 12.5 * s, 1.0 * s), P(xi - 22, 19 * s, 1.05 * s)];\\nconst jt = [P(xt, 0.14 * s, rt), P(xt - 1.5, 2.5 * s, 0.94 * s), P(xt + 3, 5.8 * s, 1.02 * s), P(xt + 10, 10.1 * s, 1.18 * s), P(xt + 18, 14.5 * s, 1.3 * s), P(xt + 28, 21 * s, 1.35 * s)];\\nconst chain = j => { let d = ''; for (let k = 0; k \\u003c j.length - 1; k++) d += K.capsule(j[k], j[k + 1]); return d; };\\nconst di = chain(ji), dt = chain(jt);\\nVP.set(I.o, { d: di }); VP.set(I.f, { d: di }); VP.set(T.o, { d: dt }); VP.set(T.f, { d: dt });\\nconst edge = (j, n, k0) => K.smoothOpen(j.slice(0, n).map((p, k) => [p.x + p.r * 0.55, p.y + (k === 0 ? p.r * 0.25 : 0)]));\\nVP.set(I.sh, { d: edge(ji, 4) }); VP.set(T.sh, { d: edge(jt, 4) });\\nconst cr = (p, w, dy) => 'M' + f(p.x - w) + ' ' + f(p.y + dy) + 'Q' + f(p.x) + ' ' + f(p.y + dy - 3) + ' ' + f(p.x + w) + ' ' + f(p.y + dy);\\nVP.set(I.cr, { d: cr(ji[1], 0.5 * ji[1].r, 2) + cr(ji[2], 0.46 * ji[2].r, -5) + cr(ji[2], 0.36 * ji[2].r, 4) });\\nVP.set(T.cr, { d: cr(jt[1], 0.42 * jt[1].r, -4) + cr(jt[1], 0.34 * jt[1].r, 4) });\\nVP.set(I.nail, { d: rr(xi, 0.28 * s, 0.74 * ri, 0.78 * s, 0.34 * s) });\\nVP.set(T.nail, { d: rr(xt + rt * 0.52, 0.34 * s, 0.30 * rt, 0.66 * s, 0.24 * s) });\\n}\\nlet lastGap = -1;\\nreturn {\\ng,\\nset(x, y, ang, gap, a) {\\nif (M.abs(gap - lastGap) > 0.05) { build(gap); lastGap = gap; }\\ng.setAttribute('transform', 'translate(' + f(x) + ' ' + f(y) + ') rotate(' + f(ang) + ')');\\ng.setAttribute('opacity', a === undefined ? 1 : f(a));\\ng.setAttribute('display', a === 0 ? 'none' : 'inline');\\n},\\n};\\n};\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst C = VP.C, M = Math, f = v => M.round(v * 10) \/ 10;\\nconst FONT = 'ui-rounded,\\\"SF Pro Rounded\\\",\\\"Nunito\\\",\\\"Quicksand\\\",\\\"Varela Round\\\",\\\"Segoe UI\\\",system-ui,-apple-system,sans-serif';\\nVP.FONT = FONT;\\nVP.bg = function (root, W, H, dur) {\\nconst g = VP.el('g', null, root);\\nVP.el('rect', { width: W, height: H, fill: C.bgA }, g);\\nconst blobs = [\\n[70, 60, 150, C.mint, 0.75], [740, 400, 190, C.lav, 0.7], [760, 40, 110, C.peach, 0.75], [40, 410, 120, C.sky, 0.75], [400, 440, 90, C.butter, 0.6],\\n].map(b => ({ e: VP.el('circle', { cx: b[0], cy: b[1], r: b[2], fill: b[3], opacity: b[4] }, g), b }));\\nlet d = '';\\n[[130, 300], [655, 120], [700, 300], [95, 130], [560, 400]].forEach((p, i) => { const s = 5 + (i % 2) * 2; d += 'M' + (p[0] - s) + ' ' + p[1] + 'L' + (p[0] + s) + ' ' + p[1] + 'M' + p[0] + ' ' + (p[1] - s) + 'L' + p[0] + ' ' + (p[1] + s); });\\nVP.el('path', { d, stroke: '#fff', 'stroke-width': 3, 'stroke-linecap': 'round', opacity: 0.9 }, g);\\nconst w = k => (dur ? 2 * M.PI * M.max(1, M.round(k * dur \/ (2 * M.PI))) \/ dur : k);\\nreturn { g, update(t) { blobs.forEach((o, i) => { const b = o.b; VP.set(o.e, { cx: f(b[0] + M.sin(t * w(0.35 + i * 0.03) + i * 1.7) * 7), cy: f(b[1] + M.cos(t * w(0.3 + i * 0.04) + i * 2.1) * 6) }); }); } };\\n};\\nlet ruid = 0;\\nVP.Rough = function (svg, W, H, amount) {\\nconst id = 'vpr' + ++ruid;\\nconst defs = VP.el('defs', null, svg);\\nconst fl = VP.el('filter', { id, filterUnits: 'userSpaceOnUse', x: 0, y: 0, width: W, height: H, 'color-interpolation-filters': 'sRGB' }, defs);\\nconst turb = VP.el('feTurbulence', { type: 'fractalNoise', baseFrequency: '0.022 0.026', numOctaves: 2, seed: 2, result: 'n' }, fl);\\nVP.el('feDisplacementMap', { in: 'SourceGraphic', in2: 'n', scale: amount === undefined ? 3.4 : amount, xChannelSelector: 'R', yChannelSelector: 'G' }, fl);\\nconst groups = []; let on = true, lastSeed = 0;\\nreturn {\\nurl: 'url(#' + id + ')',\\nuse(g) { groups.push(g); g.setAttribute('filter', 'url(#' + id + ')'); return g; },\\ntick(t) { if (!on) return; const k = 1 + (M.floor(t * 7) % 9); if (k !== lastSeed) { lastSeed = k; turb.setAttribute('seed', k); } },\\ndisable() { on = false; groups.forEach(g => g.removeAttribute('filter')); },\\nget on() { return on; },\\n};\\n};\\nfunction fit(el, maxW) {\\ntry { const len = el.getComputedTextLength(); if (len > maxW) el.setAttribute('font-size', f(parseFloat(el.getAttribute('font-size')) * maxW \/ len)); } catch (e) {  }\\nreturn el;\\n}\\nVP.UI = function (root, W, H, cfg) {\\nconst g = VP.el('g', { 'font-family': FONT }, root);\\nconst barX = 40, barW = W - 80, barY = H - 96, barH = 76;\\nconst chip = VP.el('g', null, g);\\nconst chipBox = VP.el('rect', { x: 20, y: 16, width: cfg.chip.length * 12.2 + 32, height: 34, rx: 17, fill: '#fff', opacity: 0.92 }, chip);\\nconst chipT = VP.el('text', { x: 36, y: 39.5, 'font-size': 19, 'font-weight': 800, fill: C.text, 'letter-spacing': 0.4 }, chip); chipT.textContent = cfg.chip;\\ntry { const l = chipT.getComputedTextLength(); if (l > 0) chipBox.setAttribute('width', f(l + 32)); } catch (e) {  }\\nconst n = cfg.steps.length, dots = [];\\nconst dg = VP.el('g', null, g);\\nfor (let i = 0; i \\u003c n; i++) dots.push(VP.el('circle', { cx: W - 24 - (n - 1 - i) * 19, cy: 33, r: 5.5, fill: '#fff', stroke: C.lav, 'stroke-width': 2 }, dg));\\nconst items = cfg.steps.map((s, i) => {\\nconst cg = VP.el('g', { opacity: 0 }, g);\\nVP.el('rect', { x: barX, y: barY + 5, width: barW, height: barH, rx: 24, fill: '#d9ccf3', opacity: 0.7 }, cg);\\nVP.el('rect', { x: barX, y: barY, width: barW, height: barH, rx: 24, fill: '#fff' }, cg);\\nVP.el('rect', { x: barX, y: barY, width: barW, height: barH, rx: 24, fill: 'none', stroke: C.lav, 'stroke-width': 2.5 }, cg);\\nVP.el('circle', { cx: barX + 42, cy: barY + barH \/ 2, r: 26, fill: s.color || C.coral }, cg);\\nVP.el('text', { x: barX + 42, y: barY + barH \/ 2 + 11, 'text-anchor': 'middle', 'font-size': 30, 'font-weight': 800, fill: '#fff' }, cg).textContent = s.icon || (i + 1);\\nconst two = !!s.sub;\\nconst tt = VP.el('text', { x: barX + 84, y: barY + (two ? 35 : 48), 'font-size': s.size || 31, 'font-weight': 800, fill: C.text }, cg); tt.textContent = s.title; fit(tt, barW - 110);\\nif (two) { const st = VP.el('text', { x: barX + 84, y: barY + 64, 'font-size': 23, 'font-weight': 700, fill: C.textSoft }, cg); st.textContent = s.sub; fit(st, barW - 110); }\\nreturn { g: cg, s };\\n});\\nconst tips = (cfg.tips || []).map(tp => {\\nconst tg = VP.el('g', { opacity: 0 }, g);\\nconst w = tp.w || 230, h = tp.lines.length * 25 + 42;\\nVP.el('rect', { x: tp.x + 4, y: tp.y + 5, width: w, height: h, rx: 16, fill: '#f0cfa8', opacity: 0.55 }, tg);\\nVP.el('rect', { x: tp.x, y: tp.y, width: w, height: h, rx: 16, fill: C.butter, stroke: '#f3d98d', 'stroke-width': 2.5 }, tg);\\nVP.el('text', { x: tp.x + 16, y: tp.y + 26, 'font-size': 20, 'font-weight': 800, fill: '#b5701c' }, tg).textContent = tp.head || 'TIP';\\ntp.lines.forEach((l, i) => { const te = VP.el('text', { x: tp.x + 16, y: tp.y + 51 + i * 25, 'font-size': 20, 'font-weight': 700, fill: C.text }, tg); te.textContent = l; fit(te, w - 30); });\\nreturn { g: tg, tp };\\n});\\nreturn {\\ng,\\nupdate(t) {\\nlet cur = -1;\\nitems.forEach((it, i) => {\\nconst s = it.s, a = VP.win(t, s.t0, s.t0 + 0.45, s.t1 - 0.35, s.t1);\\nit.g.setAttribute('opacity', f(a));\\nit.g.setAttribute('transform', 'translate(0 ' + f((1 - a) * 14) + ')');\\nif (t >= s.t0 \\u0026\\u0026 t \\u003c s.t1) cur = i;\\n});\\ndots.forEach((d, i) => { d.setAttribute('fill', i === cur ? C.coral : i \\u003c cur ? C.lav : '#fff'); d.setAttribute('stroke', i === cur ? C.coral : C.lav); d.setAttribute('r', i === cur ? 6.5 : 5.5); });\\ntips.forEach(tt => { const a = VP.win(t, tt.tp.t0, tt.tp.t0 + 0.4, tt.tp.t1 - 0.3, tt.tp.t1); tt.g.setAttribute('opacity', f(a)); tt.g.setAttribute('transform', 'translate(0 ' + f((1 - a) * -10) + ')'); });\\n},\\n};\\n};\\nVP.play = function (container, def, opts) {\\nopts = opts || {};\\nconst W = def.W || 800, H = def.H || 450;\\nconst svg = VP.el('svg', { viewBox: '0 0 ' + W + ' ' + H, width: '100%', role: 'img', 'aria-label': def.title, preserveAspectRatio: 'xMidYMid meet', style: 'display:block;width:100%;height:auto' }, container);\\nVP.el('title', null, svg).textContent = def.title;\\nif (def.desc) VP.el('desc', null, svg).textContent = def.desc;\\nconst skinName = opts.skin || container.getAttribute('data-skin') || 'medium';\\nconst ctx = { W, H, skin: VP.skins[skinName] || VP.skins.medium, skinName, rough: opts.rough === false ? null : VP.Rough(svg, W, H, opts.wobble) };\\nconst scene = def.build(svg, ctx);\\nconst dur = def.duration;\\nconst render = t => scene.update(t);\\nconst fixed = opts.t !== undefined \\u0026\\u0026 opts.t !== null;\\nif (fixed) { render(+opts.t); return { seek: render, svg }; }\\nconst reduce = window.matchMedia \\u0026\\u0026 matchMedia('(prefers-reduced-motion: reduce)').matches;\\nif (reduce) { render(def.poster !== undefined ? def.poster : dur * 0.55); return { seek: render, svg }; }\\nlet raf = 0, last = 0, clock = 0, on = false, inView = true;\\nconst minDt = 1000 \/ (opts.fps || 30);\\nlet slow = 0, seen = 0;\\nfunction frame(ts) {\\nraf = requestAnimationFrame(frame);\\nif (!last) last = ts;\\nconst dt = ts - last;\\nif (dt \\u003c minDt - 1) return;\\nlast = ts - (dt % minDt);\\nclock += M.min(dt, 100) \/ 1000;\\nconst t0 = performance.now();\\nrender(clock % dur);\\nif (ctx.rough \\u0026\\u0026 ctx.rough.on \\u0026\\u0026 ++seen > 20) { slow += (performance.now() - t0 > 14 || dt > 52) ? 1 : 0; if (seen === 80) { if (slow > 30) ctx.rough.disable(); seen = 21; slow = 0; } }\\n}\\nfunction start() { if (on || !inView || document.hidden) return; on = true; last = 0; raf = requestAnimationFrame(frame); }\\nfunction stop() { on = false; cancelAnimationFrame(raf); }\\nrender(0);\\nif ('IntersectionObserver' in window) new IntersectionObserver(es => { inView = es[0].isIntersecting; inView ? start() : stop(); }, { threshold: 0.05 }).observe(container);\\ndocument.addEventListener('visibilitychange', () => (document.hidden ? stop() : start()));\\nstart();\\nreturn { seek: render, svg, stop, start, destroy() { stop(); if (svg.parentNode) svg.parentNode.removeChild(svg); } };\\n};\\nVP.videos = VP.videos || {};\\nVP.auto = function () {\\ndocument.querySelectorAll('[data-vp]').forEach(el => {\\nconst def = VP.videos[el.getAttribute('data-vp')];\\nif (def \\u0026\\u0026 !el.__vp) el.__vp = VP.play(el, def, { rough: el.getAttribute('data-rough') !== 'off' });\\n});\\n};\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst C = VP.C, M = Math, f = v => M.round(v * 10) \/ 10, H = VP.hash;\\nconst star = (s) => 'M0 ' + -s + 'C' + s * 0.12 + ' ' + -s * 0.12 + ' ' + s * 0.12 + ' ' + -s * 0.12 + ' ' + s + ' 0C' + s * 0.12 + ' ' + s * 0.12 + ' ' + s * 0.12 + ' ' + s * 0.12 + ' 0 ' + s + 'C' + -s * 0.12 + ' ' + s * 0.12 + ' ' + -s * 0.12 + ' ' + s * 0.12 + ' ' + -s + ' 0C' + -s * 0.12 + ' ' + -s * 0.12 + ' ' + -s * 0.12 + ' ' + -s * 0.12 + ' 0 ' + -s + 'Z';\\nVP.Bubbles = function (parent, cx, cy, spread, n) {\\nconst g = VP.el('g', null, parent), bs = [];\\nfor (let i = 0; i \\u003c n; i++) {\\nconst r = 8 + H(i * 3.1) * 22, e = VP.el('g', null, g);\\nVP.el('circle', { r, fill: '#dff1fd', 'fill-opacity': 0.85, stroke: '#9fcdee', 'stroke-width': 2.2 }, e);\\nVP.el('path', { d: 'M' + -r * 0.55 + ' ' + -r * 0.1 + 'A' + r * 0.6 + ' ' + r * 0.6 + ' 0 0 1 ' + -r * 0.1 + ' ' + -r * 0.55, fill: 'none', stroke: '#fff', 'stroke-width': 2.4, 'stroke-linecap': 'round' }, e);\\nbs.push({ e, r, a: H(i * 7.7) * M.PI * 2, d: H(i * 1.9), k: H(i * 5.3) });\\n}\\nreturn {\\ng,\\nupdate(t, amount, rise) {\\ng.setAttribute('opacity', f(M.min(1, amount * 1.6)));\\nbs.forEach((b, i) => {\\nconst s = M.max(0, M.min(1, amount * 1.4 - b.k * 0.4));\\nconst x = cx + M.cos(b.a) * spread * (0.25 + b.d) + M.sin(t * 1.3 + i) * 4;\\nconst y = cy + M.sin(b.a) * spread * 0.55 * (0.25 + b.d) - rise * (30 + b.k * 90) + M.cos(t * 1.1 + i * 2) * 3;\\nb.e.setAttribute('transform', 'translate(' + f(x) + ' ' + f(y) + ') scale(' + f(s * (1 - rise * 0.5)) + ')');\\n});\\n},\\n};\\n};\\nVP.Sparkles = function (parent, pts, color) {\\nconst g = VP.el('g', null, parent);\\nconst ss = pts.map((p, i) => ({ e: VP.el('path', { d: star(p[2] || 14), fill: color || '#ffe08a', stroke: '#f5c14e', 'stroke-width': 1.6, 'stroke-linejoin': 'round' }, g), p, i }));\\nreturn {\\ng,\\nupdate(t, on) {\\nss.forEach(s => {\\nconst ph = (t * 1.6 + s.i * 0.37) % 1, k = on * M.sin(M.PI * ph);\\ns.e.setAttribute('transform', 'translate(' + s.p[0] + ' ' + s.p[1] + ') rotate(' + f(ph * 50) + ') scale(' + f(k) + ')');\\n});\\n},\\n};\\n};\\nVP.Faucet = function (parent, x, y, frontParent) {\\nconst g = VP.el('g', null, parent), sg = VP.el('g', null, frontParent || g);\\nconst stream = VP.el('rect', { x: x - 6, y: y + 60, width: 12, height: 0, rx: 6, fill: C.water, stroke: '#7fbdea', 'stroke-width': 2.4, opacity: 0.95 }, sg);\\nconst streak = VP.el('path', { d: '', stroke: '#fff', 'stroke-width': 2.4, 'stroke-linecap': 'round', 'stroke-dasharray': '10 16', fill: 'none', opacity: 0.85 }, sg);\\nVP.el('path', { d: 'M' + (x - 70) + ' ' + (y - 40) + 'H' + (x + 6) + 'Q' + (x + 30) + ' ' + (y - 40) + ' ' + (x + 30) + ' ' + (y - 14) + 'V' + (y + 46) + 'H' + (x - 30) + 'V' + (y - 14) + 'Q' + (x - 30) + ' ' + (y - 16) + ' ' + (x - 34) + ' ' + (y - 16) + 'H' + (x - 70) + 'Z', fill: '#e4ebf5', stroke: C.ink, 'stroke-width': 3, 'stroke-linejoin': 'round' }, g);\\nVP.el('rect', { x: x - 32, y: y + 46, width: 64, height: 16, rx: 8, fill: '#cdd8ea', stroke: C.ink, 'stroke-width': 3 }, g);\\nVP.el('circle', { cx: x - 50, cy: y - 62, r: 11, fill: C.coral2, stroke: C.ink, 'stroke-width': 3 }, g);\\nVP.el('rect', { x: x - 56, y: y - 52, width: 12, height: 14, fill: '#cdd8ea', stroke: C.ink, 'stroke-width': 3 }, g);\\nreturn {\\ng,\\nupdate(t, flow, bottom) {\\nconst h = M.max(0, (bottom - (y + 62))) * flow;\\nVP.set(stream, { height: f(h), opacity: f(flow) });\\nVP.set(streak, { d: 'M' + x + ' ' + (y + 64) + 'V' + f(y + 64 + h), 'stroke-dashoffset': f(-t * 90), opacity: f(flow) });\\n},\\n};\\n};\\nVP.Towel = function (parent, w, h) {\\nconst g = VP.el('g', null, parent);\\nVP.el('rect', { x: -w \/ 2, y: -h \/ 2, width: w, height: h, rx: 22, fill: '#c9ece1', stroke: C.ink, 'stroke-width': 3.2 }, g);\\nconst n = M.max(1, M.floor((h - 30) \/ 30)); for (let i = 0; i \\u003c n; i++) VP.el('rect', { x: -w \/ 2 + 3, y: -h \/ 2 + 12 + (n === 1 ? (h - 40) \/ 2 : i * (h - 40) \/ (n - 1)), width: w - 6, height: 8, fill: '#fff', opacity: 0.75 }, g);\\nlet fr = ''; for (let i = 0; i \\u003c 18; i++) { const x = -w \/ 2 + 18 + i * ((w - 36) \/ 17); fr += 'M' + f(x) + ' ' + (h \/ 2 - 2) + 'v9'; }\\nVP.el('path', { d: fr, stroke: C.ink, 'stroke-width': 2.6, 'stroke-linecap': 'round' }, g);\\nreturn { g, update(x, y, rot, op) { g.setAttribute('transform', 'translate(' + f(x) + ' ' + f(y) + ') rotate(' + f(rot || 0) + ')'); g.setAttribute('opacity', op === undefined ? 1 : op); } };\\n};\\nVP.Case = function (parent, cx, cy) {\\nconst g = VP.el('g', { transform: 'translate(' + cx + ' ' + cy + ')' }, parent);\\nVP.el('rect', { x: -205, y: -100, width: 410, height: 200, rx: 54, fill: '#d8ccf3', stroke: C.ink, 'stroke-width': 3.5 }, g);\\nVP.el('rect', { x: -195, y: -92, width: 390, height: 184, rx: 46, fill: 'none', stroke: '#fff', 'stroke-width': 3, opacity: 0.6 }, g);\\nconst wells = [-100, 100].map((x, i) => {\\nconst w = VP.el('g', { transform: 'translate(' + x + ' 6)' }, g);\\nVP.el('circle', { r: 66, fill: '#c1eadb', stroke: C.ink, 'stroke-width': 3.2 }, w);\\nVP.el('circle', { r: 53, fill: '#cfeaff', stroke: C.ink, 'stroke-width': 2.6 }, w);\\nconst surf = VP.el('circle', { r: 47, fill: '#e7f5ff', opacity: 0.9 }, w);\\nconst rip = [VP.el('circle', { r: 10, fill: 'none', stroke: '#8cc4ec', 'stroke-width': 2.4, opacity: 0 }, w), VP.el('circle', { r: 10, fill: 'none', stroke: '#8cc4ec', 'stroke-width': 2, opacity: 0 }, w)];\\nreturn { w, surf, rip };\\n});\\n[[-100, 'L'], [100, 'R']].forEach(p => VP.el('text', { x: p[0], y: -63, 'text-anchor': 'middle', 'font-size': 24, 'font-weight': 800, fill: '#7a68a8', 'font-family': VP.FONT }, g).textContent = p[1]);\\nconst lids = [-100, 100].map((x, i) => {\\nconst l = VP.el('g', null, g);\\nVP.el('circle', { r: 66, cx: 0, cy: 0, fill: i ? '#9fdcc7' : '#ffc9c2', stroke: C.ink, 'stroke-width': 3.2 }, l);\\nVP.el('circle', { r: 52, fill: 'none', stroke: '#fff', 'stroke-width': 3, 'stroke-dasharray': '3 9', 'stroke-linecap': 'round', opacity: 0.85 }, l);\\nVP.el('text', { x: 0, y: 12, 'text-anchor': 'middle', 'font-size': 36, 'font-weight': 800, fill: '#fff', 'font-family': VP.FONT }, l).textContent = i ? 'R' : 'L';\\nreturn l;\\n});\\nreturn {\\ng, wells, lids,\\nupdate(lidR, lidL, ripple) {\\n[[lids[1], 100, lidR], [lids[0], -100, lidL]].forEach(a => {\\nconst k = a[2], lift = (1 - k);\\na[0].setAttribute('transform', 'translate(' + f(a[1] + (a[1] > 0 ? 34 : -34) * lift) + ' ' + f(6 - 96 * lift) + ') rotate(' + f((a[1] > 0 ? -1 : 1) * 120 * lift) + ') scale(' + f(1 + 0.12 * lift) + ')');\\na[0].setAttribute('opacity', f(M.min(1, k * 3)));\\n});\\nwells[1].rip.forEach((r, i) => { const p = M.max(0, M.min(1, ripple * 1.6 - i * 0.3)); r.setAttribute('r', f(8 + p * 40)); r.setAttribute('opacity', f((1 - p) * (p > 0 ? 0.9 : 0))); });\\n},\\n};\\n};\\nVP.Check = function (parent, x, y, r) {\\nconst g = VP.el('g', null, parent);\\nVP.el('circle', { r, fill: '#a9e3cb', stroke: C.ink, 'stroke-width': 3.2 }, g);\\nVP.el('path', { d: 'M' + -r * 0.42 + ' ' + r * 0.02 + 'L' + -r * 0.1 + ' ' + r * 0.34 + 'L' + r * 0.46 + ' ' + -r * 0.3, fill: 'none', stroke: '#fff', 'stroke-width': 8, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, g);\\nreturn { g, update(k) { const s = VP.ease.back(M.max(0, M.min(1, k))); g.setAttribute('transform', 'translate(' + x + ' ' + y + ') scale(' + f(s) + ')'); g.setAttribute('opacity', f(M.min(1, k * 4))); } };\\n};\\nVP.Arrow = function (parent, d, color, w) {\\nconst g = VP.el('g', null, parent);\\nconst p = VP.el('path', { d, fill: 'none', stroke: color || C.coral, 'stroke-width': w || 5, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, g);\\nconst len = 400; p.setAttribute('stroke-dasharray', len);\\nreturn { g, path: p, update(k, a) { p.setAttribute('stroke-dashoffset', f(len * (1 - VP.ease.io(M.max(0, M.min(1, k)))))); g.setAttribute('opacity', a === undefined ? 1 : f(a)); } };\\n};\\nVP.Dropper = function (parent) {\\nconst g = VP.el('g', { opacity: 0 }, parent);\\nVP.el('path', { d: 'M-26 -34C-26 -44 -14 -48 -10 -56V-70H10V-56C14 -48 26 -44 26 -34V52Q26 62 16 62H-16Q-26 62 -26 52Z', fill: '#c9ece1', stroke: C.ink, 'stroke-width': 3.4, 'stroke-linejoin': 'round' }, g);\\nVP.el('rect', { x: -20, y: -18, width: 40, height: 52, rx: 10, fill: '#fff', stroke: C.ink, 'stroke-width': 2.6 }, g);\\nVP.el('path', { d: 'M0 -8C7 3 11 8 11 14A11 11 0 0 1 -11 14C-11 8 -7 3 0 -8Z', fill: C.water, stroke: C.ink, 'stroke-width': 2.4, 'stroke-linejoin': 'round' }, g);\\nVP.el('rect', { x: -15, y: -84, width: 30, height: 20, rx: 6, fill: C.coral2, stroke: C.ink, 'stroke-width': 3.2 }, g);\\nVP.el('path', { d: 'M-6 -84V-96H6V-84', fill: '#fff', stroke: C.ink, 'stroke-width': 3, 'stroke-linejoin': 'round' }, g);\\nreturn { g, update(x, y, rot, a) { g.setAttribute('transform', 'translate(' + f(x) + ' ' + f(y) + ') rotate(' + f(rot) + ')'); g.setAttribute('opacity', f(a)); g.setAttribute('display', a \\u003c= 0 ? 'none' : 'inline'); } };\\n};\\nVP.Drop = function (parent) {\\nconst g = VP.el('g', { opacity: 0 }, parent);\\nVP.el('path', { d: 'M0 -13C6 -4 9 1 9 5A9 9 0 0 1 -9 5C-9 1 -6 -4 0 -13Z', fill: C.water, stroke: '#6fb1ee', 'stroke-width': 2.4, 'stroke-linejoin': 'round' }, g);\\nVP.el('path', { d: 'M-3.5 3A4.5 4.5 0 0 0 0 9', fill: 'none', stroke: '#fff', 'stroke-width': 2, 'stroke-linecap': 'round' }, g);\\nreturn { g, set(x, y, s, a) { g.setAttribute('transform', 'translate(' + f(x) + ' ' + f(y) + ') scale(' + f(s) + ')'); g.setAttribute('opacity', f(a)); g.setAttribute('display', a \\u003c= 0 ? 'none' : 'inline'); } };\\n};\\nVP.Ring = function (parent, color) {\\nconst e = VP.el('ellipse', { rx: 4, ry: 2, fill: 'none', stroke: color || '#6fb1ee', 'stroke-width': 2.6, opacity: 0 }, parent);\\nreturn { e, set(x, y, k, r) { const R = (r || 30) * k; VP.set(e, { cx: f(x), cy: f(y), rx: f(4 + R), ry: f(2 + R * 0.45), opacity: f(k > 0 \\u0026\\u0026 k \\u003c 1 ? (1 - k) * 0.9 : 0) }); } };\\n};\\nVP.Badge = function (parent, x, y, kind, color) {\\nconst g = VP.el('g', null, parent), r = 34;\\nVP.el('rect', { x: -r, y: -r, width: r * 2, height: r * 2, rx: 20, fill: color || C.coral, stroke: C.ink, 'stroke-width': 3.4 }, g);\\nif (kind === 'cross') VP.el('path', { d: 'M0 -18V18M-18 0H18', stroke: '#fff', 'stroke-width': 10, 'stroke-linecap': 'round' }, g);\\nelse { VP.el('path', { d: 'M0 -18V4', stroke: '#fff', 'stroke-width': 10, 'stroke-linecap': 'round' }, g); VP.el('circle', { cy: 19, r: 5.6, fill: '#fff' }, g); }\\nreturn { g, update(k) { const s = VP.ease.back(M.max(0, M.min(1, k))); g.setAttribute('transform', 'translate(' + x + ' ' + y + ') scale(' + f(s) + ') rotate(' + f((1 - s) * -20) + ')'); g.setAttribute('opacity', f(M.min(1, k * 4))); g.setAttribute('display', k \\u003c= 0 ? 'none' : 'inline'); } };\\n};\\nVP.Swirl = function (parent) {\\nconst g = VP.el('g', { opacity: 0 }, parent);\\nVP.el('path', { d: 'M0 -26A26 26 0 1 1 -26 0', fill: 'none', stroke: C.coral, 'stroke-width': 5, 'stroke-linecap': 'round' }, g);\\nVP.el('path', { d: 'M-36 -8L-26 4L-14 -8', fill: 'none', stroke: C.coral, 'stroke-width': 5, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }, g);\\nreturn { g, update(x, y, t, a) { g.setAttribute('transform', 'translate(' + f(x) + ' ' + f(y) + ') rotate(' + f(t * 120) + ')'); g.setAttribute('opacity', f(a)); } };\\n};\\nVP.Label = function (parent, x, y, w, text, tx, ty) {\\nconst g = VP.el('g', { opacity: 0 }, parent);\\nconst sx = x + w, sy = y + 17;\\nVP.el('path', { d: 'M' + f(sx) + ' ' + f(sy) + 'C' + f(sx + 46) + ' ' + f(sy) + ' ' + f(tx - 20) + ' ' + f(ty + 34) + ' ' + tx + ' ' + ty, fill: 'none', stroke: '#fff', 'stroke-width': 8, 'stroke-linecap': 'round', opacity: 0.9 }, g);\\nVP.el('path', { d: 'M' + f(sx) + ' ' + f(sy) + 'C' + f(sx + 46) + ' ' + f(sy) + ' ' + f(tx - 20) + ' ' + f(ty + 34) + ' ' + tx + ' ' + ty, fill: 'none', stroke: C.ink, 'stroke-width': 3.6, 'stroke-linecap': 'round' }, g);\\nVP.el('circle', { cx: tx, cy: ty, r: 7.5, fill: C.coral, stroke: C.ink, 'stroke-width': 3 }, g);\\nVP.el('rect', { x: x + 3, y: y + 4, width: w, height: 34, rx: 17, fill: '#d9ccf3', opacity: 0.7 }, g);\\nVP.el('rect', { x, y, width: w, height: 34, rx: 17, fill: '#fff', stroke: C.lav, 'stroke-width': 2.5 }, g);\\nVP.el('text', { x: x + w \/ 2, y: y + 23, 'text-anchor': 'middle', 'font-size': 18, 'font-weight': 800, fill: C.text, 'font-family': VP.FONT }, g).textContent = text;\\nreturn { g, update(a) { g.setAttribute('opacity', f(a)); g.setAttribute('transform', 'translate(' + f((1 - a) * -8) + ' 0)'); } };\\n};\\nVP.star = star;\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst C = VP.C, M = Math, f = v => M.round(v * 10) \/ 10, win = VP.win, E = VP.ease;\\nVP.Lens = function (parent, r, rigid) {\\nr = r || 40;\\nconst g = VP.el('g', null, parent);\\nVP.el('ellipse', { cx: 4, cy: r + 8, rx: r * 0.8, ry: r * 0.14, fill: C.ink, opacity: 0.0 }, g);\\nconst inner = VP.el('g', null, g);\\nVP.el('circle', { r, fill: C.lens, opacity: rigid ? 0.7 : 0.5 }, inner);\\nVP.el('circle', { r, fill: 'none', stroke: C.lensEdge, 'stroke-width': rigid ? 4.5 : 3, opacity: 0.95 }, inner);\\nVP.el('circle', { r: r - 6, fill: 'none', stroke: '#fff', 'stroke-width': 2, opacity: 0.6 }, inner);\\nVP.el('path', { d: 'M' + -r * 0.72 + ' ' + -r * 0.45 + 'A' + r * 0.86 + ' ' + r * 0.86 + ' 0 0 1 ' + -r * 0.22 + ' ' + -r * 0.83, fill: 'none', stroke: '#fff', 'stroke-width': 4, 'stroke-linecap': 'round' }, inner);\\nconst ridge = VP.el('path', { d: 'M0 ' + -r + 'L0 ' + r, fill: 'none', stroke: C.lensEdge, 'stroke-width': 3, 'stroke-linecap': 'round', opacity: 0 }, inner);\\nreturn {\\ng,\\nset(x, y, s, fold, rot, a) {\\ng.setAttribute('transform', 'translate(' + f(x) + ' ' + f(y) + ') rotate(' + f(rot || 0) + ') scale(' + f((1 - 0.66 * (fold || 0)) * s) + ' ' + f((1 + 0.1 * (fold || 0)) * s) + ')');\\nridge.setAttribute('opacity', f((fold || 0) * 0.9));\\ng.setAttribute('opacity', a === undefined ? 1 : f(a));\\ng.setAttribute('display', a === 0 ? 'none' : 'inline');\\n},\\n};\\n};\\nVP.faceWindow = function (parent, ctx, cx, cy, R, eyeDy, eyeDx) {\\nconst g = VP.el('g', null, parent), S = ctx.skin;\\nconst uid = 'fw' + M.random().toString(36).slice(2, 7);\\nVP.el('circle', { cx, cy: cy + 8, r: R + 12, fill: '#d9ccf3', opacity: 0.55 }, g);\\nVP.el('circle', { cx, cy, r: R + 10, fill: C.lav }, g);\\nVP.el('circle', { cx, cy, r: R + 10, fill: 'none', stroke: '#fff', 'stroke-width': 3, opacity: 0.8 }, g);\\nVP.el('circle', { cx, cy, r: R }, VP.el('clipPath', { id: uid }, VP.el('defs', null, g)));\\nconst inner = VP.el('g', { 'clip-path': 'url(#' + uid + ')' }, g);\\nVP.el('circle', { cx, cy, r: R, fill: S.face }, inner);\\nconst ex = cx + (eyeDx || 0), ey = cy + eyeDy;\\nconst eye = VP.Eye(inner, { skin: S, cx: ex, cy: ey });\\nreturn {\\ng, eye, ex, ey,\\nupdate(st, pop) {\\neye.update(st);\\nconst s = 0.86 + 0.14 * E.back(M.min(1, pop)), o = M.min(1, pop * 2.2);\\ng.setAttribute('transform', 'translate(' + f(cx * (1 - s)) + ' ' + f(cy * (1 - s)) + ') scale(' + f(s) + ')');\\ng.setAttribute('opacity', f(o));\\ng.setAttribute('display', o \\u003c= 0 ? 'none' : 'inline');\\n},\\n};\\n};\\nVP.WASH = { scale: 21.5, y: 492, L: { x: 372, roll: -16, dy: 4 }, R: { x: 436, roll: 16, dy: -22 }, rub: 12 };\\nVP.washAct = function (parent, ctx) {\\nconst g = VP.el('g', null, parent), sk = ctx.skin, W = VP.WASH;\\nconst back = VP.el('g', null, g), front = VP.el('g', null, g);\\nconst faucet = VP.Faucet(back, 470, 22, front);\\nconst base = { pos: [0, 0], scale: W.scale, spread: 0.2, rot: [0, 0, 0], index: [-1, 10, 14, 8], middle: [0, 12, 16, 10], ring: [0, 14, 18, 10], pinky: [0, 16, 20, 10], thumb: [-34, 18, -50, 10, 10] };\\nconst hL = VP.Hand(back, { mirror: true, skin: sk }), hR = VP.Hand(back, { mirror: false, skin: sk, shadow: { dx: 10, dy: 12, opacity: 0.16 } });\\nconst bubbles = VP.Bubbles(front, 410, 252, 118, 28);\\nconst towel = VP.Towel(front, 560, 190);\\nconst spark = VP.Sparkles(front, [[290, 200, 15], [520, 190, 19], [405, 150, 12], [335, 315, 11], [485, 320, 15], [420, 250, 10]]);\\nreturn {\\ng,\\nupdate(t) {\\nconst enter = E.o(M.min(1, M.max(0, t \/ 1.0)));\\nconst rubAmp = win(t, 0.9, 1.5, 4.3, 5.0), rub = M.sin(t * 8.5) * W.rub * rubAmp;\\nconst lather = win(t, 1.1, 2.3, 3.3, 4.7);\\nconst flow = win(t, 3.3, 3.7, 4.9, 5.3);\\nconst dy = (1 - enter) * 190;\\nconst put = (h, c, dir) => {\\nconst a = c.roll * M.PI \/ 180, ux = -M.sin(a), uy = -M.cos(a);\\nh.update(Object.assign({}, base, { rot: [c.roll, -6, 0], pos: [c.x + ux * rub * dir, W.y + (c.dy || 0) + dy + uy * rub * dir] }));\\n};\\nput(hL, W.L, 1); put(hR, W.R, -1);\\nbubbles.update(t, lather, win(t, 3.3, 3.4, 3.5, 5.4) * 1.0 + 0);\\nfaucet.update(t, flow, 232);\\nconst tin = E.io(M.min(1, M.max(0, (t - 5.15) \/ 0.7))), tout = E.io(M.min(1, M.max(0, (t - 6.55) \/ 0.6)));\\nconst ty = 560 - 250 * tin + 300 * tout;\\ntowel.update(410 + M.sin(t * 11) * 7 * win(t, 5.7, 5.9, 6.3, 6.55), ty, M.sin(t * 9) * 1.2, 1);\\nspark.update(t, win(t, 6.6, 6.9, 7.3, 7.7));\\ng.setAttribute('opacity', f(M.min(1, t \/ 0.5) * (t > 7.0 ? M.max(0, (7.8 - t) \/ 0.8) : 1)));\\ng.setAttribute('display', t > 7.85 ? 'none' : 'inline');\\n},\\n};\\n};\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst C = VP.C, M = Math, E = VP.ease, win = VP.win, T = VP.track, f = v => M.round(v * 10) \/ 10, cl = VP.clamp;\\nconst STR = {\\nchip: 'SOFT LENSES \u00b7 PINCH METHOD',\\nsteps: [\\n{ t0: 0.5,  t1: 7.5,  title: 'Wash and dry your hands', sub: 'Mild soap, then a lint-free towel' },\\n{ t0: 8.2,  t1: 12.6, title: 'Look up', sub: 'Keep your head straight' },\\n{ t0: 12.6, t1: 18.4, title: 'Open wide', sub: 'Hold your upper lid up, pull your lower lid down' },\\n{ t0: 18.4, t1: 24.4, title: 'Slide the lens to the white', sub: 'Use the pad of your index finger' },\\n{ t0: 24.4, t1: 28.0, title: 'Pinch gently with your finger pads', sub: 'Never with your fingernails' },\\n{ t0: 28.0, t1: 32.3, title: 'Lift the lens out', sub: 'It should come away folded, no tugging' },\\n{ t0: 32.9, t1: 39.9, title: 'Store it in fresh solution', sub: 'Rub and rinse first. Dailies? Just toss it' },\\n{ t0: 40.1, t1: 42.7, title: 'Now repeat with the other eye', sub: 'Same steps, same order', icon: '\u2713', color: '#7fcfae' },\\n],\\ntips: [{ t0: 1.2, t1: 6.6, x: 20, y: 76, w: 222, head: 'TIP', lines: ['Plug the sink drain', 'so a dropped lens', 'cannot escape.'] },\\n{ t0: 24.9, t1: 28.1, x: 568, y: 62, w: 214, head: 'TIP', lines: ['Finger pads only.', 'Nails can scratch', 'your eye.'] }],\\n};\\nconst CURL = { ring: [0, 72, 94, 52], pinky: [0, 78, 98, 52] };\\nconst FIST = { middle: [0, 78, 98, 58], ring: [0, 84, 102, 62], pinky: [0, 88, 104, 62] };\\nconst DORSAL = Object.assign({ pos: [0, 0], rot: [78, -12, -6], scale: 23.4, spread: 0.5, index: [-1, 8, 14, 8], middle: [2, 14, 24, 12], thumb: [-28, 30, -60, 30, 25], layers: {} }, CURL);\\nconst LPOSE = Object.assign({ pos: [0, 0], rot: [-135, -12, 0], scale: 23.4, spread: 0.4, index: [0, 8, 14, 8], thumb: [-20, 30, -60, 40, 40], layers: {} }, FIST);\\nconst PA = -14, PP = [441, 262];\\nconst back = (P, ang, q) => { const a = ang * M.PI \/ 180; return [P[0] - M.sin(a) * q, P[1] + M.cos(a) * q]; };\\nVP.videos.pinch = {\\ntitle: 'How to remove soft contact lenses: the pinch method',\\ndesc: 'Animated steps: wash and dry hands, look up, open the eyelids, slide the lens down to the white of the eye, pinch it gently with the finger pads, lift it out, and store it in fresh solution.',\\nduration: 43.4, poster: 25.8, steps: STR.steps, tips: STR.tips,\\nbuild(svg, ctx) {\\nconst W = 800, H = 450, sk = ctx.skin;\\nconst bg = VP.bg(svg, W, H, this.duration);\\nconst art = VP.el('g', null, svg);\\nif (ctx.rough) ctx.rough.use(art);\\nconst wash = VP.washAct(art, ctx);\\nconst eyeAct = VP.el('g', null, art);\\nconst fw = VP.faceWindow(eyeAct, ctx, 428, 168, 162, 14);\\nconst EX = fw.ex, EY = fw.ey;\\nconst lens = VP.Lens(eyeAct, 63);\\nconst label = VP.Label(eyeAct, 112, 292, 172, 'White of the eye', 361, 214);\\nconst Lh = VP.HandActor(eyeAct, { mirror: false, skin: sk }, {\\npose: [[7, LPOSE]],\\ntg: { index: [[12.1, { x: 230, y: -30, w: 1 }], [13.4, { x: 384, y: 70, w: 1 }], [14.05, { x: 404, y: 104, w: 1 }, E.io], [14.95, { x: 404, y: 88, w: 1 }, E.io], [29.3, { x: 404, y: 88, w: 1 }], [30.6, { x: 230, y: -30, w: 1 }, E.io]] },\\nfree: [{ k: 'pos', i: 0, e: 0.6, w: 0.05 }, { k: 'pos', i: 1, e: 0.6, w: 0.05 }],\\n});\\nconst Rh = VP.HandActor(eyeAct, { mirror: true, skin: sk }, {\\npose: [[12, DORSAL]],\\ntg: {\\nmiddle: [[12.0, { x: 930, y: 300, w: 1 }], [13.4, { x: 560, y: 300, w: 1 }], [14.3, { x: 452, y: 238, w: 1 }, E.io], [15.7, { x: 456, y: 280, w: 1 }, E.io], [23.6, { x: 456, y: 280, w: 1 }], [24.7, { x: 980, y: 300, w: 1 }, E.io]],\\nindex: [[12.0, { x: 950, y: 260, w: 0 }], [17.4, { x: 500, y: 170, w: 0 }], [18.3, { x: 476, y: 172, w: 1 }, E.io], [19.3, { x: 438, y: 188, w: 1 }, E.io], [21.9, { x: 442, y: 244, w: 1 }, E.io], [23.6, { x: 442, y: 244, w: 1 }], [24.7, { x: 960, y: 250, w: 1 }, E.io]],\\n},\\n});\\nconst pin = VP.Pincer(eyeAct, { skin: sk, scale: 23.4 });\\nconst store = VP.el('g', null, art);\\nconst cs = VP.Case(store, 400, 196);\\nconst lens2 = VP.Lens(store, 40);\\nconst pin2 = VP.Pincer(store, { skin: sk, scale: 23.4 });\\nconst check = VP.Check(store, 610, 100, 40);\\nconst spark = VP.Sparkles(store, [[560, 60, 14], [660, 140, 12], [300, 70, 12], [640, 60, 10], [500, 300, 12]]);\\nconst ui = VP.UI(svg, W, H, { chip: STR.chip, steps: STR.steps, tips: STR.tips });\\nreturn {\\nupdate(t) {\\nbg.update(t);\\nif (ctx.rough) ctx.rough.tick(t);\\nwash.update(t);\\nconst pop = win(t, 7.3, 8.2, 32.0, 32.8);\\neyeAct.setAttribute('display', pop \\u003c= 0 ? 'none' : 'inline');\\nconst gy = T([[0, 0], [9.5, 0], [10.9, -34, E.io], [29.8, -34], [31.0, 0, E.io]], t);\\nconst open = T([[0, 1.04], [8.9, 1.04], [9.0, 0.02, E.snap], [9.26, 1.04, E.o], [31.3, 1.04], [31.42, 0.02, E.snap], [31.7, 1.04, E.o]], t);\\nconst up = T([[0, 0], [14.0, 0], [14.95, 14, E.io], [29.3, 14], [30.4, 0, E.io]], t);\\nconst low = T([[0, 0], [14.3, 0], [15.7, 42, E.io], [23.7, 42], [28.4, 42], [29.8, 0, E.io]], t);\\nconst ly = T([[0, 0], [19.3, 0], [21.9, 56, E.io], [26.6, 56], [27.5, 69, E.io]], t);\\nconst lx = T([[0, 0], [19.3, 0], [21.9, 8, E.io], [26.6, 8], [27.5, 2, E.io]], t);\\nconst fold = T([[0, 0], [26.75, 0], [27.55, 0.85, E.io]], t);\\nconst glow = T([[0, 0], [18.1, 0], [18.9, 0.7], [23.3, 0.7], [24.3, 0]], t);\\nconst onEye = t \\u003c 27.55;\\nconst st = { open, low, up, gy, gx: 0, brow: up * 0.45, lx, ly, fold, lrot: PA, glow, la: onEye ? 1 : 0, ls: T([[0, 1], [26.7, 1], [27.5, 0.82]], t) };\\nst.tt = t; fw.update(st, pop);\\nLh.update(t, t > 12 \\u0026\\u0026 t \\u003c 30.7 ? 1 : 0);\\nRh.update(t, t > 12 \\u0026\\u0026 t \\u003c 25.0 ? 1 : 0);\\nconst pq = T([[24.3, 380], [25.6, 70, E.io], [26.4, 0, E.io], [28.0, 0], [28.9, 62, E.io], [29.8, 62], [30.8, 400, E.i]], t);\\nconst pgap = T([[24.3, 52], [26.7, 52], [27.55, 8, E.io], [29.5, 8]], t);\\nconst pp = back(PP, PA, pq), sway = M.sin(t * 2.1) * 0.9;\\npin.set(pp[0] + sway, pp[1], PA, pgap, t > 24.2 \\u0026\\u0026 t \\u003c 31.0 ? 1 : 0);\\nconst dA = PA * M.PI \/ 180, hold = T([[27.5, 46], [29.0, 36]], t);\\nconst spriteOn = t >= 27.5 \\u0026\\u0026 t \\u003c 30.85;\\nlens.set(pp[0] + M.sin(dA) * hold, pp[1] - M.cos(dA) * hold, T([[0, 0.82], [28.0, 0.82], [29.2, 0.64]], t), 0.85, PA, spriteOn ? 1 : 0);\\nlabel.update(win(t, 18.4, 19.0, 23.2, 23.8));\\nconst s = t - 32.2, sp = win(t, 32.2, 33.0, 42.3, 43.0);\\nstore.setAttribute('display', sp \\u003c= 0 ? 'none' : 'inline');\\nstore.setAttribute('opacity', f(sp));\\nstore.setAttribute('transform', 'translate(0 ' + f((1 - E.o(M.min(1, sp * 1.6))) * 20) + ')');\\nconst lidR = E.io(cl((s - 4.7) \/ 1.0));\\nconst drop = E.i(cl((s - 3.0) \/ 0.55)), pl = cl((s - 3.55) \/ 1.1);\\ncs.update(lidR, 1, pl);\\nconst carried = s \\u003c 2.5, dp = carried ? 0 : drop;\\nconst q2 = T([[0, 380], [1.7, 0, E.io], [3.1, 0], [4.2, 380, E.i]], s), g2 = T([[0, 8], [2.4, 8], [3.0, 52, E.io]], s);\\nconst P2 = [500, 124], pp2 = [P2[0], P2[1] - q2];\\npin2.set(pp2[0], pp2[1] + M.sin(s * 2.3) * 0.8, 180, g2, s > 0.1 \\u0026\\u0026 s \\u003c 4.4 ? 1 : 0);\\nconst wellX = 500, wellY = 202, hold2 = 30;\\nconst unfold = 0.85 * (1 - E.io(cl((s - 2.4) \/ 0.6)));\\nconst lx2 = pp2[0], ly2 = carried ? pp2[1] + hold2 : (pp2[1] + hold2) + (wellY - (pp2[1] + hold2)) * dp;\\nconst sink = cl((s - 3.5) \/ 1.0);\\nlens2.set(lx2, ly2, (0.7 + 0.2 * E.io(cl((s - 2.4) \/ 0.6))) * (1 - 0.06 * sink), unfold, 0, s > 0.5 \\u0026\\u0026 s \\u003c 4.8 ? 1 - 0.55 * sink : 0);\\ncheck.update(cl((s - 6.0) \/ 0.5));\\nspark.update(t, win(t, 38.0, 38.4, 42.4, 42.9));\\nui.update(t);\\n},\\n};\\n},\\n};\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst C = VP.C, M = Math, E = VP.ease, win = VP.win, T = VP.track, f = v => M.round(v * 10) \/ 10, cl = VP.clamp;\\nconst STR = {\\nchip: 'SOFT LENSES \u00b7 SLIDE METHOD',\\nsteps: [\\n{ t0: 0.5,  t1: 7.5,  title: 'Wash and dry your hands', sub: 'Mild soap, then a lint-free towel' },\\n{ t0: 8.2,  t1: 12.6, title: 'Look toward your nose', sub: 'Keep your head straight' },\\n{ t0: 12.6, t1: 18.2, title: 'Open wide', sub: 'Hold your upper lid up, pull your lower lid down' },\\n{ t0: 18.2, t1: 25.2, title: 'Slide the lens out to the corner', sub: 'Finger flat, using the soft pad' },\\n{ t0: 25.2, t1: 28.3, title: 'Pinch gently at the corner', sub: 'Between the pads of thumb and finger' },\\n{ t0: 28.3, t1: 32.6, title: 'Lift the lens out', sub: 'It should come away folded, no tugging' },\\n{ t0: 33.4, t1: 40.4, title: 'Store it in fresh solution', sub: 'Rub and rinse first. Dailies? Just toss it' },\\n{ t0: 40.6, t1: 43.2, title: 'Now repeat with the other eye', sub: 'Same steps, same order', icon: '\u2713', color: '#7fcfae' },\\n],\\ntips: [{ t0: 1.2, t1: 6.6, x: 20, y: 76, w: 222, head: 'TIP', lines: ['Plug the sink drain', 'so a dropped lens', 'cannot escape.'] },\\n{ t0: 18.6, t1: 24.8, x: 20, y: 150, w: 224, head: 'TIP', lines: ['Keep the finger flat,', 'nail facing away', 'from your eye.'] }],\\n};\\nconst CURL = { ring: [0, 72, 94, 52], pinky: [0, 78, 98, 52] };\\nconst FIST = { middle: [0, 78, 98, 58], ring: [0, 84, 102, 62], pinky: [0, 88, 104, 62] };\\nconst FLAT = Object.assign({ pos: [0, 0], rot: [88, -4, 0], scale: 23.4, spread: 0.5, index: [-1, 6, 10, 6], middle: [2, 14, 24, 12], thumb: [-28, 30, -60, 30, 25], layers: {} }, CURL);\\nconst LPOSE = Object.assign({ pos: [0, 0], rot: [-135, -12, 0], scale: 23.4, spread: 0.4, index: [0, 8, 14, 8], thumb: [-20, 30, -60, 40, 40], layers: {} }, FIST);\\nconst PA = -34, PP = [486, 250];\\nconst back = (P, ang, q) => { const a = ang * M.PI \/ 180; return [P[0] - M.sin(a) * q, P[1] + M.cos(a) * q]; };\\nVP.videos.slide = {\\ntitle: 'How to remove soft contact lenses: the slide method',\\ndesc: 'Animated steps: wash and dry hands, look toward your nose, open the eyelids, slide the lens to the outer corner of the eye with the pad of the index finger, pinch it gently and lift it out, then store it in fresh solution.',\\nduration: 43.9, poster: 22.4, steps: STR.steps, tips: STR.tips,\\nbuild(svg, ctx) {\\nconst W = 800, H = 450, sk = ctx.skin;\\nconst bg = VP.bg(svg, W, H, this.duration);\\nconst art = VP.el('g', null, svg);\\nif (ctx.rough) ctx.rough.use(art);\\nconst wash = VP.washAct(art, ctx);\\nconst eyeAct = VP.el('g', null, art);\\nconst fw = VP.faceWindow(eyeAct, ctx, 428, 168, 162, 14);\\nconst EX = fw.ex, EY = fw.ey;\\nconst lens = VP.Lens(eyeAct, 63);\\nconst Lh = VP.HandActor(eyeAct, { mirror: false, skin: sk }, {\\npose: [[7, LPOSE]],\\ntg: { index: [[12.1, { x: 230, y: -30, w: 1 }], [13.4, { x: 384, y: 70, w: 1 }], [14.05, { x: 404, y: 104, w: 1 }, E.io], [14.95, { x: 404, y: 88, w: 1 }, E.io], [29.6, { x: 404, y: 88, w: 1 }], [30.9, { x: 230, y: -30, w: 1 }, E.io]] },\\nfree: [{ k: 'pos', i: 0, e: 0.6, w: 0.05 }, { k: 'pos', i: 1, e: 0.6, w: 0.05 }],\\n});\\nconst Rh = VP.HandActor(eyeAct, { mirror: true, skin: sk }, {\\npose: [[12, FLAT]],\\ntg: {\\nmiddle: [[12.0, { x: 930, y: 300, w: 1 }], [13.4, { x: 600, y: 300, w: 1 }], [14.3, { x: 400, y: 238, w: 1 }, E.io], [15.7, { x: 402, y: 272, w: 1 }, E.io], [19.6, { x: 402, y: 272, w: 1 }], [22.6, { x: 486, y: 276, w: 1 }, E.io], [24.0, { x: 486, y: 276, w: 1 }], [25.0, { x: 990, y: 300, w: 1 }, E.io]],\\nindex: [[12.0, { x: 950, y: 260, w: 0 }], [16.8, { x: 500, y: 150, w: 0 }], [17.8, { x: 440, y: 176, w: 1 }, E.io], [18.9, { x: 352, y: 186, w: 1 }, E.io], [19.6, { x: 352, y: 186, w: 1 }], [22.6, { x: 452, y: 196, w: 1 }, E.io], [24.0, { x: 452, y: 196, w: 1 }], [25.0, { x: 970, y: 230, w: 1 }, E.io]],\\n},\\n});\\nconst pin = VP.Pincer(eyeAct, { skin: sk, scale: 23.4 });\\nconst arrow = VP.Arrow(eyeAct, 'M440 104C480 84 540 84 578 104M558 90L580 105L556 116', C.coral, 6);\\nconst store = VP.el('g', null, art);\\nconst cs = VP.Case(store, 400, 196);\\nconst lens2 = VP.Lens(store, 40);\\nconst pin2 = VP.Pincer(store, { skin: sk, scale: 23.4 });\\nconst check = VP.Check(store, 610, 100, 40);\\nconst spark = VP.Sparkles(store, [[560, 60, 14], [660, 140, 12], [300, 70, 12], [640, 60, 10], [500, 300, 12]]);\\nconst ui = VP.UI(svg, W, H, { chip: STR.chip, steps: STR.steps, tips: STR.tips });\\nreturn {\\nupdate(t) {\\nbg.update(t);\\nif (ctx.rough) ctx.rough.tick(t);\\nwash.update(t);\\nconst pop = win(t, 7.3, 8.2, 32.7, 33.5);\\neyeAct.setAttribute('display', pop \\u003c= 0 ? 'none' : 'inline');\\nconst gx = T([[0, 0], [9.5, 0], [10.9, -38, E.io], [30.0, -38], [31.3, 0, E.io]], t);\\nconst open = T([[0, 1.04], [8.9, 1.04], [9.0, 0.02, E.snap], [9.26, 1.04, E.o], [31.6, 1.04], [31.72, 0.02, E.snap], [32.0, 1.04, E.o]], t);\\nconst up = T([[0, 0], [14.0, 0], [14.95, 14, E.io], [29.6, 14], [30.8, 0, E.io]], t);\\nconst low = T([[0, 0], [14.3, 0], [15.7, 38, E.io], [23.9, 38], [25.0, 30, E.io], [28.6, 30], [30.0, 0, E.io]], t);\\nconst lx = T([[0, 0], [18.9, 0], [22.6, 100, E.io], [26.9, 100], [27.9, 70, E.io]], t);\\nconst ly = T([[0, 0], [18.9, 0], [22.6, 14, E.io], [26.9, 14], [27.9, 30, E.io]], t);\\nconst fold = T([[0, 0], [27.05, 0], [27.9, 0.85, E.io]], t);\\nconst glow = 0;\\nconst onEye = t \\u003c 27.9;\\nconst st = { open, low, up, gy: 0, gx, brow: up * 0.45, lx, ly, fold, lrot: PA, glow, la: onEye ? 1 : 0, ls: T([[0, 1], [27.0, 1], [27.85, 0.82]], t), pullOut: 0 };\\nst.tt = t; fw.update(st, pop);\\nLh.update(t, t > 12 \\u0026\\u0026 t \\u003c 31.0 ? 1 : 0);\\nRh.update(t, t > 12 \\u0026\\u0026 t \\u003c 25.3 ? 1 : 0);\\nconst pq = T([[24.9, 380], [26.2, 70, E.io], [27.0, 0, E.io], [28.3, 0], [29.2, 66, E.io], [30.1, 66], [31.1, 400, E.i]], t);\\nconst pgap = T([[24.9, 52], [27.05, 52], [27.9, 8, E.io], [29.8, 8]], t);\\nconst pp = back(PP, PA, pq);\\npin.set(pp[0] + M.sin(t * 2.1) * 0.9, pp[1], PA, pgap, t > 24.8 \\u0026\\u0026 t \\u003c 31.3 ? 1 : 0);\\nconst dA = PA * M.PI \/ 180, hold = T([[27.9, 46], [29.2, 40]], t), spriteOn = t >= 27.9 \\u0026\\u0026 t \\u003c 31.15;\\nlens.set(pp[0] + M.sin(dA) * hold, pp[1] - M.cos(dA) * hold, T([[0, 0.82], [28.3, 0.82], [29.5, 0.64]], t), 0.85, PA, spriteOn ? 1 : 0);\\narrow.update(T([[0, 0], [19.8, 0], [21.0, 1]], t), win(t, 19.7, 20.3, 22.6, 23.3));\\nconst s = t - 32.9, sp = win(t, 32.9, 33.7, 43.0, 43.7);\\nstore.setAttribute('display', sp \\u003c= 0 ? 'none' : 'inline');\\nstore.setAttribute('opacity', f(sp));\\nstore.setAttribute('transform', 'translate(0 ' + f((1 - E.o(M.min(1, sp * 1.6))) * 20) + ')');\\ncs.update(E.io(cl((s - 4.7) \/ 1.0)), 1, cl((s - 3.55) \/ 1.1));\\nconst carried = s \\u003c 2.5, drop = E.i(cl((s - 3.0) \/ 0.55));\\nconst q2 = T([[0, 380], [1.7, 0, E.io], [3.1, 0], [4.2, 380, E.i]], s), g2 = T([[0, 8], [2.4, 8], [3.0, 52, E.io]], s);\\nconst pp2 = [500, 124 - q2];\\npin2.set(pp2[0], pp2[1] + M.sin(s * 2.3) * 0.8, 180, g2, s > 0.1 \\u0026\\u0026 s \\u003c 4.4 ? 1 : 0);\\nconst wellY = 202, sink = cl((s - 3.5) \/ 1.0), hold2 = 30;\\nconst unfold = 0.85 * (1 - E.io(cl((s - 2.4) \/ 0.6)));\\nlens2.set(pp2[0], carried ? pp2[1] + hold2 : (pp2[1] + hold2) + (wellY - (pp2[1] + hold2)) * drop,\\n(0.7 + 0.2 * E.io(cl((s - 2.4) \/ 0.6))) * (1 - 0.06 * sink), unfold, 0, s > 0.5 \\u0026\\u0026 s \\u003c 4.8 ? 1 - 0.55 * sink : 0);\\ncheck.update(cl((s - 6.0) \/ 0.5));\\nspark.update(t, win(t, 38.9, 39.3, 43.1, 43.6));\\nui.update(t);\\n},\\n};\\n},\\n};\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst C = VP.C, M = Math, E = VP.ease, win = VP.win, T = VP.track, f = v => M.round(v * 10) \/ 10, cl = VP.clamp;\\nconst STR = {\\nchip: 'RIGID LENSES \u00b7 BLINK METHOD',\\nsteps: [\\n{ t0: 0.5,  t1: 7.5,  title: 'Wash and dry your hands', sub: 'Mild soap, then a lint-free towel' },\\n{ t0: 8.2,  t1: 12.8, title: 'Look straight ahead', sub: 'Lean over a clean towel or soft surface' },\\n{ t0: 12.8, t1: 16.6, title: 'Place a finger at the outer corner', sub: 'Keep your eye wide open' },\\n{ t0: 16.6, t1: 21.4, title: 'Pull gently toward your ear', sub: 'Until your lids feel snug on the lens' },\\n{ t0: 21.4, t1: 25.3, title: 'Blink!', sub: 'The lens pops out onto the towel' },\\n{ t0: 26.0, t1: 33.0, title: 'Clean, rinse and store', sub: 'Use the solution your eye doctor recommends' },\\n{ t0: 33.2, t1: 35.8, title: 'Now repeat with the other eye', sub: 'Same steps, same order', icon: '\u2713', color: '#7fcfae' },\\n],\\ntips: [{ t0: 1.2, t1: 6.6, x: 20, y: 76, w: 222, head: 'TIP', lines: ['Cover the sink drain', 'with a clean towel', 'in case a lens drops.'] },\\n{ t0: 22.4, t1: 25.3, x: 20, y: 150, w: 226, head: 'STUCK?', lines: ['A small suction holder', 'can help. Ask your eye', 'doctor to show you.'] }],\\n};\\nconst CURL = { ring: [0, 72, 94, 52], pinky: [0, 78, 98, 52] };\\nconst FLAT = Object.assign({ pos: [0, 0], rot: [86, -6, 0], scale: 23.4, spread: 0.5, index: [-1, 8, 12, 8], middle: [2, 60, 80, 45], thumb: [-28, 30, -60, 30, 25], layers: {} }, CURL);\\nVP.videos.blink = {\\ntitle: 'How to remove rigid gas permeable (hard) contact lenses: the blink method',\\ndesc: 'Animated steps: wash and dry hands, lean over a towel, look straight ahead, place a finger at the outer corner of the eye, pull gently toward the ear and blink so the lens pops out, then clean and store it.',\\nduration: 36.4, poster: 20.2, steps: STR.steps, tips: STR.tips,\\nbuild(svg, ctx) {\\nconst W = 800, H = 450, sk = ctx.skin;\\nconst bg = VP.bg(svg, W, H, this.duration);\\nconst art = VP.el('g', null, svg);\\nif (ctx.rough) ctx.rough.use(art);\\nconst wash = VP.washAct(art, ctx);\\nconst eyeAct = VP.el('g', null, art);\\nconst fw = VP.faceWindow(eyeAct, ctx, 430, 172, 168, 12, -24);\\nconst EX = fw.ex, EY = fw.ey;\\nconst towel = VP.Towel(eyeAct, 470, 64);\\nconst lens = VP.Lens(eyeAct, 45, true);\\nconst arrow = VP.Arrow(eyeAct, 'M560 118C590 96 622 96 650 116M632 100L652 116L628 124', C.coral, 6);\\nconst pop = VP.Sparkles(eyeAct, [[404, 168, 14], [462, 154, 12], [436, 214, 11]]);\\nconst Rh = VP.HandActor(eyeAct, { mirror: true, skin: sk }, {\\npose: [[12, FLAT]],\\ntg: {\\nindex: [[12.0, { x: 960, y: 230, w: 1 }], [13.4, { x: 660, y: 200, w: 1 }, E.io], [14.6, { x: 568, y: 186, w: 1 }, E.io], [16.6, { x: 568, y: 186, w: 1 }], [19.0, { x: 604, y: 176, w: 1 }, E.io], [22.0, { x: 604, y: 176, w: 1 }], [22.8, { x: 640, y: 190, w: 1 }, E.io], [24.4, { x: 900, y: 250, w: 1 }, E.i]],\\n},\\nfree: [{ k: 'pos', i: 0, e: 0.6, w: 0.05 }, { k: 'pos', i: 1, e: 0.6, w: 0.05 }, { k: 'index', i: 0, e: 0.5, w: 7, lo: -12, hi: 12 }, { k: 'index', i: 1, e: 0.5, w: 4, lo: 0, hi: 60 }],\\n});\\nconst store = VP.el('g', null, art);\\nconst cs = VP.Case(store, 400, 196);\\nconst lens2 = VP.Lens(store, 30, true);\\nconst pin2 = VP.Pincer(store, { skin: sk, scale: 23.4 });\\nconst check = VP.Check(store, 610, 100, 40);\\nconst spark = VP.Sparkles(store, [[560, 60, 14], [660, 140, 12], [300, 70, 12], [640, 60, 10], [500, 300, 12]]);\\nconst ui = VP.UI(svg, W, H, { chip: STR.chip, steps: STR.steps, tips: STR.tips });\\nconst TB = 22.0;\\nreturn {\\nupdate(t) {\\nbg.update(t);\\nif (ctx.rough) ctx.rough.tick(t);\\nwash.update(t);\\nconst popK = win(t, 7.3, 8.2, 25.0, 25.8);\\neyeAct.setAttribute('display', popK \\u003c= 0 ? 'none' : 'inline');\\nconst open = T([[0, 1.1], [9.4, 1.1], [9.5, 0.02, E.snap], [9.78, 1.1, E.o], [TB - 0.05, 1.1], [TB + 0.03, 0.0, E.snap], [TB + 0.36, 1.1, E.o], [TB + 0.9, 1.1]], t);\\nconst pullOut = T([[0, 0], [15.0, 0], [18.6, 34, E.io], [TB + 0.02, 34], [TB + 0.5, 0, E.o]], t);\\nconst squeeze = T([[0, 0], [17.0, 0], [19.6, 0.85, E.io], [TB, 0.85], [TB + 0.5, 0, E.o]], t);\\nconst low = 0;\\nconst st = { open, low, up: 0, gx: 0, gy: 0, pullOut, squeeze, rigid: 1, la: t \\u003c TB + 0.02 ? 1 : 0, ls: 1, brow: 0 };\\nst.tt = t; fw.update(st, popK);\\nconst tk = E.o(cl((t - 8.6) \/ 0.9)) * (1 - cl((t - 25.0) \/ 0.8));\\ntowel.update(EX + 22, 352 - (1 - tk) * 90 + (1 - tk) * 0, -2.5, tk);\\nRh.update(t, t > 12 \\u0026\\u0026 t \\u003c 25.0 ? 1 : 0);\\nconst u = t - TB;\\nif (u >= 0 \\u0026\\u0026 t \\u003c 25.9) {\\nconst g = 900, v0 = -150, x0 = EX, y0 = EY, ground = 336;\\nconst tf = (-v0 + M.sqrt(v0 * v0 + 2 * g * (ground - y0))) \/ g;\\nlet x, y, rot, sc = 0.72 * 1, a = 1;\\nif (u \\u003c tf) { x = x0 + 34 * (u \/ tf); y = y0 + v0 * u + 0.5 * g * u * u; rot = 260 * (u \/ tf); }\\nelse { const b = cl((u - tf) \/ 0.34); x = x0 + 34 + 10 * b; y = ground - 24 * M.sin(M.PI * b) * (1 - b * 0.4); rot = 260 + 40 * b; }\\nlens.set(x, y, sc, 0, rot, 1);\\npop.update(t, win(t, TB - 0.02, TB + 0.1, TB + 0.5, TB + 0.8));\\n} else { lens.set(0, 0, 1, 0, 0, 0); pop.update(t, 0); }\\narrow.update(T([[0, 0], [16.9, 0], [18.0, 1]], t), win(t, 16.8, 17.4, 21.6, 22.0));\\nconst s = t - 25.5, sp = win(t, 25.5, 26.3, 35.4, 36.0);\\nstore.setAttribute('display', sp \\u003c= 0 ? 'none' : 'inline');\\nstore.setAttribute('opacity', f(sp));\\nstore.setAttribute('transform', 'translate(0 ' + f((1 - E.o(M.min(1, sp * 1.6))) * 20) + ')');\\ncs.update(E.io(cl((s - 4.7) \/ 1.0)), 1, cl((s - 3.55) \/ 1.1));\\nconst carried = s \\u003c 2.5, drop = E.i(cl((s - 3.0) \/ 0.55));\\nconst q2 = T([[0, 380], [1.7, 0, E.io], [3.1, 0], [4.2, 380, E.i]], s), g2 = T([[0, 8], [2.4, 8], [3.0, 52, E.io]], s);\\nconst pp2 = [500, 124 - q2], sink = cl((s - 3.5) \/ 1.0), hold2 = 22;\\npin2.set(pp2[0], pp2[1] + M.sin(s * 2.3) * 0.8, 180, g2, s > 0.1 \\u0026\\u0026 s \\u003c 4.4 ? 1 : 0);\\nlens2.set(pp2[0], carried ? pp2[1] + hold2 : (pp2[1] + hold2) + (202 - (pp2[1] + hold2)) * drop, 0.8 * (1 - 0.06 * sink), 0, 0, s > 0.5 \\u0026\\u0026 s \\u003c 4.8 ? 1 - 0.55 * sink : 0);\\ncheck.update(cl((s - 6.0) \/ 0.5));\\nspark.update(t, win(t, 31.6, 32.0, 35.5, 36.0));\\nui.update(t);\\n},\\n};\\n},\\n};\\n})(window.VP);\\n(function (VP) {\\n'use strict';\\nconst C = VP.C, M = Math, E = VP.ease, win = VP.win, T = VP.track, f = v => M.round(v * 10) \/ 10, cl = VP.clamp;\\nconst STR = {\\nchip: 'STUCK OR DRY LENS',\\nsteps: [\\n{ t0: 0.6,  t1: 5.6,  title: 'Lens feels stuck or dry?', sub: 'Do not pull it. Wash and dry your hands first', icon: '!' },\\n{ t0: 5.9,  t1: 12.4, title: 'Add rewetting drops or saline', sub: 'Sterile products only, never tap water or saliva' },\\n{ t0: 12.7, t1: 17.4, title: 'Blink a few times', sub: 'Let the lens rehydrate and loosen' },\\n{ t0: 17.7, t1: 24.4, title: 'Gently massage your closed lid', sub: 'Light circles with a finger pad, never a nail' },\\n{ t0: 24.7, t1: 29.7, title: 'Now remove it as usual', sub: 'Slide it to the white of the eye, then pinch' },\\n{ t0: 30.0, t1: 35.4, title: 'Still stuck? Do not force it', sub: 'Red or sore eye? See your eye care professional', icon: '+' },\\n],\\ntips: [{ t0: 6.6, t1: 12.2, x: 574, y: 150, w: 216, head: 'TIP', lines: ['Sterile saline or lens', 'rewetting drops only.', 'Never tap water.'] }],\\n};\\nconst blink = (t, base, dur) => [[t - 0.08, base], [t + 0.03, 0.04, E.snap], [t + (dur || 0.3), base, E.o]];\\nconst LPOSE = Object.assign({ pos: [0, 0], rot: [-135, -12, 0], scale: 23.4, spread: 0.4, index: [0, 8, 14, 8], thumb: [-20, 30, -60, 40, 40], layers: {},\\nmiddle: [0, 78, 98, 58], ring: [0, 84, 102, 62], pinky: [0, 88, 104, 62] });\\nVP.videos.stuck = {\\ntitle: 'What to do if a soft contact lens feels stuck or dry',\\ndesc: 'Animated steps: do not pull or pinch a stuck lens; wash your hands, add sterile rewetting drops or saline, blink several times, gently massage the closed eyelid, then remove it as usual; if it is still stuck or your eye is red or sore, stop and see an eye care professional.',\\nduration: 36.2, poster: 20.4, steps: STR.steps, tips: STR.tips,\\nbuild(svg, ctx) {\\nconst W = 800, H = 450, sk = ctx.skin;\\nconst bg = VP.bg(svg, W, H, this.duration);\\nconst art = VP.el('g', null, svg);\\nif (ctx.rough) ctx.rough.use(art);\\nconst eyeAct = VP.el('g', null, art);\\nconst fw = VP.faceWindow(eyeAct, ctx, 428, 168, 162, 14);\\nconst EX = fw.ex, EY = fw.ey;\\nconst ghost = VP.Lens(eyeAct, 63);\\nconst rings = [VP.Ring(eyeAct), VP.Ring(eyeAct), VP.Ring(eyeAct)];\\nconst drops = [VP.Drop(eyeAct), VP.Drop(eyeAct), VP.Drop(eyeAct)];\\nconst bottle = VP.Dropper(eyeAct);\\nconst swirl = VP.Swirl(eyeAct);\\nconst Lh = VP.HandActor(eyeAct, { mirror: false, skin: sk }, {\\npose: [[16, LPOSE]],\\ntg: { index: [[16.6, { x: 230, y: -30, w: 1 }], [17.6, { x: 396, y: 120, w: 1 }, E.io], [18.4, { x: 414, y: 190, w: 1 }, E.io], [23.6, { x: 414, y: 190, w: 1 }], [24.8, { x: 230, y: -30, w: 1 }, E.io]] },\\nfree: VP.FREE_POS,\\n});\\nconst bang = VP.Badge(eyeAct, 640, 92, 'bang', C.coral);\\nconst cross = VP.Badge(eyeAct, 640, 92, 'cross', '#ff8f8f');\\nconst ui = VP.UI(svg, W, H, { chip: STR.chip, steps: STR.steps, tips: STR.tips });\\nconst DT = [8.0, 9.1, 10.2];\\nconst NZ = [508, 82], TILT = -125;\\nreturn {\\nupdate(t) {\\nbg.update(t);\\nif (ctx.rough) ctx.rough.tick(t);\\nconst pop = win(t, 0.3, 1.1, 35.0, 35.8);\\neyeAct.setAttribute('display', pop \\u003c= 0 ? 'none' : 'inline');\\nlet openKeys = [[0, 0.86], [5.5, 0.86], [6.1, 1.06]];\\nDT.forEach(d => { openKeys = openKeys.concat(blink(d + 0.45, 1.06)); });\\n[13.4, 14.5, 15.6].forEach(b => { openKeys = openKeys.concat(blink(b, 1.06, 0.36)); });\\nopenKeys = openKeys.concat([[17.6, 1.06], [17.95, 0.0, E.io], [24.1, 0.0], [24.55, 1.06, E.o]], blink(29.85, 1.06), [[35, 1.06]]);\\nconst open = T(openKeys, t);\\nconst red = T([[0, 0.55], [5.6, 0.6], [8.0, 0.6], [12, 0.3], [16, 0.12], [24, 0.0], [29.9, 0.0], [31.6, 0.8, E.io], [35, 0.8]], t);\\nconst gy = T([[0, 0], [6.2, 0], [7.2, -24, E.io], [11.6, -24], [12.6, 0, E.io]], t);\\nconst lx = T([[0, -14], [11, -14], [16, -8], [24.4, 0, E.io], [29.85, 0], [29.95, -14]], t);\\nconst ly = T([[0, 12], [11, 12], [16, 6], [24.4, 0, E.io], [25.6, 0], [27.4, 34, E.io], [29.85, 34], [29.95, 12]], t);\\nconst st = { open, red, gy, lx, ly, la: 1, low: 0, up: 0, brow: open \\u003c 0.5 ? 0 : 0 };\\nst.tt = t; fw.update(st, pop);\\nconst mk = win(t, 18.7, 19.3, 23.3, 24.0);\\nconst ph = (t - 18.6) * M.PI * 2 \/ 1.3, wob = win(t, 18.6, 19.0, 23.6, 24.0);\\nconst ghostFree = T([[0, 0], [22.0, 0], [24.0, 12, E.io]], t);\\nghost.set(EX + M.cos(ph) * 5 * wob + ghostFree, EY + 12 + M.sin(ph) * 4 * wob, 1, 0, 0, 0.5 * mk);\\nconst cx = 414 + M.cos(ph) * 10 * wob, cy = 190 + M.sin(ph) * 8 * wob;\\nconst lt = M.max(0, t - 18.6);\\nLh.hand.opts.mirror = false;\\nLh.update(t, t > 16.5 \\u0026\\u0026 t \\u003c 25.0 ? 1 : 0);\\nswirl.update(414, 186, t, win(t, 19.2, 19.8, 22.9, 23.5) * 0.9);\\nconst bIn = E.io(cl((t - 6.0) \/ 0.9)) * (1 - E.io(cl((t - 11.2) \/ 0.9)));\\nconst squeeze = DT.reduce((a, d) => a + M.max(0, 1 - M.abs(t - (d - 0.5)) \/ 0.16), 0);\\nconst bx = 790 + (NZ[0] - 790) * bIn, by = -70 + (NZ[1] + 70) * bIn;\\nbottle.g.setAttribute('display', bIn \\u003c= 0 ? 'none' : 'inline');\\nbottle.update(bx, by, TILT * bIn, bIn);\\nbottle.g.setAttribute('transform', 'translate(' + f(bx) + ' ' + f(by) + ') rotate(' + f(TILT * bIn) + ') scale(' + f(0.8 * (1 - squeeze * 0.06)) + ' ' + f(0.8 * (1 + squeeze * 0.05)) + ')');\\nDT.forEach((d, i) => {\\nconst u = cl((t - (d - 0.5)) \/ 0.5), tip = [NZ[0] - 66, NZ[1] + 48];\\nconst y = tip[1] + (EY - 6 - tip[1]) * E.i(u), vis = u > 0 \\u0026\\u0026 u \\u003c 1 ? 1 : 0;\\ndrops[i].set(tip[0] + 3 * u, y, 0.85 + 0.15 * u, vis);\\nrings[i].set(EX + 6, EY + 12, cl((t - d) \/ 0.55), 42);\\n});\\nbang.update(cl((t - 0.9) \/ 0.5) * (1 - cl((t - 5.3) \/ 0.3)));\\ncross.update(cl((t - 30.8) \/ 0.5) * (1 - cl((t - 34.7) \/ 0.3)));\\nui.update(t);\\n},\\n};\\n},\\n};\\n})(window.VP);\\nif(document.readyState===\\\"loading\\\")document.addEventListener(\\\"DOMContentLoaded\\\",VP.auto);else VP.auto();\\n})();\\n\")()<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Taking out contacts shouldn\u2019t feel like a wrestling match. Watch four short animated guides for soft lenses, long nails, stuck lenses and rigid lenses.<\/p>\n","protected":false},"author":3,"featured_media":909,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[5],"tags":[11,16],"semantictags":[],"class_list":["post-908","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tips","tag-contact-lenses","tag-eye-health"],"_links":{"self":[{"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/posts\/908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/comments?post=908"}],"version-history":[{"count":6,"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/posts\/908\/revisions"}],"predecessor-version":[{"id":916,"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/posts\/908\/revisions\/916"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/media\/909"}],"wp:attachment":[{"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/media?parent=908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/categories?post=908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/tags?post=908"},{"taxonomy":"semantictags","embeddable":true,"href":"https:\/\/www.visionpros.ca\/pro\/wp-json\/wp\/v2\/semantictags?post=908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}