{"id":16,"date":"2026-09-25T21:53:17","date_gmt":"2026-09-25T21:53:17","guid":{"rendered":"https:\/\/mapp.io\/?page_id=16"},"modified":"2026-09-25T22:22:59","modified_gmt":"2026-09-25T22:22:59","slug":"mapp-io-home-we-make-playable-ads","status":"publish","type":"page","link":"https:\/\/mapp.io\/","title":{"rendered":"mApp.io Home \u2022 We make playable ads"},"content":{"rendered":"<div id=\"cs-content\" class=\"cs-content\"><div class=\"x-section e16-e1 mg-0\"><div class=\"x-row x-container max width e16-e2 mg-1 mg-2 mg-3 mg-b mg-c\"><div class=\"x-row-inner\"><div class=\"x-col e16-e3 mg-s mg-t mg-u mg-v mg-w mg-x mg-y\"><div class=\"x-text x-content e16-e4 mg-1d mg-1e mg-1f mg-1g mg-1h mg-1i\"><span class=\"chip\">Playable ad studio<\/span><span><\/span><\/div><div class=\"x-text x-text-headline e16-e5 mg-1s mg-1t mg-1u mg-1v mg-1w mg-1x\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">People skip ads. Nobody skips a game.<\/h1>\n<span class=\"x-text-content-text-subheadline\"><span>mApp builds <\/span><strong>playable ads<\/strong><span> for your business \u2014 short, custom mini-games that promote your product using high engagement.<\/span><\/span><\/div><\/div><\/div><div class=\"x-div e16-e6 mg-2e\"><a class=\"x-anchor x-anchor-button e16-e7 mg-2f mg-2g mg-2h mg-2i mg-2j\" tabindex=\"0\" href=\"https:\/\/calendly.com\/joab-mapp\/30min\" target=\"_blank\" rel=\"noopener noreferrer\"><div class=\"x-anchor-content\"><div class=\"x-anchor-text\"><span class=\"x-anchor-text-primary\">Book A 30-Minute Call<\/span><\/div><\/div><span class=\"x-new-tab-notice\">(opens in a new tab)<\/span><\/a><a class=\"x-anchor x-anchor-button e16-e8 mg-2f mg-2h mg-2j mg-2k\" tabindex=\"0\" href=\"#\"><div class=\"x-anchor-content\"><div class=\"x-anchor-text\"><span class=\"x-anchor-text-primary\">Email Us<\/span><\/div><\/div><\/a><\/div><div class=\"x-text x-content e16-e9 mg-1e mg-1j mg-1k mg-1l mg-1m mg-1n mg-1o\"><div class=\"hero-copy\">\n<p class=\"fine\">Ideal for restaurants, dealerships, retail, gyms, clinics, law offices and universities.<\/p>\n\n<\/div><\/div><\/div><div class=\"x-col e16-e10 mg-w mg-x mg-y mg-z\"><div style=\"max-width:420px;margin:0 auto;\">\n  <div style=\"position:relative;width:100%;padding-top:177.78%;border-radius:18px;overflow:hidden;box-shadow:0 10px 30px rgba(43,18,8,.18);background:#F7EAD3;\">\n    <iframe\n      src=\"https:\/\/playables.ai\/view\/slice-master\/\"\n      title=\"Slice Master\"\n      loading=\"eager\"\n      allow=\"autoplay; fullscreen\"\n      onload=\"var c=this.nextElementSibling;setTimeout(function(){c.style.opacity='0';setTimeout(function(){c.style.display='none';},400);},2000);\"\n      style=\"position:absolute;inset:0;width:100%;height:100%;border:0;\"\n      scrolling=\"no\"><\/iframe>\n    <div style=\"position:absolute;inset:0;background:#F7EAD3;display:flex;align-items:center;justify-content:center;transition:opacity .4s ease;font:600 17px system-ui,-apple-system,sans-serif;color:#A67C52;letter-spacing:.04em;\">\n      Loading\u2026\n    <\/div>\n  <\/div>\n<\/div><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e12 mg-1 mg-3 mg-4 mg-5 mg-b mg-d\"><div class=\"x-row-inner\"><div class=\"x-col e16-e13 mg-s mg-t mg-u mg-v mg-w mg-x mg-y\"><div class=\"x-text x-content e16-e14 mg-1d mg-1e mg-1f mg-1g mg-1h mg-1i\"><span class=\"chip\">Playable ad studio<\/span><span><\/span><\/div><div class=\"x-text x-text-headline e16-e15 mg-1s mg-1u mg-1y mg-1z mg-20 mg-21\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h2 class=\"x-text-content-text-primary\">An ad they play, not an ad they wait out.<\/h2>\n<\/div><\/div><\/div><\/div><div class=\"x-col e16-e16 mg-s mg-t mg-v mg-w mg-x mg-y mg-10\"><div class=\"x-text x-content e16-e17 mg-1e mg-1g mg-1i mg-1j mg-1k mg-1l mg-1p\"><div class=\"hero-copy\">\n<p class=\"fine\">A playable ad is a 15-to-30 second mini-game that runs inside the apps and games people already use. They tap, they play, they win something real: a coupon, an offer, a glimpse at your latest deals.<\/p>\n<p class=\"fine\">You get the attention a video ad has to beg for.<\/p>\n<\/div><\/div><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e18 mg-1 mg-3 mg-5 mg-6 mg-7 mg-b mg-e\"><div class=\"x-row-inner\"><div class=\"x-col e16-e19 mg-s mg-t mg-u mg-w mg-11 mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e20 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">Built around your offer<\/h1>\n<span class=\"x-text-content-text-subheadline\">Stack the burger. Park the car. Beat the clock. The mechanic comes out of what you actually sell.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e21 mg-s mg-t mg-u mg-w mg-11 mg-12 mg-13 mg-15\"><div class=\"x-text x-text-headline e16-e22 mg-1s mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25 mg-26 mg-27\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">Something to gain<\/h1>\n<span class=\"x-text-content-text-subheadline\">Every game finishes on a real reward, a code, a coupon, a landing page with the latest deals.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e23 mg-w mg-12 mg-13 mg-16\"><div class=\"x-text x-text-headline e16-e24 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">Runs where people already are<\/h1>\n<span class=\"x-text-content-text-subheadline\">Inside mobile games, on social, on your own site, on a QR code in the window. One game, every channel.<\/span><\/div><\/div><\/div><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e25 mg-1 mg-3 mg-5 mg-8 mg-b mg-f\"><div class=\"x-row-inner\"><div class=\"x-col e16-e26 mg-s mg-w mg-x mg-y mg-10 mg-11 mg-17\"><span class=\"x-image e16-e27 mg-2n\"><img decoding=\"async\" src=\"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/meta.png\" width=\"711\" height=\"300\" alt=\"Image\" loading=\"lazy\"><\/span><span class=\"x-image e16-e28 mg-2n\"><img decoding=\"async\" src=\"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/app-lovin.png\" width=\"711\" height=\"300\" alt=\"Image\" loading=\"lazy\"><\/span><span class=\"x-image e16-e29 mg-2n\"><img decoding=\"async\" src=\"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/google-ads.png\" width=\"711\" height=\"300\" alt=\"Image\" loading=\"lazy\"><\/span><span class=\"x-image e16-e30 mg-2n\"><img decoding=\"async\" src=\"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/tiktok.png\" width=\"711\" height=\"300\" alt=\"Image\" loading=\"lazy\"><\/span><\/div><\/div><\/div><\/div><div class=\"x-section e16-e31 mg-0\" id=\"work\"><div class=\"x-row x-container max width e16-e32 mg-1 mg-2 mg-3 mg-b mg-g\"><div class=\"x-row-inner\"><div class=\"x-col e16-e33 mg-s mg-t mg-u mg-v mg-w mg-x mg-18\"><div class=\"x-text x-content e16-e34 mg-1d mg-1e mg-1f mg-1g mg-1h mg-1i\"><p><span class=\"chip\">Selected Work<\/span><\/p><\/div><div class=\"x-text x-text-headline e16-e35 mg-1s mg-1u mg-1y mg-1z mg-20 mg-21\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h2 class=\"x-text-content-text-primary\">Games We've Built<\/h2>\n<\/div><\/div><\/div><\/div><div class=\"x-col e16-e36 mg-s mg-t mg-v mg-w mg-x mg-y mg-10\"><div class=\"x-text x-content e16-e37 mg-1e mg-1g mg-1i mg-1j mg-1k mg-1l mg-1p\"><div class=\"hero-copy\">\n<div class=\"sec-head\">\n<p class=\"sub\">A few playable ads made for businesses like yours. Click one to play it yourself &mdash;no download, no signup.<\/p>\n<\/div>\n<\/div><\/div><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e38 mg-1 mg-3 mg-5 mg-6 mg-b mg-h\"><div class=\"x-row-inner\"><div class=\"x-col e16-e39 mg-w mg-x mg-y mg-z\"><div style=\"max-width:420px;margin:0 auto;\">\n  <div style=\"position:relative;width:100%;padding-top:177.78%;border-radius:18px;overflow:hidden;box-shadow:0 10px 30px rgba(43,18,8,.18);background:#F7EAD3;\">\n    <iframe\n      src=\"https:\/\/playables.ai\/view\/slice-master\/\"\n      title=\"Slice Master\"\n      loading=\"eager\"\n      allow=\"autoplay; fullscreen\"\n      onload=\"var c=this.nextElementSibling;setTimeout(function(){c.style.opacity='0';setTimeout(function(){c.style.display='none';},400);},2000);\"\n      style=\"position:absolute;inset:0;width:100%;height:100%;border:0;\"\n      scrolling=\"no\"><\/iframe>\n    <div style=\"position:absolute;inset:0;background:#F7EAD3;display:flex;align-items:center;justify-content:center;transition:opacity .4s ease;font:600 17px system-ui,-apple-system,sans-serif;color:#A67C52;letter-spacing:.04em;\">\n      Loading\u2026\n    <\/div>\n  <\/div>\n<\/div><\/div><div class=\"x-col e16-e41 mg-w mg-x mg-y mg-z\"><div style=\"max-width:420px;margin:0 auto;\">\n  <div style=\"position:relative;width:100%;padding-top:177.78%;border-radius:18px;overflow:hidden;box-shadow:0 10px 30px rgba(4,6,10,.35);background:#0F1319;\">\n    <iframe\n      src=\"https:\/\/playables.ai\/view\/payne-highway-dash\/\"\n      title=\"Autogroup Sample \u2014 Highway Dash\"\n      loading=\"eager\"\n      allow=\"autoplay; fullscreen\"\n      onload=\"var c=this.nextElementSibling;setTimeout(function(){c.style.opacity='0';setTimeout(function(){c.style.display='none';},400);},2000);\"\n      style=\"position:absolute;inset:0;width:100%;height:100%;border:0;\"\n      scrolling=\"no\"><\/iframe>\n    <div style=\"position:absolute;inset:0;background:#0F1319;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;transition:opacity .4s ease;font:600 15px system-ui,-apple-system,sans-serif;color:#C9D0D8;letter-spacing:.22em;text-transform:uppercase;\">\n      Loading\n      <div style=\"width:64px;height:3px;border-radius:2px;background:#E4002B;\"><\/div>\n    <\/div>\n  <\/div>\n<\/div><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e43 mg-1 mg-3 mg-5 mg-7 mg-9 mg-b mg-i\"><div class=\"x-row-inner\"><div class=\"x-col e16-e44 mg-w mg-x mg-y mg-z\"><!-- ======================================================================\n     PERFECT POUR \u2014 inline embed\n     Paste this whole block into a Cornerstone \"Raw Content\" element.\n     Everything is scoped to #cfEmbed; nothing touches <html> or <body>.\n     To reskin for a client, edit the CONFIG block at the top of the\n     script \u2014 shop name, city, prize, code prefix, address, logo.\n     One instance per page.\n     ====================================================================== -->\n\n<div id=\"cfEmbed\">\n  <div class=\"cf-frame\">\n    <div class=\"cf-stage\" data-cf=\"stage\" tabindex=\"0\"\n         aria-label=\"Perfect Pour. Press and hold, or hold the space bar, to pour.\">\n      <canvas data-cf=\"canvas\"><\/canvas>\n\n      <div class=\"cf-hud\" data-cf=\"hud\" hidden>\n        <div>\n          <div class=\"cf-kicker\" data-cf=\"drinkNo\">Drink 1 of 3<\/div>\n          <div class=\"cf-drink\" data-cf=\"drinkName\">Cortado<\/div>\n        <\/div>\n        <div class=\"cf-steps\" data-cf=\"steps\"><\/div>\n      <\/div>\n\n      <div class=\"cf-hint\" data-cf=\"hint\" hidden>Hold anywhere to pour.<br>Let go on the line.<\/div>\n      <div class=\"cf-pop\" data-cf=\"pop\" aria-live=\"polite\"><\/div>\n\n      <div class=\"cf-veil\" data-cf=\"start\">\n        <img class=\"cf-logo\" data-cf=\"logo\" alt=\"\" hidden>\n        <div class=\"cf-stamp\" data-cf=\"stampStart\"><\/div>\n        <h3 class=\"cf-h1\">Perfect<br>Pour<\/h3>\n        <p class=\"cf-p\">Three drinks. Hold to pour, let go on the line. Pour well and the pastry's on us.<\/p>\n        <button class=\"cf-btn\" type=\"button\" data-cf=\"go\">Start pouring<\/button>\n      <\/div>\n\n      <div class=\"cf-veil\" data-cf=\"end\" hidden>\n        <h3 class=\"cf-h2\" data-cf=\"verdict\">Latte artist.<\/h3>\n        <p class=\"cf-score\" data-cf=\"scoreLine\"><\/p>\n        <div class=\"cf-coupon\">\n          <img class=\"cf-logo-sm\" data-cf=\"logoCoupon\" alt=\"\" hidden>\n          <div class=\"cf-what\" data-cf=\"prize\"><\/div>\n          <div class=\"cf-code\" data-cf=\"code\"><\/div>\n          <div class=\"cf-fine\" data-cf=\"fine\"><\/div>\n        <\/div>\n        <a class=\"cf-btn\" data-cf=\"directions\" href=\"#\" target=\"_blank\" rel=\"noopener\">Get directions<\/a>\n        <button class=\"cf-linkish\" type=\"button\" data-cf=\"again\">Play again<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<style>\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Fraunces:opsz,wght,SOFT@9..144,400..900,0..100&display=swap');\n\n#cfEmbed{\n  --cf-enamel:#9DBFAC; --cf-ink:#1F2A24; --cf-cream:#F6EFE3;\n  --cf-accent:#E4572E; --cf-btn:#C4441F; --cf-btn-edge:#8E2F14;\n  --cf-font:Fraunces,Georgia,'Times New Roman',serif;\n  width:100%;\n  max-width:min(420px, 44vh);\n  margin:0 auto;\n}\n#cfEmbed *{box-sizing:border-box}\n#cfEmbed .cf-frame{position:relative;width:100%;padding-top:177.78%}\n#cfEmbed .cf-stage{\n  position:absolute;top:0;left:0;right:0;bottom:0;\n  background:var(--cf-enamel);border-radius:18px;overflow:hidden;\n  font-family:var(--cf-font);font-variation-settings:\"SOFT\" 100;line-height:1.2;\n  touch-action:manipulation;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;\n  outline:none;\n}\n#cfEmbed .cf-stage.is-playing{touch-action:none}\n#cfEmbed .cf-stage:focus-visible{box-shadow:inset 0 0 0 3px var(--cf-accent)}\n#cfEmbed canvas{position:absolute;top:0;left:0;width:100%;height:100%;display:block}\n\n#cfEmbed .cf-hud{\n  position:absolute;top:0;left:0;right:0;z-index:2;pointer-events:none;\n  display:flex;justify-content:space-between;align-items:flex-start;gap:10px;\n  padding:16px 16px 0;color:var(--cf-ink);\n}\n#cfEmbed .cf-hud[hidden]{display:none}\n#cfEmbed .cf-kicker{font-size:11px;font-weight:600;opacity:.7}\n#cfEmbed .cf-drink{font-size:27px;font-weight:800;letter-spacing:-.02em;line-height:1;margin-top:3px}\n#cfEmbed .cf-steps{display:flex;gap:4px;flex-wrap:wrap;justify-content:flex-end;max-width:160px;padding-top:2px}\n#cfEmbed .cf-step{\n  font-size:11px;font-weight:700;padding:4px 8px;border-radius:99px;\n  border:1.5px solid rgba(31,42,36,.28);color:rgba(31,42,36,.5);\n}\n#cfEmbed .cf-step.is-now{border-color:var(--cf-ink);color:var(--cf-ink);background:rgba(246,239,227,.55)}\n#cfEmbed .cf-step.is-done{background:var(--cf-ink);border-color:var(--cf-ink);color:var(--cf-cream)}\n\n#cfEmbed .cf-hint{\n  position:absolute;left:0;right:0;top:78%;z-index:2;pointer-events:none;\n  text-align:center;font-size:16px;font-weight:600;line-height:1.35;color:var(--cf-ink);opacity:.8;\n}\n#cfEmbed .cf-hint[hidden]{display:none}\n#cfEmbed .cf-pop{\n  position:absolute;left:0;right:0;top:79%;z-index:2;pointer-events:none;\n  text-align:center;font-size:30px;font-weight:900;letter-spacing:-.02em;color:var(--cf-ink);\n  opacity:0;\n}\n#cfEmbed .cf-pop.is-best{color:var(--cf-btn)}\n#cfEmbed .cf-pop.is-on{animation:cfPop .8s cubic-bezier(.16,1,.3,1) both}\n@keyframes cfPop{\n  0%{opacity:0;transform:translateY(8px) scale(.92)}\n  18%{opacity:1;transform:none}\n  70%{opacity:1}\n  100%{opacity:0;transform:translateY(-6px)}\n}\n\n#cfEmbed .cf-veil{\n  position:absolute;top:0;left:0;right:0;bottom:0;z-index:3;\n  display:flex;flex-direction:column;align-items:center;justify-content:center;\n  text-align:center;gap:16px;padding:28px 24px;\n  background:rgba(31,42,36,.86);color:var(--cf-cream);\n}\n#cfEmbed .cf-veil[hidden]{display:none}\n#cfEmbed .cf-stamp{font-size:11px;font-weight:600;letter-spacing:.12em;opacity:.7;margin:0}\n#cfEmbed .cf-h1{margin:0;font-size:52px;font-weight:900;letter-spacing:-.035em;line-height:.9;color:var(--cf-cream)}\n#cfEmbed .cf-h2{margin:0;font-size:36px;font-weight:900;letter-spacing:-.03em;line-height:.95;color:var(--cf-cream)}\n#cfEmbed .cf-p{margin:0;font-size:15px;line-height:1.45;max-width:26ch;opacity:.85;color:var(--cf-cream)}\n#cfEmbed .cf-score{margin:-6px 0 0;font-size:13px;font-weight:600;opacity:.7;color:var(--cf-cream)}\n\n#cfEmbed .cf-logo{width:auto;max-width:190px;max-height:72px;object-fit:contain;display:block;margin:0 auto -2px}\n#cfEmbed .cf-logo-sm{width:auto;max-width:110px;max-height:30px;object-fit:contain;display:block;margin:0 auto 12px}\n#cfEmbed .cf-logo[hidden],#cfEmbed .cf-logo-sm[hidden]{display:none}\n\n#cfEmbed .cf-btn{\n  display:inline-block;text-decoration:none;text-align:center;\n  font-family:inherit;font-variation-settings:\"SOFT\" 100;font-size:17px;font-weight:800;\n  background:var(--cf-btn);color:#fff;border:0;border-radius:999px;\n  padding:16px 34px;cursor:pointer;box-shadow:0 4px 0 var(--cf-btn-edge);\n}\n#cfEmbed .cf-btn:hover{background:var(--cf-btn);color:#fff}\n#cfEmbed .cf-btn:active{transform:translateY(3px);box-shadow:0 1px 0 var(--cf-btn-edge)}\n#cfEmbed .cf-btn:focus-visible{outline:3px solid var(--cf-cream);outline-offset:3px}\n#cfEmbed .cf-linkish{\n  background:none;border:0;color:var(--cf-cream);opacity:.65;font-family:inherit;\n  font-size:13px;font-weight:600;cursor:pointer;padding:8px;text-decoration:underline;\n}\n\n#cfEmbed .cf-coupon{\n  width:100%;max-width:290px;background:var(--cf-cream);color:var(--cf-ink);\n  border-radius:14px;padding:18px 16px;\n  animation:cfRise .5s cubic-bezier(.16,1,.3,1) both;\n}\n#cfEmbed .cf-what{font-size:18px;font-weight:800;letter-spacing:-.01em;line-height:1.15}\n#cfEmbed .cf-code{\n  margin-top:12px;border:2px dashed rgba(31,42,36,.3);border-radius:8px;\n  padding:11px 8px;font-size:22px;font-weight:900;letter-spacing:.12em;\n}\n#cfEmbed .cf-fine{margin-top:10px;font-size:10.5px;font-weight:500;opacity:.62;line-height:1.45}\n@keyframes cfRise{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}\n@media (prefers-reduced-motion:reduce){\n  #cfEmbed .cf-coupon,#cfEmbed .cf-pop.is-on{animation-duration:.01s}\n}\n<\/style>\n\n<script>\n(function () {\n  'use strict';\n  var root = document.getElementById('cfEmbed');\n  if (!root || root.dataset.cfReady) return;\n  root.dataset.cfReady = '1';\n\n  \/* =================================================================\n     CONFIG \u2014 everything a client reskin touches lives here.\n     logo \/ logoCoupon: a media library URL or a data: URI. '' hides it.\n  ================================================================== *\/\n  var CONFIG = {\n    shop: 'Daybreak Coffee Co.',\n    city: 'McAllen',\n    prize: 'A free pastry with your next drink',\n    codePrefix: 'DAWN',\n    address: '1200 Coffee Row, McAllen, Texas',\n    directions: '#',\n    logo: '',\n    logoCoupon: ''\n  };\n\n  function q(n) { return root.querySelector('[data-cf=\"' + n + '\"]'); }\n\n  var W = 360, H = 640;\n  var stage = q('stage'), cv = q('canvas'), ctx = cv.getContext('2d');\n  var elHud = q('hud'), elDrinkNo = q('drinkNo'), elDrinkName = q('drinkName'), elSteps = q('steps');\n  var elHint = q('hint'), elPop = q('pop'), elStart = q('start'), elEnd = q('end');\n  var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n  \/* ---------- apply config ---------- *\/\n  q('stampStart').textContent = (CONFIG.shop + ' \\u00B7 ' + CONFIG.city).toUpperCase();\n  q('prize').textContent = CONFIG.prize;\n  var fine = q('fine');\n  fine.textContent = 'Show this at the register. Good for 7 days.';\n  fine.appendChild(document.createElement('br'));\n  fine.appendChild(document.createTextNode(CONFIG.address));\n  q('directions').href = CONFIG.directions || '#';\n  function mountLogo(el, src) {\n    if (!el || !src) return;\n    el.alt = CONFIG.shop;\n    el.src = src;\n    el.hidden = false;\n    el.addEventListener('error', function () { el.hidden = true; });\n  }\n  mountLogo(q('logo'), CONFIG.logo);\n  mountLogo(q('logoCoupon'), CONFIG.logoCoupon || CONFIG.logo);\n\n  \/* ---------- drinks ---------- *\/\n  var KINDS = {\n    espresso: { label: 'Espresso', fill: '#3A2216', rgb: '58,34,22', stream: '#5A3420', freq: 650 },\n    milk: { label: 'Milk', fill: '#EFE3CF', rgb: '239,227,207', stream: '#F4EAD8', freq: 1150 },\n    foam: { label: 'Foam', fill: '#FFFDF7', rgb: '255,253,247', stream: '#FFFFFF', freq: 1900 }\n  };\n  \/\/ bands are fractions of the glass: [kind, bottom of line, top of line]\n  var DRINKS = [\n    { name: 'Cortado', rate: 1.05, layers: [['espresso', .20, .32], ['milk', .52, .64]] },\n    { name: 'Latte', rate: 1.3, layers: [['espresso', .14, .25], ['milk', .60, .71], ['foam', .82, .92]] },\n    { name: 'Cappuccino', rate: 1.5, layers: [['espresso', .16, .27], ['milk', .44, .55], ['foam', .80, .91]] }\n  ];\n  var MAX_PTS = DRINKS.reduce(function (n, d) { return n + d.layers.length * 3; }, 0);\n\n  \/* ---------- glass geometry ---------- *\/\n  var GL = { cx: 180, rimY: 254, floorY: 461, baseY: 472, topHW: 69, botHW: 57, wall: 5 };\n  var CAP = GL.floorY - GL.rimY - 6;\n  function hwAt(y) {\n    var t = (y - GL.rimY) \/ (GL.baseY - GL.rimY);\n    return GL.topHW + (GL.botHW - GL.topHW) * t;\n  }\n\n  \/* ---------- canvas sizing ---------- *\/\n  function fit() {\n    var r = stage.getBoundingClientRect();\n    if (!r.width) return;\n    var dpr = Math.min(window.devicePixelRatio || 1, 2);\n    cv.width = Math.round(r.width * dpr);\n    cv.height = Math.round(r.height * dpr);\n    ctx.setTransform(1, 0, 0, 1, 0, 0);\n    ctx.scale(cv.width \/ W, cv.height \/ H);\n    render(performance.now());\n  }\n  if (window.ResizeObserver) new ResizeObserver(fit).observe(stage);\n  else window.addEventListener('resize', fit);\n\n  \/* ---------- sound ---------- *\/\n  var ac = null, noiseBuf = null, pourSrc = null, pourGain = null, pourFilter = null, pourBase = 0;\n  function blip(freq, dur, vol) {\n    if (!ac) return;\n    var o = ac.createOscillator(), g = ac.createGain();\n    o.type = 'sine'; o.frequency.value = freq;\n    g.gain.setValueAtTime(vol || .1, ac.currentTime);\n    g.gain.exponentialRampToValueAtTime(.0001, ac.currentTime + dur);\n    o.connect(g); g.connect(ac.destination);\n    o.start(); o.stop(ac.currentTime + dur);\n  }\n  function startPour(kind) {\n    if (!ac) return;\n    if (!noiseBuf) {\n      noiseBuf = ac.createBuffer(1, ac.sampleRate, ac.sampleRate);\n      var d = noiseBuf.getChannelData(0);\n      for (var i = 0; i < d.length; i++) d[i] = Math.random() * 2 - 1;\n    }\n    pourSrc = ac.createBufferSource(); pourSrc.buffer = noiseBuf; pourSrc.loop = true;\n    pourFilter = ac.createBiquadFilter(); pourFilter.type = 'bandpass'; pourFilter.Q.value = 1.1;\n    pourBase = KINDS[kind].freq; pourFilter.frequency.value = pourBase;\n    pourGain = ac.createGain();\n    pourGain.gain.setValueAtTime(.0001, ac.currentTime);\n    pourGain.gain.exponentialRampToValueAtTime(.06, ac.currentTime + .06);\n    pourSrc.connect(pourFilter); pourFilter.connect(pourGain); pourGain.connect(ac.destination);\n    pourSrc.start();\n  }\n  function stopPour() {\n    if (!pourSrc || !ac) return;\n    var g = pourGain, s = pourSrc, now = ac.currentTime;\n    g.gain.cancelScheduledValues(now);\n    g.gain.setValueAtTime(Math.max(g.gain.value, .0001), now);\n    g.gain.exponentialRampToValueAtTime(.0001, now + .08);\n    s.stop(now + .1);\n    pourSrc = null; pourGain = null; pourFilter = null;\n  }\n\n  \/* ---------- state ---------- *\/\n  var state = 'idle';           \/\/ idle | play | serve | done\n  var drinkIdx, layerIdx, layers, level, band, holding, pourStart, points, serveAt, ox, firstPour;\n\n  function reset() {\n    drinkIdx = 0; points = 0; firstPour = true;\n    loadDrink();\n  }\n  function loadDrink() {\n    layerIdx = 0; layers = []; level = 0; holding = false; ox = 0;\n    band = makeBand();\n    renderHud();\n  }\n  function curDrink() { return DRINKS[drinkIdx]; }\n  function curKind() {\n    var d = curDrink();\n    return d && d.layers[layerIdx] ? d.layers[layerIdx][0] : null;\n  }\n  function makeBand() {\n    var L = curDrink().layers[layerIdx];\n    if (!L) return null;\n    var min = L[1] * CAP, max = L[2] * CAP, w = max - min;\n    if (min < level + 8) { min = level + 10; max = min + w; }       \/\/ forgive an earlier overpour\n    if (max > CAP - 2) { max = CAP - 2; min = Math.max(level + 6, max - w); }\n    if (max - min < 8) return null;                                  \/\/ no room left; skip layer\n    return { kind: L[0], min: min, max: max };\n  }\n\n  function renderHud() {\n    var d = curDrink();\n    elDrinkNo.textContent = 'Drink ' + (drinkIdx + 1) + ' of ' + DRINKS.length;\n    elDrinkName.textContent = d.name;\n    elSteps.textContent = '';\n    d.layers.forEach(function (L, i) {\n      var s = document.createElement('span');\n      s.className = 'cf-step' + (i < layerIdx ? ' is-done' : i === layerIdx ? ' is-now' : '');\n      s.textContent = KINDS[L[0]].label;\n      elSteps.appendChild(s);\n    });\n  }\n\n  function pop(text, best) {\n    elPop.textContent = text;\n    elPop.className = 'cf-pop';\n    void elPop.offsetWidth;                \/\/ restart the animation\n    elPop.className = 'cf-pop is-on' + (best ? ' is-best' : '');\n  }\n\n  \/* ---------- pouring ---------- *\/\n  function pressStart() {\n    if (state !== 'play' || holding || !band) return;\n    holding = true;\n    pourStart = level;\n    startPour(band.kind);\n    if (firstPour) { firstPour = false; elHint.hidden = true; }\n  }\n  function pressEnd() {\n    if (!holding) return;\n    holding = false;\n    stopPour();\n    if (level - pourStart < 3) { level = pourStart; return; }   \/\/ a stray tap, not a pour\n    commit();\n  }\n\n  function commit() {\n    var mid = (band.min + band.max) \/ 2, half = (band.max - band.min) \/ 2;\n    var err = Math.abs(level - mid), pts, word;\n    if (err <= half * .4) { pts = 3; word = 'Perfect.'; }\n    else if (err <= half) { pts = 2; word = 'Nice pour.'; }\n    else if (err <= half * 2.2) { pts = 1; word = 'Close.'; }\n    else { pts = 0; word = 'Rustic.'; }\n    points += pts;\n    pop(word, pts === 3);\n    blip(pts === 3 ? 880 : pts === 2 ? 740 : 560, .16, .09);\n\n    layers.push({ kind: band.kind, top: level });\n    layerIdx++;\n    band = curDrink().layers[layerIdx] ? makeBand() : null;\n    renderHud();\n\n    if (!band) {\n      state = 'serve';\n      serveAt = performance.now() + 380;\n    }\n  }\n\n  \/* ---------- drawing ---------- *\/\n  function roundRect(x, y, w, h, r) {\n    ctx.beginPath();\n    ctx.moveTo(x + r, y);\n    ctx.arcTo(x + w, y, x + w, y + h, r);\n    ctx.arcTo(x + w, y + h, x, y + h, r);\n    ctx.arcTo(x, y + h, x, y, r);\n    ctx.arcTo(x, y, x + w, y, r);\n    ctx.closePath();\n  }\n  function glassPath(cx, inset, yBottom) {\n    ctx.beginPath();\n    ctx.moveTo(cx - hwAt(GL.rimY) + inset, GL.rimY);\n    ctx.lineTo(cx + hwAt(GL.rimY) - inset, GL.rimY);\n    ctx.lineTo(cx + hwAt(yBottom) - inset, yBottom);\n    ctx.lineTo(cx - hwAt(yBottom) + inset, yBottom);\n    ctx.closePath();\n  }\n\n  function drawRoom() {\n    ctx.fillStyle = '#9DBFAC';\n    ctx.fillRect(0, 0, W, H);\n    \/\/ subway tile backsplash\n    ctx.strokeStyle = 'rgba(31,42,36,.08)'; ctx.lineWidth = 1;\n    for (var row = 0, y = 12; y < 468; y += 26, row++) {\n      ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke();\n      for (var x = row % 2 ? 26 : 0; x < W; x += 52) {\n        ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x, y + 26); ctx.stroke();\n      }\n    }\n    \/\/ marble counter\n    ctx.fillStyle = '#EFE6D6';\n    ctx.fillRect(0, 468, W, H - 468);\n    ctx.fillStyle = 'rgba(31,42,36,.16)';\n    ctx.fillRect(0, 468, W, 2);\n    ctx.strokeStyle = 'rgba(31,42,36,.05)'; ctx.lineWidth = 1.2;\n    ctx.beginPath(); ctx.moveTo(10, 540); ctx.bezierCurveTo(90, 520, 150, 590, 240, 560); ctx.stroke();\n    ctx.beginPath(); ctx.moveTo(200, 620); ctx.bezierCurveTo(260, 600, 300, 640, 360, 606); ctx.stroke();\n  }\n\n  function drawLayer(kind, prevKind, from, to, cx, wobble, t) {\n    var yb = GL.floorY - from, yt = GL.floorY - to, x0 = cx - 80, w = 160, k = KINDS[kind];\n    ctx.fillStyle = k.fill;\n    ctx.beginPath();\n    ctx.moveTo(x0, yb);\n    ctx.lineTo(x0, yt);\n    if (wobble && !reduce) {\n      for (var x = 0; x <= w; x += 8) ctx.lineTo(x0 + x, yt + Math.sin(x * .09 + t * .012) * 1.6);\n    } else {\n      ctx.lineTo(x0 + w, yt);\n    }\n    ctx.lineTo(x0 + w, yb);\n    ctx.closePath();\n    ctx.fill();\n\n    if (prevKind) {   \/\/ soft blend where two layers meet\n      var g = ctx.createLinearGradient(0, yb, 0, yb - 10);\n      g.addColorStop(0, 'rgba(' + KINDS[prevKind].rgb + ',1)');\n      g.addColorStop(1, 'rgba(' + KINDS[prevKind].rgb + ',0)');\n      ctx.fillStyle = g;\n      ctx.fillRect(x0, yb - 10, w, 10);\n    }\n    if (kind === 'espresso' && to - from > 3) {\n      ctx.fillStyle = '#B8702F';\n      ctx.fillRect(x0, yt, w, 3);\n    }\n    if (kind === 'foam' && to - from > 4) {\n      ctx.fillStyle = '#FFFFFF';\n      for (var bx = 4; bx < w; bx += 11) {\n        ctx.beginPath(); ctx.arc(x0 + bx, yt + 2, 3 + (bx * 7) % 3, 0, 7); ctx.fill();\n      }\n    }\n  }\n\n  function drawGlass(cx, t) {\n    \/\/ shadow on the counter\n    ctx.fillStyle = 'rgba(31,42,36,.16)';\n    ctx.beginPath(); ctx.ellipse(cx, GL.baseY + 2, 66, 7, 0, 0, 7); ctx.fill();\n    \/\/ glass body tint\n    glassPath(cx, 0, GL.baseY);\n    ctx.fillStyle = 'rgba(255,255,255,.2)';\n    ctx.fill();\n\n    \/\/ liquid + target band, clipped to the inside of the glass\n    ctx.save();\n    glassPath(cx, GL.wall, GL.floorY);\n    ctx.clip();\n    var prev = 0, prevKind = null;\n    for (var i = 0; i < layers.length; i++) {\n      drawLayer(layers[i].kind, prevKind, prev, layers[i].top, cx, false, t);\n      prev = layers[i].top; prevKind = layers[i].kind;\n    }\n    if (band && level > prev) drawLayer(band.kind, prevKind, prev, level, cx, holding, t);\n    if (band && state === 'play') {\n      var yTop = GL.floorY - band.max, yBot = GL.floorY - band.min;\n      ctx.fillStyle = 'rgba(228,87,46,.15)';\n      ctx.fillRect(cx - 80, yTop, 160, yBot - yTop);\n      ctx.strokeStyle = '#E4572E'; ctx.lineWidth = 1.5; ctx.setLineDash([5, 4]);\n      ctx.beginPath(); ctx.moveTo(cx - 80, yTop); ctx.lineTo(cx + 80, yTop); ctx.stroke();\n      ctx.beginPath(); ctx.moveTo(cx - 80, yBot); ctx.lineTo(cx + 80, yBot); ctx.stroke();\n      ctx.setLineDash([]);\n    }\n    ctx.restore();\n\n    \/\/ thick glass base\n    ctx.fillStyle = 'rgba(255,255,255,.4)';\n    ctx.beginPath();\n    ctx.moveTo(cx - hwAt(GL.floorY), GL.floorY);\n    ctx.lineTo(cx + hwAt(GL.floorY), GL.floorY);\n    ctx.lineTo(cx + hwAt(GL.baseY), GL.baseY);\n    ctx.lineTo(cx - hwAt(GL.baseY), GL.baseY);\n    ctx.closePath(); ctx.fill();\n    \/\/ outline + highlight\n    glassPath(cx, 0, GL.baseY);\n    ctx.strokeStyle = 'rgba(255,255,255,.9)'; ctx.lineWidth = 2.5; ctx.stroke();\n    ctx.strokeStyle = 'rgba(255,255,255,.5)'; ctx.lineWidth = 5; ctx.lineCap = 'round';\n    ctx.beginPath();\n    ctx.moveTo(cx - hwAt(GL.rimY + 18) + 13, GL.rimY + 18);\n    ctx.lineTo(cx - hwAt(GL.floorY - 30) + 13, GL.floorY - 30);\n    ctx.stroke();\n\n    \/\/ band ticks + label outside the glass\n    if (band && state === 'play') {\n      var yT = GL.floorY - band.max, yB = GL.floorY - band.min, mid = (yT + yB) \/ 2;\n      ctx.strokeStyle = '#E4572E'; ctx.lineWidth = 3; ctx.lineCap = 'round';\n      [yT, yB].forEach(function (y) {\n        var hw = hwAt(y);\n        ctx.beginPath(); ctx.moveTo(cx - hw - 12, y); ctx.lineTo(cx - hw - 2, y); ctx.stroke();\n        ctx.beginPath(); ctx.moveTo(cx + hw + 2, y); ctx.lineTo(cx + hw + 12, y); ctx.stroke();\n      });\n      var rx = cx + hwAt(mid) + 12;\n      ctx.beginPath(); ctx.moveTo(rx, yT); ctx.lineTo(rx, yB); ctx.stroke();\n      ctx.fillStyle = '#1F2A24';\n      ctx.font = '700 14px Fraunces, Georgia, serif';\n      ctx.textBaseline = 'middle';\n      ctx.fillText(KINDS[band.kind].label, rx + 8, mid);\n    }\n  }\n\n  function drawPortafilter() {\n    ctx.fillStyle = '#B9C0C4'; roundRect(150, 104, 60, 36, 6); ctx.fill();          \/\/ group head\n    ctx.fillStyle = 'rgba(255,255,255,.5)'; ctx.fillRect(158, 110, 10, 24);\n    ctx.fillStyle = '#2A2522'; roundRect(58, 150, 80, 13, 6); ctx.fill();           \/\/ handle\n    ctx.fillStyle = '#C9CED1'; roundRect(128, 138, 104, 32, 12); ctx.fill();        \/\/ basket\n    ctx.fillStyle = '#A3AAAE'; ctx.fillRect(136, 160, 88, 6);\n    ctx.fillStyle = '#8E969A'; roundRect(172, 170, 16, 14, 4); ctx.fill();          \/\/ spout\n  }\n  function drawPitcher() {\n    ctx.save();\n    ctx.translate(240, 195);\n    ctx.rotate(-.55);\n    ctx.fillStyle = '#C9CED1';\n    ctx.beginPath();\n    ctx.moveTo(-30, -34); ctx.lineTo(30, -34); ctx.lineTo(26, 34); ctx.lineTo(-26, 34);\n    ctx.closePath(); ctx.fill();\n    ctx.beginPath(); ctx.moveTo(-30, -34); ctx.lineTo(-44, -40); ctx.lineTo(-30, -22); ctx.closePath(); ctx.fill();\n    ctx.strokeStyle = '#9AA2A6'; ctx.lineWidth = 6; ctx.lineCap = 'round';\n    ctx.beginPath(); ctx.moveTo(30, -22); ctx.quadraticCurveTo(54, 0, 28, 22); ctx.stroke();\n    ctx.fillStyle = 'rgba(255,255,255,.45)'; ctx.fillRect(-20, -28, 8, 54);\n    ctx.restore();\n  }\n\n  function render(t) {\n    drawRoom();\n    var cx = GL.cx + (ox || 0);\n    if (layers) drawGlass(cx, t);\n    if (state === 'play' && band) {\n      if (band.kind === 'espresso') drawPortafilter(); else drawPitcher();\n      if (holding) {\n        var sw = band.kind === 'espresso' ? 4 : 6;\n        var surface = GL.floorY - level;\n        ctx.fillStyle = KINDS[band.kind].stream;\n        ctx.fillRect(GL.cx - sw \/ 2 + (reduce ? 0 : Math.sin(t * .03) * .8), 184, sw, Math.max(0, surface - 184));\n      }\n    }\n  }\n\n  \/* ---------- loop ---------- *\/\n  var last = 0;\n  function frame(now) {\n    if (state !== 'play' && state !== 'serve') return;\n    var dt = Math.min((now - last) || 16, 34) \/ 16.667;\n    last = now;\n\n    if (state === 'play' && holding) {\n      level += curDrink().rate * dt;\n      if (pourFilter) pourFilter.frequency.value = pourBase + level * 5;   \/\/ pitch climbs as the glass fills\n      if (level >= CAP) { level = CAP; pressEnd(); }\n    }\n\n    if (state === 'serve' && now >= serveAt) {\n      var p = (now - serveAt) \/ 440;\n      if (p < 1) {\n        ox = reduce ? 0 : 300 * p * p;                                     \/\/ slide the finished drink away\n      } else if (drinkIdx < DRINKS.length - 1) {\n        drinkIdx++;\n        loadDrink();\n        blip(1046, .12, .07); setTimeout(function () { blip(1318, .18, .07); }, 90);\n        ox = reduce ? 0 : -300;\n        serveAt = Infinity;\n        state = 'in';\n        inAt = now;\n      } else {\n        finish();\n        return;\n      }\n    }\n    render(now);\n    requestAnimationFrame(frame);\n  }\n\n  var inAt = 0;\n  function slideIn(now) {\n    if (state !== 'in') return;\n    var p = Math.min((now - inAt) \/ 420, 1);\n    var e = 1 - Math.pow(1 - p, 3);\n    ox = reduce ? 0 : -300 * (1 - e);\n    render(now);\n    if (p < 1) { requestAnimationFrame(slideIn); return; }\n    ox = 0;\n    state = 'play';\n    last = performance.now();\n    requestAnimationFrame(frame);\n  }\n  \/\/ hook the slide-in into the main loop transition\n  var _frame = frame;\n  frame = function (now) {\n    if (state === 'in') { slideIn(now); return; }\n    _frame(now);\n  };\n\n  \/* ---------- flow ---------- *\/\n  function begin() {\n    if (!ac) {\n      try { ac = new (window.AudioContext || window.webkitAudioContext)(); } catch (err) { ac = null; }\n    }\n    if (ac && ac.state === 'suspended') ac.resume();\n    reset(); fit();\n    elStart.hidden = true; elEnd.hidden = true;\n    elHud.hidden = false; elHint.hidden = false;\n    stage.classList.add('is-playing');\n    state = 'play';\n    last = performance.now();\n    requestAnimationFrame(frame);\n    try { stage.focus({ preventScroll: true }); } catch (e) {}\n  }\n\n  function finish() {\n    state = 'done';\n    stopPour();\n    stage.classList.remove('is-playing');\n    elHud.hidden = true; elHint.hidden = true;\n    var share = points \/ MAX_PTS;\n    q('verdict').textContent = share >= .75 ? 'Latte artist.' : share >= .5 ? 'Solid pour.' : 'Everyone starts somewhere.';\n    q('scoreLine').textContent = points + ' of ' + MAX_PTS + ' pour points';\n    var chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789', out = '';\n    for (var i = 0; i < 4; i++) out += chars[(Math.random() * chars.length) | 0];\n    q('code').textContent = CONFIG.codePrefix + '-' + out;\n    elEnd.hidden = false;\n    blip(659, .12, .09); setTimeout(function () { blip(988, .26, .09); }, 120);\n    ox = 0; layers = []; level = 0; band = null;\n    render(performance.now());\n  }\n\n  \/* ---------- input ---------- *\/\n  stage.addEventListener('pointerdown', function (e) {\n    if (state !== 'play') return;\n    if (e.target.closest && e.target.closest('button,a')) return;\n    e.preventDefault();\n    pressStart();\n  });\n  window.addEventListener('pointerup', pressEnd);\n  window.addEventListener('pointercancel', pressEnd);\n  window.addEventListener('blur', pressEnd);\n  stage.addEventListener('contextmenu', function (e) { if (state === 'play') e.preventDefault(); });\n  stage.addEventListener('keydown', function (e) {\n    if (state !== 'play') return;\n    if (e.code === 'Space' || e.key === ' ' || e.key === 'Enter') {\n      e.preventDefault();\n      if (!e.repeat) pressStart();\n    }\n  });\n  stage.addEventListener('keyup', function (e) {\n    if (e.code === 'Space' || e.key === ' ' || e.key === 'Enter') { e.preventDefault(); pressEnd(); }\n  });\n\n  q('go').addEventListener('click', begin);\n  q('again').addEventListener('click', begin);\n\n  reset();\n  state = 'idle';\n  fit();\n})();\n<\/script><\/div><div class=\"x-col e16-e46 mg-w mg-x mg-y mg-z\"><!-- ======================================================================\n     SPOTLESS \u2014 inline embed (car wash)\n     Paste this whole block into a Cornerstone \"Raw Content\" element.\n     Everything is scoped to #cwEmbed; nothing touches <html> or <body>.\n     To reskin for a client, edit the CONFIG block at the top of the\n     script \u2014 shop name, city, prize, code prefix, address, CTA, logo.\n     One instance per page.\n     ====================================================================== -->\n\n<div id=\"cwEmbed\">\n  <div class=\"cw-frame\">\n    <div class=\"cw-stage\" data-cw=\"stage\" tabindex=\"0\"\n         aria-label=\"Spotless. Drag across the car to blast it clean. With a keyboard, use the arrow keys to aim and hold space to spray.\">\n      <canvas data-cw=\"canvas\"><\/canvas>\n\n      <div class=\"cw-hud\" data-cw=\"hud\" hidden>\n        <div>\n          <div class=\"cw-kicker\" data-cw=\"carNo\">Car 1 of 3<\/div>\n          <div class=\"cw-car\" data-cw=\"carName\">The Daily Driver<\/div>\n        <\/div>\n        <div class=\"cw-meter\">\n          <div class=\"cw-pct\"><span data-cw=\"pct\">0<\/span>%<\/div>\n          <div class=\"cw-bar\"><i data-cw=\"bar\"><\/i><\/div>\n        <\/div>\n      <\/div>\n\n      <div class=\"cw-hint\" data-cw=\"hint\" hidden>Drag across the car<br>to blast it clean.<\/div>\n      <div class=\"cw-pop\" data-cw=\"pop\" aria-live=\"polite\"><\/div>\n\n      <div class=\"cw-veil\" data-cw=\"start\">\n        <img class=\"cw-logo\" data-cw=\"logo\" alt=\"\" hidden>\n        <div class=\"cw-stamp\" data-cw=\"stampStart\"><\/div>\n        <h3 class=\"cw-h1\">Spot&shy;less<\/h3>\n        <p class=\"cw-p\">Three filthy rides. Drag to blast them clean. Finish all three to claim your reward.<\/p>\n        <button class=\"cw-btn\" type=\"button\" data-cw=\"go\">Grab the wand<\/button>\n      <\/div>\n\n      <div class=\"cw-veil\" data-cw=\"end\" hidden>\n        <h3 class=\"cw-h2\" data-cw=\"verdict\">Showroom shine.<\/h3>\n        <p class=\"cw-score\" data-cw=\"scoreLine\"><\/p>\n        <div class=\"cw-coupon\">\n          <img class=\"cw-logo-sm\" data-cw=\"logoCoupon\" alt=\"\" hidden>\n          <div class=\"cw-what\" data-cw=\"prize\"><\/div>\n          <div class=\"cw-code\" data-cw=\"code\"><\/div>\n          <div class=\"cw-fine\" data-cw=\"fine\"><\/div>\n        <\/div>\n        <a class=\"cw-btn\" data-cw=\"cta\" href=\"#\" target=\"_blank\" rel=\"noopener\">Claim it<\/a>\n        <button class=\"cw-linkish\" type=\"button\" data-cw=\"again\">Play again<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<style>\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Unbounded:wght@400..900&family=Figtree:wght@500;600;700&display=swap');\n\n#cwEmbed{\n  --cw-wall:#1F66A8; --cw-ink:#0F1B2A; --cw-paper:#F5F8FB;\n  --cw-sun:#FFD23F; --cw-sun-edge:#B8921A; --cw-foam:#FF5FA2;\n  --cw-display:Unbounded,'Arial Black','Helvetica Neue',sans-serif;\n  --cw-body:Figtree,'Helvetica Neue',Helvetica,Arial,sans-serif;\n  width:100%;\n  max-width:min(420px, 44vh);\n  margin:0 auto;\n}\n#cwEmbed *{box-sizing:border-box}\n#cwEmbed .cw-frame{position:relative;width:100%;padding-top:177.78%}\n#cwEmbed .cw-stage{\n  position:absolute;top:0;left:0;right:0;bottom:0;\n  background:var(--cw-wall);border-radius:18px;overflow:hidden;\n  font-family:var(--cw-body);line-height:1.25;cursor:crosshair;\n  touch-action:manipulation;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;\n  outline:none;\n}\n#cwEmbed .cw-stage.is-playing{touch-action:none}\n#cwEmbed .cw-stage:focus-visible{box-shadow:inset 0 0 0 3px var(--cw-sun)}\n#cwEmbed canvas{position:absolute;top:0;left:0;width:100%;height:100%;display:block}\n\n#cwEmbed .cw-hud{\n  position:absolute;top:0;left:0;right:0;z-index:2;pointer-events:none;\n  display:flex;justify-content:space-between;align-items:flex-start;gap:10px;\n  padding:16px 16px 0;color:#fff;\n}\n#cwEmbed .cw-hud[hidden]{display:none}\n#cwEmbed .cw-kicker{font-size:11px;font-weight:600;opacity:.8}\n#cwEmbed .cw-car{\n  font-family:var(--cw-display);font-size:15px;font-weight:800;letter-spacing:-.01em;\n  line-height:1.12;margin-top:4px;max-width:180px;\n}\n#cwEmbed .cw-meter{text-align:right}\n#cwEmbed .cw-pct{font-family:var(--cw-display);font-size:28px;font-weight:800;line-height:1;letter-spacing:-.02em}\n#cwEmbed .cw-bar{width:84px;height:7px;margin:7px 0 0 auto;border-radius:99px;background:rgba(255,255,255,.25);overflow:hidden}\n#cwEmbed .cw-bar i{display:block;height:100%;width:100%;background:var(--cw-sun);transform:scaleX(0);transform-origin:left}\n\n#cwEmbed .cw-hint{\n  position:absolute;left:0;right:0;top:80%;z-index:2;pointer-events:none;\n  text-align:center;font-size:16px;font-weight:700;line-height:1.35;color:#fff;opacity:.85;\n}\n#cwEmbed .cw-hint[hidden]{display:none}\n#cwEmbed .cw-pop{\n  position:absolute;left:0;right:0;top:79%;z-index:2;pointer-events:none;\n  text-align:center;font-family:var(--cw-display);font-size:28px;font-weight:900;\n  letter-spacing:-.02em;color:var(--cw-sun);opacity:0;\n}\n#cwEmbed .cw-pop.is-on{animation:cwPop 1s cubic-bezier(.16,1,.3,1) both}\n@keyframes cwPop{\n  0%{opacity:0;transform:translateY(10px) scale(.9)}\n  16%{opacity:1;transform:none}\n  72%{opacity:1}\n  100%{opacity:0;transform:translateY(-6px)}\n}\n\n#cwEmbed .cw-veil{\n  position:absolute;top:0;left:0;right:0;bottom:0;z-index:3;\n  display:flex;flex-direction:column;align-items:center;justify-content:center;\n  text-align:center;gap:16px;padding:28px 24px;\n  background:rgba(15,27,42,.86);color:var(--cw-paper);\n}\n#cwEmbed .cw-veil[hidden]{display:none}\n#cwEmbed .cw-stamp{font-size:11px;font-weight:700;letter-spacing:.12em;opacity:.72;margin:0}\n#cwEmbed .cw-h1{margin:0;font-family:var(--cw-display);font-size:44px;font-weight:900;letter-spacing:-.04em;line-height:.95;color:var(--cw-paper)}\n#cwEmbed .cw-h2{margin:0;font-family:var(--cw-display);font-size:28px;font-weight:900;letter-spacing:-.03em;line-height:1.05;color:var(--cw-paper)}\n#cwEmbed .cw-p{margin:0;font-size:15px;line-height:1.45;max-width:27ch;opacity:.86;color:var(--cw-paper)}\n#cwEmbed .cw-score{margin:-6px 0 0;font-size:13px;font-weight:600;opacity:.72;color:var(--cw-paper)}\n\n#cwEmbed .cw-logo{width:auto;max-width:190px;max-height:72px;object-fit:contain;display:block;margin:0 auto -2px}\n#cwEmbed .cw-logo-sm{width:auto;max-width:110px;max-height:30px;object-fit:contain;display:block;margin:0 auto 12px}\n#cwEmbed .cw-logo[hidden],#cwEmbed .cw-logo-sm[hidden]{display:none}\n\n#cwEmbed .cw-btn{\n  display:inline-block;text-decoration:none;text-align:center;\n  font-family:var(--cw-display);font-size:15px;font-weight:800;letter-spacing:-.01em;\n  background:var(--cw-sun);color:var(--cw-ink);border:0;border-radius:999px;\n  padding:16px 30px;cursor:pointer;box-shadow:0 4px 0 var(--cw-sun-edge);\n}\n#cwEmbed .cw-btn:hover{background:var(--cw-sun);color:var(--cw-ink)}\n#cwEmbed .cw-btn:active{transform:translateY(3px);box-shadow:0 1px 0 var(--cw-sun-edge)}\n#cwEmbed .cw-btn:focus-visible{outline:3px solid #fff;outline-offset:3px}\n#cwEmbed .cw-linkish{\n  background:none;border:0;color:var(--cw-paper);opacity:.68;font-family:inherit;\n  font-size:13px;font-weight:600;cursor:pointer;padding:8px;text-decoration:underline;\n}\n\n#cwEmbed .cw-coupon{\n  width:100%;max-width:290px;background:var(--cw-paper);color:var(--cw-ink);\n  border-radius:14px;padding:18px 16px;\n  animation:cwRise .5s cubic-bezier(.16,1,.3,1) both;\n}\n#cwEmbed .cw-what{font-family:var(--cw-display);font-size:15px;font-weight:800;letter-spacing:-.01em;line-height:1.25}\n#cwEmbed .cw-code{\n  margin-top:12px;border:2px dashed rgba(15,27,42,.3);border-radius:8px;\n  padding:11px 8px;font-family:var(--cw-display);font-size:20px;font-weight:900;letter-spacing:.1em;\n}\n#cwEmbed .cw-fine{margin-top:10px;font-size:11px;font-weight:500;opacity:.64;line-height:1.45}\n@keyframes cwRise{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}\n@media (prefers-reduced-motion:reduce){\n  #cwEmbed .cw-coupon,#cwEmbed .cw-pop.is-on{animation-duration:.01s}\n}\n<\/style>\n\n<script>\n(function () {\n  'use strict';\n  var root = document.getElementById('cwEmbed');\n  if (!root || root.dataset.cwReady) return;\n  root.dataset.cwReady = '1';\n\n  \/* =================================================================\n     CONFIG \u2014 everything a client reskin touches lives here.\n     logo \/ logoCoupon: a media library URL or a data: URI. '' hides it.\n  ================================================================== *\/\n  var CONFIG = {\n    shop: 'Tidal Express Wash',\n    city: 'Harlingen',\n    prize: 'Your first month of Unlimited Washes for $1',\n    codePrefix: 'TIDE',\n    address: '500 Suds Street, Harlingen, Texas',\n    ctaLabel: 'Claim my $1 month',\n    ctaLink: '#',\n    logo: '',\n    logoCoupon: ''\n  };\n\n  function q(n) { return root.querySelector('[data-cw=\"' + n + '\"]'); }\n\n  var W = 360, H = 640, OS = 2, FLOOR = 462, BRUSH = 21, DONE_AT = .88;\n  var stage = q('stage'), cv = q('canvas'), ctx = cv.getContext('2d');\n  var elHud = q('hud'), elCarNo = q('carNo'), elCarName = q('carName'), elPct = q('pct'), elBar = q('bar');\n  var elHint = q('hint'), elPop = q('pop'), elStart = q('start'), elEnd = q('end');\n  var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n  \/* ---------- apply config ---------- *\/\n  q('stampStart').textContent = (CONFIG.shop + ' \\u00B7 ' + CONFIG.city).toUpperCase();\n  q('prize').textContent = CONFIG.prize;\n  var fine = q('fine');\n  fine.textContent = 'Show this at the pay station. Good for 7 days.';\n  fine.appendChild(document.createElement('br'));\n  fine.appendChild(document.createTextNode(CONFIG.address));\n  var cta = q('cta');\n  cta.textContent = CONFIG.ctaLabel;\n  cta.href = CONFIG.ctaLink || '#';\n  function mountLogo(el, src) {\n    if (!el || !src) return;\n    el.alt = CONFIG.shop;\n    el.src = src;\n    el.hidden = false;\n    el.addEventListener('error', function () { el.hidden = true; });\n  }\n  mountLogo(q('logo'), CONFIG.logo);\n  mountLogo(q('logoCoupon'), CONFIG.logoCoupon || CONFIG.logo);\n\n  \/* ---------- offscreen layers: clean car, dirt, mask ---------- *\/\n  function makeLayer() {\n    var c = document.createElement('canvas');\n    c.width = W * OS; c.height = H * OS;\n    var x = c.getContext('2d', { willReadFrequently: true });\n    x.setTransform(OS, 0, 0, OS, 0, 0);\n    return { c: c, x: x };\n  }\n  function wipe(L) {\n    L.x.save(); L.x.setTransform(1, 0, 0, 1, 0, 0);\n    L.x.clearRect(0, 0, L.c.width, L.c.height);\n    L.x.restore();\n  }\n  var CAR = makeLayer(), DIRT = makeLayer(), MASK = makeLayer();\n  var BOX = { x: 20, y: 306, w: 320, h: 160 };\n\n  \/* ---------- vehicles ---------- *\/\n  var VEHICLES = [\n    {\n      name: 'The Daily Driver', paint: '#D2322D', pillar: '#7E1916',\n      wheels: [[96, 432, 28], [264, 432, 28]],\n      body: function (c) {\n        c.beginPath(); c.moveTo(34, 420); c.lineTo(36, 394);\n        c.quadraticCurveTo(38, 380, 54, 378); c.lineTo(98, 374);\n        c.quadraticCurveTo(118, 330, 152, 322); c.lineTo(214, 320);\n        c.quadraticCurveTo(240, 324, 264, 368); c.lineTo(312, 378);\n        c.quadraticCurveTo(330, 382, 330, 400); c.lineTo(330, 422);\n        c.quadraticCurveTo(330, 432, 320, 432); c.lineTo(44, 432);\n        c.quadraticCurveTo(34, 432, 34, 420); c.closePath();\n      },\n      glass: function (c) {\n        c.beginPath(); c.moveTo(112, 370); c.quadraticCurveTo(128, 338, 156, 331);\n        c.lineTo(208, 329); c.quadraticCurveTo(230, 333, 248, 368); c.closePath();\n      },\n      pillars: [180], doors: [150, 212],\n      tail: [36, 384, 9, 11], head: [314, 386, 15, 8],\n      dirt: { base: 'rgba(128,98,62,.88)', blotch: 26, splat: 140, drips: 22, heavyLow: false, bugs: 0 },\n      text: 'WASH ME', textAt: [182, 404]\n    },\n    {\n      name: 'The Ranch Truck', paint: '#E6EAEE', pillar: '#8C969F',\n      wheels: [[84, 432, 30], [282, 432, 30]],\n      body: function (c) {\n        c.beginPath(); c.moveTo(24, 422); c.lineTo(24, 382); c.lineTo(170, 382);\n        c.lineTo(176, 328); c.quadraticCurveTo(178, 318, 190, 318); c.lineTo(244, 318);\n        c.quadraticCurveTo(260, 320, 274, 352); c.lineTo(318, 362);\n        c.quadraticCurveTo(336, 366, 336, 388); c.lineTo(336, 422);\n        c.quadraticCurveTo(336, 432, 324, 432); c.lineTo(36, 432);\n        c.quadraticCurveTo(24, 432, 24, 422); c.closePath();\n      },\n      glass: function (c) {\n        c.beginPath(); c.moveTo(188, 356); c.lineTo(192, 330); c.lineTo(240, 330);\n        c.quadraticCurveTo(252, 332, 264, 356); c.closePath();\n      },\n      pillars: [], doors: [214], bed: true,\n      tail: [24, 386, 7, 14], head: [320, 372, 15, 8],\n      dirt: { base: 'rgba(112,82,48,.9)', blotch: 34, splat: 210, drips: 32, heavyLow: true, bugs: 0 }\n    },\n    {\n      name: 'The Family Hauler', paint: '#F2B705', pillar: '#6E5200',\n      wheels: [[90, 432, 29], [266, 432, 29]],\n      body: function (c) {\n        c.beginPath(); c.moveTo(28, 422); c.lineTo(30, 354);\n        c.quadraticCurveTo(32, 326, 58, 322); c.lineTo(218, 318);\n        c.quadraticCurveTo(246, 320, 270, 356); c.lineTo(314, 364);\n        c.quadraticCurveTo(332, 368, 332, 390); c.lineTo(332, 422);\n        c.quadraticCurveTo(332, 432, 320, 432); c.lineTo(40, 432);\n        c.quadraticCurveTo(28, 432, 28, 422); c.closePath();\n      },\n      glass: function (c) {\n        c.beginPath(); c.moveTo(54, 358); c.lineTo(58, 334); c.lineTo(212, 331);\n        c.quadraticCurveTo(236, 333, 254, 358); c.closePath();\n      },\n      pillars: [122, 186], doors: [152, 222], rails: true,\n      tail: [28, 362, 7, 16], head: [316, 378, 15, 8],\n      dirt: { base: 'rgba(158,136,102,.8)', blotch: 30, splat: 160, drips: 12, heavyLow: false, bugs: 48 }\n    }\n  ];\n\n  function roundRect(c, x, y, w, h, r) {\n    c.beginPath();\n    c.moveTo(x + r, y); c.arcTo(x + w, y, x + w, y + h, r); c.arcTo(x + w, y + h, x, y + h, r);\n    c.arcTo(x, y + h, x, y, r); c.arcTo(x, y, x + w, y, r); c.closePath();\n  }\n\n  function paintCar(v) {\n    var c = CAR.x;\n    wipe(CAR);\n    v.body(c); c.fillStyle = v.paint; c.fill();\n\n    c.save(); v.body(c); c.clip();\n    var g = c.createLinearGradient(0, 316, 0, 432);\n    g.addColorStop(0, 'rgba(255,255,255,.42)');\n    g.addColorStop(.32, 'rgba(255,255,255,.08)');\n    g.addColorStop(.6, 'rgba(0,0,0,0)');\n    g.addColorStop(1, 'rgba(0,0,0,.26)');\n    c.fillStyle = g; c.fillRect(0, 300, W, 140);\n    c.strokeStyle = 'rgba(255,255,255,.6)'; c.lineWidth = 2;\n    c.beginPath(); c.moveTo(38, 391); c.lineTo(330, 391); c.stroke();\n    c.strokeStyle = 'rgba(0,0,0,.22)'; c.lineWidth = 1.4;\n    v.doors.forEach(function (x) { c.beginPath(); c.moveTo(x, 366); c.lineTo(x + 2, 428); c.stroke(); });\n    c.fillStyle = 'rgba(0,0,0,.28)';\n    v.doors.forEach(function (x) { roundRect(c, x + 10, 398, 15, 4, 2); c.fill(); });\n    if (v.bed) {\n      c.strokeStyle = 'rgba(0,0,0,.3)'; c.lineWidth = 2;\n      c.beginPath(); c.moveTo(24, 390); c.lineTo(171, 390); c.stroke();\n    }\n    c.restore();\n\n    v.glass(c); c.fillStyle = '#1B2733'; c.fill();\n    c.save(); v.glass(c); c.clip();\n    c.fillStyle = 'rgba(255,255,255,.2)';\n    c.beginPath(); c.moveTo(150, 300); c.lineTo(178, 300); c.lineTo(136, 380); c.lineTo(108, 380); c.closePath(); c.fill();\n    c.fillStyle = v.pillar;\n    v.pillars.forEach(function (x) { c.fillRect(x - 3, 300, 6, 80); });\n    c.restore();\n\n    if (v.rails) {\n      c.strokeStyle = '#262B31'; c.lineWidth = 3; c.lineCap = 'round';\n      c.beginPath(); c.moveTo(66, 317); c.lineTo(210, 313); c.stroke();\n    }\n    c.fillStyle = '#E0262B'; roundRect(c, v.tail[0], v.tail[1], v.tail[2], v.tail[3], 3); c.fill();\n    c.fillStyle = '#FFF4C7'; roundRect(c, v.head[0], v.head[1], v.head[2], v.head[3], 3); c.fill();\n\n    v.wheels.forEach(function (w) {\n      var x = w[0], y = w[1], r = w[2];\n      c.fillStyle = '#0E1216';\n      c.beginPath(); c.arc(x, y, r + 5, Math.PI, 0); c.fill();\n      c.fillStyle = '#1C2126';\n      c.beginPath(); c.arc(x, y, r, 0, 7); c.fill();\n      c.fillStyle = '#C9D1D8';\n      c.beginPath(); c.arc(x, y, r * .56, 0, 7); c.fill();\n      c.strokeStyle = '#8F9AA4'; c.lineWidth = 2.6; c.lineCap = 'round';\n      for (var k = 0; k < 5; k++) {\n        var a = k * Math.PI * 2 \/ 5 - Math.PI \/ 2;\n        c.beginPath();\n        c.moveTo(x + Math.cos(a) * r * .18, y + Math.sin(a) * r * .18);\n        c.lineTo(x + Math.cos(a) * r * .5, y + Math.sin(a) * r * .5);\n        c.stroke();\n      }\n      c.fillStyle = '#6E7A85';\n      c.beginPath(); c.arc(x, y, r * .16, 0, 7); c.fill();\n    });\n  }\n\n  function paintDirt(v) {\n    var d = DIRT.x, p = v.dirt, i, x, y, r, g;\n    wipe(DIRT);\n    d.globalCompositeOperation = 'source-over';\n    d.fillStyle = p.base;\n    d.fillRect(0, 296, W, 176);\n\n    for (i = 0; i < p.blotch; i++) {\n      x = BOX.x + Math.random() * BOX.w; y = BOX.y + Math.random() * BOX.h; r = 10 + Math.random() * 30;\n      var col = Math.random() < .55 ? '82,58,32' : '184,160,120';\n      g = d.createRadialGradient(x, y, 0, x, y, r);\n      g.addColorStop(0, 'rgba(' + col + ',' + (.35 + Math.random() * .35).toFixed(2) + ')');\n      g.addColorStop(1, 'rgba(' + col + ',0)');\n      d.fillStyle = g; d.beginPath(); d.arc(x, y, r, 0, 7); d.fill();\n    }\n    if (p.heavyLow) {\n      g = d.createLinearGradient(0, 378, 0, 466);\n      g.addColorStop(0, 'rgba(92,64,34,0)');\n      g.addColorStop(.35, 'rgba(92,64,34,.92)');\n      g.addColorStop(1, 'rgba(66,45,24,1)');\n      d.fillStyle = g; d.fillRect(0, 378, W, 92);\n    }\n    d.fillStyle = 'rgba(70,50,28,.72)';\n    for (i = 0; i < p.splat; i++) {\n      x = BOX.x + Math.random() * BOX.w; y = BOX.y + Math.random() * BOX.h;\n      d.beginPath(); d.arc(x, y, .6 + Math.random() * 2.2, 0, 7); d.fill();\n    }\n    d.lineCap = 'round';\n    for (i = 0; i < p.drips; i++) {\n      x = 32 + Math.random() * 296; y = 368 + Math.random() * 50;\n      d.strokeStyle = 'rgba(86,62,36,.58)'; d.lineWidth = 1.4 + Math.random() * 2.2;\n      d.beginPath(); d.moveTo(x, y); d.lineTo(x + (Math.random() - .5) * 2, y + 10 + Math.random() * 26); d.stroke();\n    }\n    for (i = 0; i < p.bugs; i++) {       \/\/ South Texas windshield season\n      x = 246 + Math.random() * 86; y = 328 + Math.random() * 92;\n      d.fillStyle = 'rgba(232,204,92,.75)';\n      d.beginPath(); d.ellipse(x, y, 3 + Math.random() * 2.5, 1.6, Math.random() * 3, 0, 7); d.fill();\n      d.fillStyle = 'rgba(28,20,14,.9)';\n      d.beginPath(); d.arc(x, y, 1.3, 0, 7); d.fill();\n    }\n\n    \/\/ keep dirt only on the vehicle\n    var m = MASK.x;\n    wipe(MASK);\n    m.fillStyle = '#000';\n    v.body(m); m.fill();\n    v.wheels.forEach(function (w) { m.beginPath(); m.arc(w[0], w[1], w[2] + 1, 0, 7); m.fill(); });\n    d.save();\n    d.setTransform(1, 0, 0, 1, 0, 0);\n    d.globalCompositeOperation = 'destination-in';\n    d.drawImage(MASK.c, 0, 0);\n    d.restore();\n    d.globalCompositeOperation = 'source-over';\n\n    if (v.text) {                        \/\/ somebody already wrote in the dust\n      d.save();\n      d.globalCompositeOperation = 'destination-out';\n      d.fillStyle = 'rgba(0,0,0,.9)';\n      d.font = '800 16px Unbounded, \"Arial Black\", sans-serif';\n      d.textAlign = 'center'; d.textBaseline = 'middle';\n      d.translate(v.textAt[0], v.textAt[1]); d.rotate(-.05);\n      d.fillText(v.text, 0, 0);\n      d.restore();\n    }\n  }\n\n  function dirtyCount() {\n    var img = DIRT.x.getImageData(BOX.x * OS, BOX.y * OS, BOX.w * OS, BOX.h * OS).data, n = 0;\n    for (var i = 3; i < img.length; i += 16) if (img[i] > 40) n++;\n    return n;\n  }\n\n  function dab(x, y) {\n    var d = DIRT.x;\n    d.save();\n    d.globalCompositeOperation = 'destination-out';\n    var g = d.createRadialGradient(x, y, 0, x, y, BRUSH);\n    g.addColorStop(0, 'rgba(0,0,0,.95)');\n    g.addColorStop(.55, 'rgba(0,0,0,.6)');\n    g.addColorStop(1, 'rgba(0,0,0,0)');\n    d.fillStyle = g;\n    d.beginPath(); d.arc(x, y, BRUSH, 0, 7); d.fill();\n    d.restore();\n  }\n\n  \/* ---------- canvas sizing ---------- *\/\n  function fit() {\n    var r = stage.getBoundingClientRect();\n    if (!r.width) return;\n    var dpr = Math.min(window.devicePixelRatio || 1, 2);\n    cv.width = Math.round(r.width * dpr);\n    cv.height = Math.round(r.height * dpr);\n    ctx.setTransform(1, 0, 0, 1, 0, 0);\n    ctx.scale(cv.width \/ W, cv.height \/ H);\n    render(performance.now());\n  }\n  if (window.ResizeObserver) new ResizeObserver(fit).observe(stage);\n  else window.addEventListener('resize', fit);\n\n  \/* ---------- sound ---------- *\/\n  var ac = null, noiseBuf = null, hiss = null;\n  function blip(freq, dur, vol) {\n    if (!ac) return;\n    var o = ac.createOscillator(), g = ac.createGain();\n    o.type = 'sine'; o.frequency.value = freq;\n    g.gain.setValueAtTime(vol || .1, ac.currentTime);\n    g.gain.exponentialRampToValueAtTime(.0001, ac.currentTime + dur);\n    o.connect(g); g.connect(ac.destination);\n    o.start(); o.stop(ac.currentTime + dur);\n  }\n  function hissOn() {\n    if (!ac || hiss) return;\n    if (!noiseBuf) {\n      noiseBuf = ac.createBuffer(1, ac.sampleRate, ac.sampleRate);\n      var data = noiseBuf.getChannelData(0);\n      for (var i = 0; i < data.length; i++) data[i] = Math.random() * 2 - 1;\n    }\n    var s = ac.createBufferSource(), f = ac.createBiquadFilter(), g = ac.createGain();\n    s.buffer = noiseBuf; s.loop = true;\n    f.type = 'highpass'; f.frequency.value = 1700;\n    g.gain.setValueAtTime(.0001, ac.currentTime);\n    g.gain.exponentialRampToValueAtTime(.055, ac.currentTime + .05);\n    s.connect(f); f.connect(g); g.connect(ac.destination);\n    s.start();\n    hiss = { s: s, g: g };\n  }\n  function hissOff() {\n    if (!hiss || !ac) return;\n    var now = ac.currentTime;\n    hiss.g.gain.cancelScheduledValues(now);\n    hiss.g.gain.setValueAtTime(Math.max(hiss.g.gain.value, .0001), now);\n    hiss.g.gain.exponentialRampToValueAtTime(.0001, now + .08);\n    hiss.s.stop(now + .1);\n    hiss = null;\n  }\n\n  \/* ---------- state ---------- *\/\n  var state = 'idle';     \/\/ idle | play | shine | out | in | done\n  var idx, dirty0, clean, dirtAlpha, ox, pressing, aim, lastDab, drops, stars;\n  var startAt, stateAt, lastMeasure, touched, loaded = false;\n\n  function loadCar() {\n    var v = VEHICLES[idx];\n    paintCar(v);\n    paintDirt(v);\n    dirty0 = Math.max(1, dirtyCount());\n    clean = 0; dirtAlpha = 1; lastDab = null;\n    elCarNo.textContent = 'Car ' + (idx + 1) + ' of ' + VEHICLES.length;\n    elCarName.textContent = v.name;\n    setMeter(0);\n    loaded = true;\n  }\n  function setMeter(p) {\n    var n = Math.min(100, Math.round(p * 100 \/ DONE_AT));\n    elPct.textContent = String(n);\n    elBar.style.transform = 'scaleX(' + (n \/ 100).toFixed(3) + ')';\n  }\n  function pop(text) {\n    elPop.textContent = text;\n    elPop.className = 'cw-pop';\n    void elPop.offsetWidth;\n    elPop.className = 'cw-pop is-on';\n  }\n\n  \/* ---------- drawing ---------- *\/\n  var LEDS = ['#FF5FA2', '#5FD4FF', '#FFD23F'];\n  function drawBay(t) {\n    ctx.fillStyle = '#1F66A8'; ctx.fillRect(0, 0, W, FLOOR);\n    ctx.fillStyle = 'rgba(255,255,255,.05)';\n    for (var y = 36; y < FLOOR; y += 36) ctx.fillRect(0, y, W, 18);\n    for (var x = 15, i = 0; x < W; x += 30, i++) {\n      var col = LEDS[i % 3], pulse = reduce ? 1 : .75 + .25 * Math.sin(t * .003 + i);\n      var g = ctx.createRadialGradient(x, 196, 0, x, 196, 13);\n      g.addColorStop(0, col); g.addColorStop(1, 'rgba(31,102,168,0)');\n      ctx.globalAlpha = .55 * pulse; ctx.fillStyle = g;\n      ctx.beginPath(); ctx.arc(x, 196, 13, 0, 7); ctx.fill();\n      ctx.globalAlpha = 1; ctx.fillStyle = col;\n      ctx.beginPath(); ctx.arc(x, 196, 3.4, 0, 7); ctx.fill();\n    }\n    ctx.fillStyle = 'rgba(0,0,0,.18)'; ctx.fillRect(0, FLOOR - 14, W, 14);\n    ctx.fillStyle = '#2C3540'; ctx.fillRect(0, FLOOR, W, H - FLOOR);\n  }\n\n  function drawFloorOver() {\n    var g = ctx.createLinearGradient(0, FLOOR, 0, FLOOR + 130);\n    g.addColorStop(0, 'rgba(44,53,64,0)');\n    g.addColorStop(1, 'rgba(44,53,64,.96)');\n    ctx.fillStyle = g; ctx.fillRect(0, FLOOR, W, H - FLOOR);\n    ctx.fillStyle = 'rgba(255,255,255,.14)'; ctx.fillRect(0, FLOOR, W, 2);\n    ctx.fillStyle = '#1E252D'; roundRect(ctx, 146, 596, 68, 12, 3); ctx.fill();\n    ctx.fillStyle = '#39434E';\n    for (var x = 152; x < 210; x += 8) ctx.fillRect(x, 599, 3, 6);\n  }\n\n  function drawWand(tx, ty, on) {\n    var bx = 392, by = 700, dx = tx - bx, dy = ty - by;\n    var L = Math.hypot(dx, dy) || 1, ux = dx \/ L, uy = dy \/ L;\n    var tipX = tx - ux * 58, tipY = ty - uy * 58;\n    var gunX = tipX - ux * 128, gunY = tipY - uy * 128;\n    if (on) {\n      var px = -uy, py = ux;\n      ctx.fillStyle = 'rgba(232,247,255,.4)';\n      ctx.beginPath();\n      ctx.moveTo(tipX + px * 2, tipY + py * 2); ctx.lineTo(tx + px * 17, ty + py * 17);\n      ctx.lineTo(tx - px * 17, ty - py * 17); ctx.lineTo(tipX - px * 2, tipY - py * 2);\n      ctx.closePath(); ctx.fill();\n      var g = ctx.createRadialGradient(tx, ty, 0, tx, ty, 30);\n      g.addColorStop(0, 'rgba(255,255,255,.6)'); g.addColorStop(1, 'rgba(255,255,255,0)');\n      ctx.fillStyle = g; ctx.beginPath(); ctx.arc(tx, ty, 30, 0, 7); ctx.fill();\n    }\n    ctx.lineCap = 'round';\n    ctx.strokeStyle = '#AEB9C4'; ctx.lineWidth = 5;\n    ctx.beginPath(); ctx.moveTo(tipX, tipY); ctx.lineTo(gunX, gunY); ctx.stroke();\n    ctx.strokeStyle = '#FFD23F'; ctx.lineWidth = 16;\n    ctx.beginPath(); ctx.moveTo(gunX, gunY); ctx.lineTo(bx, by); ctx.stroke();\n    ctx.strokeStyle = '#1E252D'; ctx.lineWidth = 7;\n    ctx.beginPath(); ctx.moveTo(tipX, tipY); ctx.lineTo(tipX - ux * 10, tipY - uy * 10); ctx.stroke();\n  }\n\n  function drawStar(x, y, s) {\n    ctx.beginPath();\n    ctx.moveTo(x, y - s); ctx.quadraticCurveTo(x, y, x + s, y);\n    ctx.quadraticCurveTo(x, y, x, y + s); ctx.quadraticCurveTo(x, y, x - s, y);\n    ctx.quadraticCurveTo(x, y, x, y - s); ctx.closePath(); ctx.fill();\n  }\n\n  function render(t) {\n    drawBay(t);\n    var cx = ox || 0, show = loaded && state !== 'done';\n\n    if (show) {\n      \/\/ reflection on the wet floor\n      ctx.save();\n      ctx.beginPath(); ctx.rect(0, FLOOR, W, H - FLOOR); ctx.clip();\n      ctx.translate(cx, FLOOR * 2); ctx.scale(1, -1);\n      ctx.globalAlpha = .22; ctx.drawImage(CAR.c, 0, 0, W, H);\n      ctx.globalAlpha = .22 * dirtAlpha; ctx.drawImage(DIRT.c, 0, 0, W, H);\n      ctx.restore();\n    }\n    drawFloorOver();\n\n    if (show) {\n      ctx.fillStyle = 'rgba(0,0,0,.35)';\n      ctx.beginPath(); ctx.ellipse(180 + cx, FLOOR + 1, 152, 6, 0, 0, 7); ctx.fill();\n      ctx.drawImage(CAR.c, cx, 0, W, H);\n      ctx.globalAlpha = dirtAlpha; ctx.drawImage(DIRT.c, cx, 0, W, H); ctx.globalAlpha = 1;\n\n      var i;\n      ctx.fillStyle = 'rgba(222,242,255,.85)';\n      for (i = 0; i < drops.length; i++) {\n        var dr = drops[i];\n        ctx.globalAlpha = Math.max(dr.life, 0);\n        ctx.beginPath(); ctx.arc(dr.x, dr.y, dr.r, 0, 7); ctx.fill();\n      }\n      ctx.globalAlpha = 1;\n      for (i = 0; i < stars.length; i++) {\n        var st = stars[i], k = Math.sin(Math.max(0, Math.min(1, st.life)) * Math.PI);\n        ctx.fillStyle = i % 2 ? '#FFFFFF' : '#FFF3B0';\n        drawStar(st.x + cx, st.y, st.s * k);\n      }\n      if (state === 'play' || state === 'shine') drawWand(aim.x, aim.y, pressing && state === 'play');\n    }\n  }\n\n  \/* ---------- loop ---------- *\/\n  var last = 0;\n  function frame(now) {\n    if (state === 'idle' || state === 'done') return;\n    var dt = Math.min((now - last) || 16, 34) \/ 16.667, i;\n    last = now;\n\n    var spraying = pressing && state === 'play';\n    if (spraying) { hissOn(); } else { hissOff(); }\n\n    if (spraying) {\n      var tx = aim.x - ox, ty = aim.y;\n      if (!lastDab) { dab(tx, ty); lastDab = { x: tx, y: ty }; }\n      var dx = tx - lastDab.x, dy = ty - lastDab.y, dist = Math.hypot(dx, dy), steps = Math.max(1, Math.ceil(dist \/ 5));\n      for (i = 1; i <= steps; i++) dab(lastDab.x + dx * i \/ steps, lastDab.y + dy * i \/ steps);\n      dab(tx, ty);                       \/\/ holding still keeps blasting\n      lastDab = { x: tx, y: ty };\n      for (i = 0; i < (reduce ? 1 : 3); i++) {\n        drops.push({ x: aim.x, y: aim.y, vx: (Math.random() - .5) * 5, vy: -Math.random() * 2.6 - .4, r: 1 + Math.random() * 1.8, life: 1 });\n      }\n    }\n\n    if (state === 'play' && now - lastMeasure > 150) {\n      lastMeasure = now;\n      clean = Math.max(clean, 1 - dirtyCount() \/ dirty0);\n      setMeter(clean);\n      if (clean >= DONE_AT) {\n        state = 'shine'; stateAt = now; pressing = false; lastDab = null;\n        hissOff();\n        setMeter(1);\n        pop('Spotless.');\n        blip(784, .12, .09); setTimeout(function () { blip(1175, .24, .09); }, 110);\n        for (i = 0; i < (reduce ? 4 : 14); i++) {\n          stars.push({ x: BOX.x + 20 + Math.random() * (BOX.w - 40), y: 322 + Math.random() * 100, s: 5 + Math.random() * 7, life: -Math.random() * .5 });\n        }\n      }\n    }\n\n    if (state === 'shine') {\n      dirtAlpha = Math.max(0, 1 - (now - stateAt) \/ 380);\n      if (now - stateAt > 1050) { state = 'out'; stateAt = now; }\n    } else if (state === 'out') {\n      var po = (now - stateAt) \/ 480;\n      ox = reduce ? 0 : 440 * po * po;\n      if (po >= 1) {\n        if (idx < VEHICLES.length - 1) {\n          idx++; loadCar(); stars = [];\n          state = 'in'; stateAt = now; ox = reduce ? 0 : -440;\n        } else { finish(); return; }\n      }\n    } else if (state === 'in') {\n      var pi = Math.min((now - stateAt) \/ 520, 1);\n      ox = reduce ? 0 : -440 * Math.pow(1 - pi, 3);\n      if (pi >= 1) { ox = 0; state = 'play'; lastMeasure = now; }\n    }\n\n    for (i = drops.length - 1; i >= 0; i--) {\n      var d = drops[i];\n      d.x += d.vx * dt; d.y += d.vy * dt; d.vy += .32 * dt; d.life -= .045 * dt;\n      if (d.life <= 0) drops.splice(i, 1);\n    }\n    for (i = stars.length - 1; i >= 0; i--) {\n      stars[i].life += .028 * dt;\n      if (stars[i].life >= 1) stars.splice(i, 1);\n    }\n\n    render(now);\n    requestAnimationFrame(frame);\n  }\n\n  \/* ---------- flow ---------- *\/\n  function begin() {\n    if (!ac) {\n      try { ac = new (window.AudioContext || window.webkitAudioContext)(); } catch (err) { ac = null; }\n    }\n    if (ac && ac.state === 'suspended') ac.resume();\n    idx = 0; ox = 0; drops = []; stars = []; pressing = false; touched = false;\n    aim = { x: 250, y: 372 };\n    loadCar(); fit();\n    elStart.hidden = true; elEnd.hidden = true;\n    elHud.hidden = false; elHint.hidden = false;\n    stage.classList.add('is-playing');\n    state = 'play';\n    startAt = last = lastMeasure = performance.now();\n    requestAnimationFrame(frame);\n    try { stage.focus({ preventScroll: true }); } catch (e) {}\n  }\n\n  function finish() {\n    state = 'done';\n    hissOff();\n    pressing = false;\n    stage.classList.remove('is-playing');\n    elHud.hidden = true; elHint.hidden = true;\n    var secs = Math.round((performance.now() - startAt) \/ 1000);\n    q('verdict').textContent = secs <= 28 ? 'Showroom shine.' : secs <= 45 ? 'Road-trip ready.' : 'Clean enough to see yourself.';\n    q('scoreLine').textContent = 'Three rides, spotless in ' + Math.floor(secs \/ 60) + ':' + ('0' + secs % 60).slice(-2);\n    var chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789', out = '';\n    for (var i = 0; i < 4; i++) out += chars[(Math.random() * chars.length) | 0];\n    q('code').textContent = CONFIG.codePrefix + '-' + out;\n    elEnd.hidden = false;\n    blip(659, .12, .09); setTimeout(function () { blip(988, .26, .09); }, 120);\n    render(performance.now());\n  }\n\n  \/* ---------- input ---------- *\/\n  function toLogical(e) {\n    var r = stage.getBoundingClientRect();\n    return {\n      x: Math.max(8, Math.min(W - 8, (e.clientX - r.left) \/ r.width * W)),\n      y: Math.max(230, Math.min(FLOOR + 10, (e.clientY - r.top) \/ r.height * H))\n    };\n  }\n  function active() { return state !== 'idle' && state !== 'done'; }\n\n  stage.addEventListener('pointerdown', function (e) {\n    if (!active()) return;\n    if (e.target.closest && e.target.closest('button,a')) return;\n    e.preventDefault();\n    try { stage.setPointerCapture(e.pointerId); } catch (err) {}\n    aim = toLogical(e);\n    pressing = true; lastDab = null;\n    if (!touched) { touched = true; elHint.hidden = true; }\n  });\n  stage.addEventListener('pointermove', function (e) {\n    if (!active()) return;\n    aim = toLogical(e);\n  });\n  function release() { pressing = false; lastDab = null; }\n  window.addEventListener('pointerup', release);\n  window.addEventListener('pointercancel', release);\n  window.addEventListener('blur', release);\n  stage.addEventListener('contextmenu', function (e) { if (active()) e.preventDefault(); });\n\n  stage.addEventListener('keydown', function (e) {\n    if (!active()) return;\n    var k = e.key, step = 12;\n    if (k === 'ArrowLeft') aim.x = Math.max(8, aim.x - step);\n    else if (k === 'ArrowRight') aim.x = Math.min(W - 8, aim.x + step);\n    else if (k === 'ArrowUp') aim.y = Math.max(230, aim.y - step);\n    else if (k === 'ArrowDown') aim.y = Math.min(FLOOR + 10, aim.y + step);\n    else if (k === ' ' || e.code === 'Space') {\n      if (!e.repeat) { pressing = true; lastDab = null; if (!touched) { touched = true; elHint.hidden = true; } }\n    } else return;\n    e.preventDefault();\n  });\n  stage.addEventListener('keyup', function (e) {\n    if (e.key === ' ' || e.code === 'Space') { e.preventDefault(); release(); }\n  });\n\n  q('go').addEventListener('click', begin);\n  q('again').addEventListener('click', begin);\n\n  idx = 0; ox = 0; drops = []; stars = []; pressing = false;\n  aim = { x: 250, y: 372 };\n  loadCar();\n  fit();\n})();\n<\/script><\/div><div class=\"x-col e16-e48 mg-w mg-x mg-y mg-z\"><!-- ======================================================================\n     AFTER THE CRASH \u2014 inline embed (personal injury law firm)\n     Paste this whole block into a Cornerstone \"Raw Content\" element.\n     Everything is scoped to #acEmbed; nothing touches <html> or <body>.\n\n     To adapt for a firm, edit two blocks at the top of the script:\n       CONFIG \u2014 firm name, city, phone, links, legal line, logo\n       CARDS  \u2014 every statement and explanation, English and Spanish.\n                Have the firm's attorney approve this block before launch.\n\n     This is attorney advertising. In Texas it must be filed with the\n     State Bar Advertising Review Committee. One instance per page.\n     ====================================================================== -->\n\n<div id=\"acEmbed\">\n  <div class=\"ac-frame\">\n    <div class=\"ac-stage\" data-ac=\"stage\" tabindex=\"0\">\n      <div class=\"ac-sign\" aria-hidden=\"true\"><\/div>\n\n      <div class=\"ac-lang\" role=\"group\" aria-label=\"Language \/ Idioma\">\n        <button type=\"button\" data-ac-lang=\"en\" aria-label=\"English\">EN<\/button>\n        <button type=\"button\" data-ac-lang=\"es\" aria-label=\"Espa\u00f1ol\">ES<\/button>\n      <\/div>\n\n      <div class=\"ac-hud\" data-ac=\"hud\" hidden>\n        <div class=\"ac-prog\" data-ac=\"prog\"><\/div>\n        <div class=\"ac-segs\" data-ac=\"segs\"><\/div>\n      <\/div>\n\n      <div class=\"ac-deck\" data-ac=\"deck\" hidden>\n        <div class=\"ac-back ac-back-2\" aria-hidden=\"true\"><\/div>\n        <div class=\"ac-back ac-back-1\" aria-hidden=\"true\"><\/div>\n        <div class=\"ac-card\" data-ac=\"card\">\n          <span class=\"ac-stamp ac-stamp-do\" data-ac=\"stampDo\" aria-hidden=\"true\"><\/span>\n          <span class=\"ac-stamp ac-stamp-dont\" data-ac=\"stampDont\" aria-hidden=\"true\"><\/span>\n          <p class=\"ac-card-kicker\" data-ac=\"cardKicker\"><\/p>\n          <p class=\"ac-card-text\" data-ac=\"cardText\" aria-live=\"polite\"><\/p>\n        <\/div>\n        <div class=\"ac-fb\" data-ac=\"fb\" hidden aria-live=\"polite\">\n          <div class=\"ac-fb-head\" data-ac=\"fbHead\"><\/div>\n          <p class=\"ac-fb-rule\"><span class=\"ac-fb-icon\" data-ac=\"fbIcon\"><\/span><span data-ac=\"fbRule\"><\/span><\/p>\n          <p class=\"ac-fb-why\" data-ac=\"fbWhy\"><\/p>\n          <div class=\"ac-fb-foot\">\n            <span data-ac=\"fbTap\"><\/span>\n            <span class=\"ac-fb-timer\"><i data-ac=\"fbTimer\"><\/i><\/span>\n          <\/div>\n        <\/div>\n      <\/div>\n\n      <div class=\"ac-controls\" data-ac=\"controls\" hidden>\n        <button class=\"ac-choice ac-choice-dont\" data-ac=\"btnDont\" type=\"button\">\n          <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M6 6l12 12M18 6L6 18\"\/><\/svg>\n          <span data-ac=\"lblDont\"><\/span>\n        <\/button>\n        <button class=\"ac-choice ac-choice-do\" data-ac=\"btnDo\" type=\"button\">\n          <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M4.5 12.5l5 5L19.5 7\"\/><\/svg>\n          <span data-ac=\"lblDo\"><\/span>\n        <\/button>\n      <\/div>\n      <p class=\"ac-hint\" data-ac=\"hint\" hidden><\/p>\n\n      <div class=\"ac-screen\" data-ac=\"start\">\n        <img class=\"ac-logo\" data-ac=\"logo\" alt=\"\" hidden>\n        <svg class=\"ac-hazard\" viewBox=\"0 0 64 56\" aria-hidden=\"true\">\n          <path d=\"M32 3L61 53H3z\" fill=\"#F2A900\" stroke=\"#16211B\" stroke-width=\"3.5\" stroke-linejoin=\"round\"\/>\n          <path d=\"M32 20v16\" stroke=\"#16211B\" stroke-width=\"5\" stroke-linecap=\"round\"\/>\n          <circle cx=\"32\" cy=\"44\" r=\"3.2\" fill=\"#16211B\"\/>\n        <\/svg>\n        <div class=\"ac-tab\" data-ac=\"tab\"><\/div>\n        <h3 class=\"ac-h1\"><span data-ac=\"title1\"><\/span><br><span data-ac=\"title2\"><\/span><\/h3>\n        <p class=\"ac-sub\" data-ac=\"sub\"><\/p>\n        <button class=\"ac-btn\" type=\"button\" data-ac=\"go\"><\/button>\n        <p class=\"ac-firm\" data-ac=\"firm\"><\/p>\n      <\/div>\n\n      <div class=\"ac-screen ac-end\" data-ac=\"end\" hidden>\n        <h3 class=\"ac-h2\" data-ac=\"verdict\"><\/h3>\n        <p class=\"ac-score\" data-ac=\"score\"><\/p>\n        <div class=\"ac-list\">\n          <p class=\"ac-list-title\" data-ac=\"listTitle\"><\/p>\n          <div class=\"ac-cols\">\n            <div><p class=\"ac-col-h ac-col-do\" data-ac=\"colDo\"><\/p><ul data-ac=\"listDo\"><\/ul><\/div>\n            <div><p class=\"ac-col-h ac-col-dont\" data-ac=\"colDont\"><\/p><ul data-ac=\"listDont\"><\/ul><\/div>\n          <\/div>\n        <\/div>\n        <a class=\"ac-btn\" data-ac=\"call\" href=\"#\"><\/a>\n        <a class=\"ac-ghost\" data-ac=\"checklist\" href=\"#\" target=\"_blank\" rel=\"noopener\"><\/a>\n        <button class=\"ac-linkish\" type=\"button\" data-ac=\"again\"><\/button>\n        <p class=\"ac-legal\" data-ac=\"legal\"><\/p>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<style>\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Overpass:wght@400..900&display=swap');\n\n#acEmbed{\n  --ac-sign:#0E6B45; --ac-sign-deep:#0A5236; --ac-paper:#F4F1EA; --ac-ink:#16211B;\n  --ac-do:#1C7C45; --ac-dont:#C2372B; --ac-amber:#F2A900; --ac-amber-edge:#A87500;\n  width:100%;\n  max-width:min(420px, 44vh);\n  margin:0 auto;\n}\n#acEmbed *{box-sizing:border-box}\n#acEmbed .ac-frame{position:relative;width:100%;padding-top:177.78%;container-type:inline-size}\n#acEmbed .ac-stage{\n  position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;\n  background:var(--ac-sign);border-radius:18px;color:var(--ac-paper);\n  font-family:Overpass,'Helvetica Neue',Helvetica,Arial,sans-serif;\n  font-size:16px;font-size:4.444cqw;line-height:1.3;\n  -webkit-user-select:none;user-select:none;-webkit-touch-callout:none;outline:none;\n}\n#acEmbed .ac-stage:focus-visible{box-shadow:inset 0 0 0 3px var(--ac-amber)}\n#acEmbed .ac-sign{\n  position:absolute;top:2.2%;left:3.6%;right:3.6%;bottom:2.2%;\n  border:.26em solid var(--ac-paper);border-radius:1em;pointer-events:none;\n}\n#acEmbed [hidden]{display:none !important}\n#acEmbed button{font-family:inherit}\n\n\/* language toggle *\/\n#acEmbed .ac-lang{\n  position:absolute;top:5.2%;right:8%;z-index:5;display:flex;\n  border:.12em solid rgba(244,241,234,.7);border-radius:99px;overflow:hidden;\n}\n#acEmbed .ac-lang button{\n  background:transparent;border:0;color:var(--ac-paper);cursor:pointer;\n  font-size:.72em;font-weight:800;letter-spacing:.06em;padding:.4em .8em;\n}\n#acEmbed .ac-lang button[aria-pressed=\"true\"]{background:var(--ac-paper);color:var(--ac-sign)}\n#acEmbed .ac-lang button:focus-visible{outline:2px solid var(--ac-amber);outline-offset:-2px}\n\n\/* hud *\/\n#acEmbed .ac-hud{position:absolute;top:5.4%;left:8%;right:32%;z-index:4;pointer-events:none}\n#acEmbed .ac-prog{font-size:.8em;font-weight:700;letter-spacing:.02em;opacity:.9}\n#acEmbed .ac-segs{display:flex;gap:.22em;margin-top:.45em}\n#acEmbed .ac-seg{flex:1;height:.3em;border-radius:99px;background:rgba(244,241,234,.28)}\n#acEmbed .ac-seg.is-now{background:var(--ac-paper)}\n#acEmbed .ac-seg.is-right{background:#7FD6A2}\n#acEmbed .ac-seg.is-wrong{background:#F29A8E}\n\n\/* deck *\/\n#acEmbed .ac-deck{position:absolute;left:9%;right:9%;top:16.5%;height:50%;z-index:3}\n#acEmbed .ac-back,#acEmbed .ac-card,#acEmbed .ac-fb{\n  position:absolute;top:0;left:0;right:0;bottom:0;border-radius:1.1em;\n}\n#acEmbed .ac-back{background:var(--ac-paper)}\n#acEmbed .ac-back-1{transform:translateY(.55em) scale(.955);opacity:.55}\n#acEmbed .ac-back-2{transform:translateY(1.1em) scale(.91);opacity:.28}\n#acEmbed .ac-card{\n  background:var(--ac-paper);color:var(--ac-ink);\n  display:flex;flex-direction:column;justify-content:center;padding:1.4em 1.3em;\n  box-shadow:0 .5em 1.4em rgba(5,30,18,.35);cursor:grab;touch-action:none;will-change:transform;\n}\n#acEmbed .ac-card:active{cursor:grabbing}\n#acEmbed .ac-card-kicker{margin:0;font-size:.78em;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--ac-sign)}\n#acEmbed .ac-card-text{margin:.5em 0 0;font-size:1.42em;font-weight:800;line-height:1.16;letter-spacing:-.01em}\n#acEmbed .ac-stamp{\n  position:absolute;top:.9em;font-size:1.25em;font-weight:900;letter-spacing:.06em;\n  padding:.12em .5em;border:.16em solid;border-radius:.3em;opacity:0;pointer-events:none;\n}\n#acEmbed .ac-stamp-do{left:.9em;color:var(--ac-do);transform:rotate(-12deg)}\n#acEmbed .ac-stamp-dont{right:.9em;color:var(--ac-dont);transform:rotate(12deg)}\n\n\/* feedback *\/\n#acEmbed .ac-fb{\n  background:var(--ac-paper);color:var(--ac-ink);overflow:hidden;\n  display:flex;flex-direction:column;padding:0 1.3em 1em;cursor:pointer;\n  box-shadow:0 .5em 1.4em rgba(5,30,18,.35);\n  animation:acIn .32s cubic-bezier(.16,1,.3,1) both;\n}\n#acEmbed .ac-fb-head{\n  margin:0 -1.3em;padding:.85em 1.3em .7em;font-size:1.3em;font-weight:900;letter-spacing:-.01em;color:#fff;\n  background:var(--ac-do);\n}\n#acEmbed .ac-fb.is-wrong .ac-fb-head{background:var(--ac-dont)}\n#acEmbed .ac-fb-rule{display:flex;align-items:center;gap:.45em;margin:.9em 0 0;font-size:1.05em;font-weight:800}\n#acEmbed .ac-fb-icon{\n  display:inline-flex;align-items:center;justify-content:center;width:1.5em;height:1.5em;border-radius:50%;\n  color:#fff;font-size:.8em;flex-shrink:0;\n}\n#acEmbed .ac-fb-icon svg{width:1em;height:1em;fill:none;stroke:currentColor;stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round}\n#acEmbed .ac-fb-why{margin:.6em 0 0;font-size:.98em;line-height:1.42;font-weight:500;color:#34403A}\n#acEmbed .ac-fb-foot{\n  margin-top:auto;display:flex;align-items:center;justify-content:space-between;gap:.8em;\n  font-size:.72em;font-weight:700;color:#5C6862;padding-top:.8em;\n}\n#acEmbed .ac-fb-timer{flex:0 0 32%;height:.35em;border-radius:99px;background:rgba(22,33,27,.12);overflow:hidden}\n#acEmbed .ac-fb-timer i{display:block;height:100%;width:100%;background:var(--ac-sign);transform-origin:left;transform:scaleX(0)}\n#acEmbed .ac-fb-timer i.is-running{animation:acTimer var(--ac-auto,6s) linear forwards}\n@keyframes acTimer{from{transform:scaleX(0)}to{transform:scaleX(1)}}\n@keyframes acIn{from{opacity:0;transform:translateY(.8em) scale(.97)}to{opacity:1;transform:none}}\n\n\/* choices *\/\n#acEmbed .ac-controls{position:absolute;left:9%;right:9%;top:71.5%;z-index:3;display:flex;gap:.7em}\n#acEmbed .ac-choice{\n  flex:1;display:flex;align-items:center;justify-content:center;gap:.45em;\n  min-height:3.1em;border-radius:99px;border:0;cursor:pointer;\n  background:var(--ac-paper);font-size:1.05em;font-weight:900;letter-spacing:.01em;\n  box-shadow:0 .22em 0 rgba(5,30,18,.4);\n}\n#acEmbed .ac-choice svg{width:1.15em;height:1.15em;fill:none;stroke:currentColor;stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round}\n#acEmbed .ac-choice-do{color:var(--ac-do)}\n#acEmbed .ac-choice-dont{color:var(--ac-dont)}\n#acEmbed .ac-choice:active{transform:translateY(.15em);box-shadow:0 .07em 0 rgba(5,30,18,.4)}\n#acEmbed .ac-choice:focus-visible{outline:3px solid var(--ac-amber);outline-offset:3px}\n#acEmbed .ac-hint{\n  position:absolute;left:10%;right:10%;top:84%;z-index:3;margin:0;text-align:center;\n  font-size:.82em;font-weight:600;line-height:1.35;opacity:.85;pointer-events:none;\n}\n\n\/* start + end screens *\/\n#acEmbed .ac-screen{\n  position:absolute;top:0;left:0;right:0;bottom:0;z-index:4;\n  display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;\n  gap:.95em;padding:14% 11% 10%;\n}\n#acEmbed .ac-logo{width:auto;max-width:11em;max-height:4em;object-fit:contain;display:block}\n#acEmbed .ac-hazard{width:3.4em;height:auto;display:block}\n#acEmbed .ac-tab{\n  font-size:.74em;font-weight:900;letter-spacing:.14em;text-transform:uppercase;\n  border:.16em solid var(--ac-paper);border-radius:.4em;padding:.35em .8em .25em;\n}\n#acEmbed .ac-h1{margin:0;font-size:3em;font-weight:900;line-height:.92;letter-spacing:-.025em;color:var(--ac-paper)}\n#acEmbed .ac-sub{margin:0;font-size:1em;line-height:1.42;font-weight:500;max-width:18em;opacity:.92}\n#acEmbed .ac-firm{margin:0;font-size:.72em;font-weight:700;letter-spacing:.08em;text-transform:uppercase;opacity:.75}\n#acEmbed .ac-btn{\n  display:inline-flex;align-items:center;justify-content:center;text-decoration:none;text-align:center;\n  background:var(--ac-amber);color:var(--ac-ink);border:0;border-radius:99px;cursor:pointer;\n  font-size:1.02em;font-weight:900;line-height:1.15;padding:.95em 1.7em .85em;\n  box-shadow:0 .25em 0 var(--ac-amber-edge);\n}\n#acEmbed .ac-btn:hover{background:var(--ac-amber);color:var(--ac-ink)}\n#acEmbed .ac-btn:active{transform:translateY(.18em);box-shadow:0 .07em 0 var(--ac-amber-edge)}\n#acEmbed .ac-btn:focus-visible,#acEmbed .ac-ghost:focus-visible,#acEmbed .ac-linkish:focus-visible{outline:3px solid var(--ac-paper);outline-offset:3px}\n\n#acEmbed .ac-end{gap:.65em;padding:13% 10% 8%}\n#acEmbed .ac-h2{margin:0;font-size:1.6em;font-weight:900;line-height:1.05;letter-spacing:-.015em;color:var(--ac-paper)}\n#acEmbed .ac-score{margin:-.2em 0 0;font-size:.82em;font-weight:700;opacity:.82}\n#acEmbed .ac-list{\n  width:100%;background:var(--ac-paper);color:var(--ac-ink);border-radius:.9em;padding:.85em .9em .8em;text-align:left;\n  animation:acIn .45s cubic-bezier(.16,1,.3,1) both;\n}\n#acEmbed .ac-list-title{margin:0 0 .5em;font-size:.86em;font-weight:900}\n#acEmbed .ac-cols{display:grid;grid-template-columns:1fr 1fr;gap:.7em}\n#acEmbed .ac-col-h{margin:0 0 .25em;font-size:.64em;font-weight:900;letter-spacing:.1em;text-transform:uppercase}\n#acEmbed .ac-col-do{color:var(--ac-do)}\n#acEmbed .ac-col-dont{color:var(--ac-dont)}\n#acEmbed .ac-list ul{margin:0;padding:0;list-style:none}\n#acEmbed .ac-list li{font-size:.68em;font-weight:600;line-height:1.3;padding:.22em 0;border-top:1px solid rgba(22,33,27,.1)}\n#acEmbed .ac-ghost{\n  display:inline-block;text-decoration:none;color:var(--ac-paper);\n  font-size:.82em;font-weight:800;border:.13em solid rgba(244,241,234,.7);border-radius:99px;padding:.6em 1.2em .5em;\n}\n#acEmbed .ac-ghost:hover{color:var(--ac-paper);background:rgba(244,241,234,.08)}\n#acEmbed .ac-linkish{\n  background:none;border:0;color:var(--ac-paper);opacity:.75;cursor:pointer;\n  font-size:.74em;font-weight:700;text-decoration:underline;padding:.2em .5em;\n}\n#acEmbed .ac-legal{margin:0;font-size:.56em;line-height:1.35;opacity:.7;max-width:26em}\n\n#acEmbed .ac-sub,#acEmbed .ac-h1,#acEmbed .ac-h2,#acEmbed .ac-card-text,#acEmbed .ac-btn{text-wrap:balance}\n#acEmbed .ac-fb-why,#acEmbed .ac-legal{text-wrap:pretty}\n\n@media (prefers-reduced-motion:reduce){\n  #acEmbed .ac-fb,#acEmbed .ac-list{animation-duration:.01s}\n}\n<\/style>\n\n<script>\n(function () {\n  'use strict';\n  var root = document.getElementById('acEmbed');\n  if (!root || root.dataset.acReady) return;\n  root.dataset.acReady = '1';\n\n  \/* =================================================================\n     CONFIG \u2014 the firm's details. Everything visible to a visitor that\n     isn't a card lives here.\n  ================================================================== *\/\n  var CONFIG = {\n    firm: 'Northstar Injury Law',\n    city: 'Brownsville',\n    phone: '+19565550100',                    \/\/ used for the tel: link\n    phoneLabel: '(956) 555-0100',\n    checklistLink: '#',                        \/\/ printable PDF of the checklist\n    defaultLang: 'en',                         \/\/ 'en' or 'es'\n    autoAdvanceMs: 6000,                       \/\/ 0 = only advance on tap\n    \/\/ Demo text. For a real firm, the attorney supplies this line, e.g.\n    \/\/ 'Attorney advertising. [Responsible attorney], [Office city], Texas.'\n    legal: {\n      en: 'Demonstration only. Northstar Injury Law is a fictional firm. Playing this game does not create an attorney-client relationship.',\n      es: 'Solo demostraci\\u00F3n. Northstar Injury Law es un despacho ficticio. Jugar este juego no crea una relaci\\u00F3n abogado-cliente.'\n    },\n    logo: ''\n  };\n\n  \/* =================================================================\n     CARDS \u2014 have the firm's attorney approve every line here.\n     answer: 'do' or 'dont'. The first card always plays first; the\n     rest shuffle each round so nobody can learn a pattern.\n  ================================================================== *\/\n  var CARDS = [\n    { answer: 'do',\n      en: { text: 'Call 911 if anyone is hurt or the cars are blocking traffic.',\n            why: 'Safety comes first. A police report also creates an official record of what happened.',\n            short: \"Call 911 if anyone's hurt\" },\n      es: { text: 'Llamar al 911 si alguien est\u00e1 herido o los carros bloquean el tr\u00e1fico.',\n            why: 'La seguridad es primero. Un reporte policial tambi\u00e9n deja un registro oficial de lo que pas\u00f3.',\n            short: 'Llamar al 911 si hay heridos' } },\n    { answer: 'dont',\n      en: { text: 'Tell the other driver, \\u201CI\\u2019m so sorry \\u2014 this was my fault.\\u201D',\n            why: 'Stay calm and kind, but don\\u2019t assign blame at the scene. Let the facts speak for themselves.',\n            short: 'Admit fault at the scene' },\n      es: { text: 'Decirle al otro conductor: \\u00ABPerd\\u00F3n, fue mi culpa.\\u00BB',\n            why: 'Mant\\u00E9n la calma y s\\u00E9 amable, pero no te eches la culpa en el lugar. Deja que los hechos hablen.',\n            short: 'Aceptar la culpa en el lugar' } },\n    { answer: 'do',\n      en: { text: 'Take photos of both cars, the road, and any injuries.',\n            why: 'Evidence fades fast. Photos from the scene can matter more than anything you remember later.',\n            short: 'Photograph everything' },\n      es: { text: 'Tomar fotos de los dos carros, el camino y cualquier lesi\\u00F3n.',\n            why: 'La evidencia desaparece r\\u00E1pido. Las fotos del momento pueden valer m\\u00E1s que lo que recuerdes despu\\u00E9s.',\n            short: 'Tomar fotos de todo' } },\n    { answer: 'dont',\n      en: { text: 'Skip the doctor because you feel fine.',\n            why: 'Some injuries don\\u2019t show up for hours or days. Getting checked also documents when it started.',\n            short: 'Skip the doctor' },\n      es: { text: 'No ir al doctor porque te sientes bien.',\n            why: 'Algunas lesiones no se notan hasta horas o d\\u00EDas despu\\u00E9s. Ir al doctor tambi\\u00E9n documenta cu\\u00E1ndo empez\\u00F3.',\n            short: 'Saltarte al doctor' } },\n    { answer: 'do',\n      en: { text: 'Get the other driver\\u2019s name, phone, insurance, and plate number.',\n            why: 'You\\u2019ll need all of it. Snap a photo of their insurance card and license plate.',\n            short: 'Get the other driver\\u2019s info' },\n      es: { text: 'Pedirle al otro conductor su nombre, tel\\u00E9fono, seguro y placa.',\n            why: 'Vas a necesitar todo. T\\u00F3male foto a su tarjeta de seguro y a la placa.',\n            short: 'Pedir los datos del otro conductor' } },\n    { answer: 'dont',\n      en: { text: 'Give the other driver\\u2019s insurance company a recorded statement right away.',\n            why: 'There\\u2019s no need to rush. Talk to a lawyer first \\u2014 their adjuster works for them, not for you.',\n            short: 'Give a recorded statement' },\n      es: { text: 'Darle una declaraci\\u00F3n grabada a la aseguradora del otro conductor de inmediato.',\n            why: 'No hay por qu\\u00E9 apurarse. Habla primero con un abogado: su ajustador trabaja para ellos, no para ti.',\n            short: 'Dar una declaraci\\u00F3n grabada' } },\n    { answer: 'do',\n      en: { text: 'Write down names and numbers of anyone who saw it happen.',\n            why: 'Witnesses leave quickly. A neutral account can settle a he-said, she-said.',\n            short: 'Collect witness contacts' },\n      es: { text: 'Anotar nombres y tel\\u00E9fonos de quien vio el accidente.',\n            why: 'Los testigos se van r\\u00E1pido. Un testimonio neutral puede aclarar qui\\u00E9n dijo qu\\u00E9.',\n            short: 'Anotar a los testigos' } },\n    { answer: 'dont',\n      en: { text: 'Post about the crash on social media that night.',\n            why: 'Posts can be screenshotted and used against you \\u2014 even a joke, or a quick \\u201Cwe\\u2019re fine!\\u201D',\n            short: 'Post about it online' },\n      es: { text: 'Publicar sobre el choque en redes sociales esa misma noche.',\n            why: 'Tus publicaciones pueden usarse en tu contra, hasta un chiste o un r\\u00E1pido \\u00AB\\u00A1estamos bien!\\u00BB',\n            short: 'Publicarlo en redes' } }\n  ];\n\n  var STR = {\n    en: {\n      tab: '8 quick calls', title1: 'After the', title2: 'Crash',\n      sub: 'Someone just hit your car. Do you know what to do next? Swipe to find out.',\n      go: 'Start', kicker: 'Do or don\\u2019t?',\n      hint: 'Swipe right if you should. Left if you shouldn\\u2019t.',\n      doLbl: 'Do', dontLbl: 'Don\\u2019t', stampDo: 'DO', stampDont: 'DON\\u2019T',\n      prog: 'Call {n} of {t}', right: 'Right call.', wrong: 'Not quite.',\n      ruleDo: 'Do it.', ruleDont: 'Don\\u2019t.', tap: 'Tap to continue',\n      score: '{n} of {t} right calls',\n      v3: 'You\\u2019d handle it like a pro.', v2: 'You know more than most.', v1: 'Good thing you played this first.',\n      listTitle: 'Your glovebox checklist', colDo: 'Do', colDont: 'Don\\u2019t',\n      call: 'Call for a free consultation', checklist: 'Get the printable checklist', again: 'Play again',\n      aria: 'After the Crash. Swipe the card right for do, left for don\\u2019t, or use the arrow keys.'\n    },\n    es: {\n      tab: '8 decisiones r\\u00E1pidas', title1: 'Despu\\u00E9s del', title2: 'Choque',\n      sub: 'Alguien acaba de chocar tu carro. \\u00BFSabes qu\\u00E9 hacer? Desliza para descubrirlo.',\n      go: 'Empezar', kicker: '\\u00BFS\\u00ED o no?',\n      hint: 'Desliza a la derecha si debes hacerlo. A la izquierda si no.',\n      doLbl: 'S\\u00ED', dontLbl: 'No', stampDo: 'S\\u00CD', stampDont: 'NO',\n      prog: 'Decisi\\u00F3n {n} de {t}', right: '\\u00A1Correcto!', wrong: 'No exactamente.',\n      ruleDo: 'Hazlo.', ruleDont: 'No lo hagas.', tap: 'Toca para continuar',\n      score: '{n} de {t} decisiones correctas',\n      v3: 'Lo manejar\\u00EDas como un profesional.', v2: 'Sabes m\\u00E1s que la mayor\\u00EDa.', v1: 'Qu\\u00E9 bueno que jugaste esto primero.',\n      listTitle: 'Tu lista para la guantera', colDo: 'S\\u00ED', colDont: 'No',\n      call: 'Llama para una consulta gratis', checklist: 'Descarga la lista imprimible', again: 'Jugar otra vez',\n      aria: 'Despu\\u00E9s del choque. Desliza la tarjeta a la derecha para s\\u00ED, a la izquierda para no, o usa las flechas.'\n    }\n  };\n\n  var ICON_CHECK = '<svg viewBox=\"0 0 24 24\"><path d=\"M4.5 12.5l5 5L19.5 7\"\/><\/svg>';\n  var ICON_X = '<svg viewBox=\"0 0 24 24\"><path d=\"M6 6l12 12M18 6L6 18\"\/><\/svg>';\n\n  function q(n) { return root.querySelector('[data-ac=\"' + n + '\"]'); }\n  var stage = q('stage'), card = q('card'), fb = q('fb'), deck = q('deck');\n  var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n  var lang = CONFIG.defaultLang === 'es' ? 'es' : 'en';\n  function t(k, n, tot) {\n    return String(STR[lang][k]).replace('{n}', n).replace('{t}', tot);\n  }\n\n  \/* ---------- sound: kept quiet on purpose ---------- *\/\n  var ac = null;\n  function tone(f, d, v) {\n    if (!ac) return;\n    var o = ac.createOscillator(), g = ac.createGain();\n    o.type = 'sine'; o.frequency.value = f;\n    g.gain.setValueAtTime(v, ac.currentTime);\n    g.gain.exponentialRampToValueAtTime(.0001, ac.currentTime + d);\n    o.connect(g); g.connect(ac.destination);\n    o.start(); o.stop(ac.currentTime + d);\n  }\n\n  \/* ---------- state ---------- *\/\n  var state = 'start', order = [], i = 0, right = 0, results = [], busy = false, autoTimer = null, lastOk = false;\n\n  function shuffleRest() {\n    var rest = CARDS.slice(1);\n    for (var k = rest.length - 1; k > 0; k--) {\n      var j = Math.floor(Math.random() * (k + 1)), tmp = rest[k]; rest[k] = rest[j]; rest[j] = tmp;\n    }\n    return [CARDS[0]].concat(rest);\n  }\n\n  \/* ---------- language ---------- *\/\n  function applyLang() {\n    root.querySelectorAll('[data-ac-lang]').forEach(function (b) {\n      b.setAttribute('aria-pressed', String(b.getAttribute('data-ac-lang') === lang));\n    });\n    stage.setAttribute('aria-label', t('aria'));\n    stage.setAttribute('lang', lang);\n    q('tab').textContent = t('tab');\n    q('title1').textContent = t('title1');\n    q('title2').textContent = t('title2');\n    q('sub').textContent = t('sub');\n    q('go').textContent = t('go');\n    q('firm').textContent = CONFIG.firm + ' \\u00B7 ' + CONFIG.city;\n    q('cardKicker').textContent = t('kicker');\n    q('hint').textContent = t('hint');\n    q('lblDo').textContent = t('doLbl');\n    q('lblDont').textContent = t('dontLbl');\n    q('stampDo').textContent = t('stampDo');\n    q('stampDont').textContent = t('stampDont');\n    q('call').textContent = t('call');\n    q('checklist').textContent = t('checklist');\n    q('again').textContent = t('again');\n    q('legal').textContent = CONFIG.legal[lang];\n    if (state === 'card' || state === 'fb') {\n      q('prog').textContent = t('prog', i + 1, order.length);\n      q('cardText').textContent = order[i][lang].text;\n    }\n    if (state === 'fb') paintFeedback();\n    if (state === 'end') paintEnd();\n  }\n  root.querySelectorAll('[data-ac-lang]').forEach(function (b) {\n    b.addEventListener('click', function (e) {\n      e.stopPropagation();\n      lang = b.getAttribute('data-ac-lang');\n      applyLang();\n    });\n  });\n\n  \/* ---------- config into the page ---------- *\/\n  q('call').href = 'tel:' + CONFIG.phone;\n  q('call').setAttribute('aria-describedby', '');\n  q('checklist').href = CONFIG.checklistLink || '#';\n  if (CONFIG.logo) {\n    var logo = q('logo');\n    logo.src = CONFIG.logo; logo.alt = CONFIG.firm; logo.hidden = false;\n    logo.addEventListener('error', function () { logo.hidden = true; });\n  }\n  stage.style.setProperty('--ac-auto', (CONFIG.autoAdvanceMs || 6000) + 'ms');\n\n  \/* ---------- segments ---------- *\/\n  function paintSegs() {\n    var segs = q('segs');\n    segs.textContent = '';\n    for (var k = 0; k < order.length; k++) {\n      var s = document.createElement('span');\n      s.className = 'ac-seg' + (k < results.length ? (results[k] ? ' is-right' : ' is-wrong') : k === i ? ' is-now' : '');\n      segs.appendChild(s);\n    }\n  }\n\n  \/* ---------- card ---------- *\/\n  function place(dx, dy) {\n    card.style.transform = 'translate(' + dx + 'px,' + (dy * .15) + 'px) rotate(' + (dx * .05) + 'deg)';\n    var a = Math.min(1, Math.abs(dx) \/ (card.offsetWidth * .28 || 1));\n    q('stampDo').style.opacity = dx > 0 ? a : 0;\n    q('stampDont').style.opacity = dx < 0 ? a : 0;\n  }\n\n  function showCard() {\n    state = 'card'; busy = false;\n    fb.hidden = true; card.hidden = false;\n    q('controls').hidden = false;\n    q('hint').hidden = i > 1;\n    q('prog').textContent = t('prog', i + 1, order.length);\n    q('cardText').textContent = order[i][lang].text;\n    paintSegs();\n    card.style.transition = 'none';\n    place(0, 0);\n    if (!reduce) {\n      card.style.transform = 'translateY(.9em) scale(.95)';\n      card.style.opacity = '0';\n      void card.offsetWidth;\n      card.style.transition = 'transform .3s cubic-bezier(.16,1,.3,1), opacity .2s';\n      card.style.transform = 'none';\n    }\n    card.style.opacity = '1';\n  }\n\n  function decide(dir) {\n    if (state !== 'card' || busy) return;\n    busy = true;\n    var w = stage.offsetWidth, sign = dir === 'do' ? 1 : -1;\n    q('stampDo').style.opacity = dir === 'do' ? 1 : 0;\n    q('stampDont').style.opacity = dir === 'dont' ? 1 : 0;\n    card.style.transition = reduce ? 'none' : 'transform .3s cubic-bezier(.4,0,.8,.6)';\n    card.style.transform = 'translate(' + (sign * w * 1.1) + 'px, -.5em) rotate(' + (sign * 22) + 'deg)';\n    lastOk = dir === order[i].answer;\n    if (lastOk) right++;\n    results.push(lastOk);\n    if (lastOk) { tone(660, .12, .05); setTimeout(function () { tone(880, .18, .05); }, 90); }\n    else tone(220, .22, .06);\n    setTimeout(showFeedback, reduce ? 0 : 300);\n  }\n\n  function paintFeedback() {\n    var c = order[i], isDo = c.answer === 'do';\n    fb.classList.toggle('is-wrong', !lastOk);\n    q('fbHead').textContent = lastOk ? t('right') : t('wrong');\n    var icon = q('fbIcon');\n    icon.innerHTML = isDo ? ICON_CHECK : ICON_X;\n    icon.style.background = isDo ? 'var(--ac-do)' : 'var(--ac-dont)';\n    q('fbRule').textContent = isDo ? t('ruleDo') : t('ruleDont');\n    q('fbWhy').textContent = c[lang].why;\n    q('fbTap').textContent = t('tap');\n  }\n\n  function showFeedback() {\n    state = 'fb';\n    card.hidden = true;\n    q('controls').hidden = true;\n    q('hint').hidden = true;\n    paintFeedback();\n    paintSegs();\n    fb.hidden = false;\n    fb.style.animation = 'none'; void fb.offsetWidth; fb.style.animation = '';\n    var bar = q('fbTimer');\n    bar.classList.remove('is-running'); void bar.offsetWidth;\n    clearTimeout(autoTimer);\n    if (CONFIG.autoAdvanceMs > 0 && !reduce) {\n      bar.classList.add('is-running');\n      autoTimer = setTimeout(next, CONFIG.autoAdvanceMs);\n    }\n    try { stage.focus({ preventScroll: true }); } catch (e) {}\n  }\n\n  function next() {\n    if (state !== 'fb') return;\n    clearTimeout(autoTimer);\n    i++;\n    if (i >= order.length) finish(); else showCard();\n  }\n\n  \/* ---------- flow ---------- *\/\n  function begin() {\n    if (!ac) { try { ac = new (window.AudioContext || window.webkitAudioContext)(); } catch (e) { ac = null; } }\n    if (ac && ac.state === 'suspended') ac.resume();\n    order = shuffleRest(); i = 0; right = 0; results = [];\n    q('start').hidden = true; q('end').hidden = true;\n    q('hud').hidden = false; deck.hidden = false;\n    showCard();\n    try { stage.focus({ preventScroll: true }); } catch (e) {}\n  }\n\n  function paintEnd() {\n    var share = right \/ order.length;\n    q('verdict').textContent = share === 1 ? t('v3') : share >= .75 ? t('v2') : t('v1');\n    q('score').textContent = t('score', right, order.length);\n    q('listTitle').textContent = t('listTitle');\n    q('colDo').textContent = t('colDo');\n    q('colDont').textContent = t('colDont');\n    var ld = q('listDo'), ln = q('listDont');\n    ld.textContent = ''; ln.textContent = '';\n    CARDS.forEach(function (c) {\n      var li = document.createElement('li');\n      li.textContent = c[lang].short;\n      (c.answer === 'do' ? ld : ln).appendChild(li);\n    });\n  }\n\n  function finish() {\n    state = 'end';\n    clearTimeout(autoTimer);\n    q('hud').hidden = true; deck.hidden = true; q('controls').hidden = true; q('hint').hidden = true;\n    paintEnd();\n    q('end').hidden = false;\n    tone(523, .14, .05); setTimeout(function () { tone(784, .26, .05); }, 120);\n  }\n\n  \/* ---------- input ---------- *\/\n  var drag = null;\n  card.addEventListener('pointerdown', function (e) {\n    if (state !== 'card' || busy) return;\n    e.preventDefault();\n    try { card.setPointerCapture(e.pointerId); } catch (err) {}\n    drag = { x: e.clientX, y: e.clientY, dx: 0, dy: 0 };\n    card.style.transition = 'none';\n  });\n  card.addEventListener('pointermove', function (e) {\n    if (!drag) return;\n    drag.dx = e.clientX - drag.x; drag.dy = e.clientY - drag.y;\n    place(drag.dx, drag.dy);\n  });\n  function endDrag() {\n    if (!drag) return;\n    var dx = drag.dx, th = card.offsetWidth * .28;\n    drag = null;\n    if (dx > th) decide('do');\n    else if (dx < -th) decide('dont');\n    else { card.style.transition = 'transform .25s cubic-bezier(.2,.8,.2,1)'; place(0, 0); }\n  }\n  card.addEventListener('pointerup', endDrag);\n  card.addEventListener('pointercancel', endDrag);\n\n  q('btnDo').addEventListener('click', function () { decide('do'); });\n  q('btnDont').addEventListener('click', function () { decide('dont'); });\n  stage.addEventListener('click', function (e) {\n    if (state === 'fb' && !(e.target.closest && e.target.closest('.ac-lang'))) next();\n  });\n  stage.addEventListener('keydown', function (e) {\n    if (state === 'card') {\n      if (e.key === 'ArrowRight') { e.preventDefault(); decide('do'); }\n      else if (e.key === 'ArrowLeft') { e.preventDefault(); decide('dont'); }\n    } else if (state === 'fb') {\n      if (['Enter', ' ', 'ArrowRight', 'ArrowLeft'].indexOf(e.key) > -1) { e.preventDefault(); next(); }\n    }\n  });\n  q('go').addEventListener('click', begin);\n  q('again').addEventListener('click', begin);\n\n  applyLang();\n})();\n<\/script><\/div><\/div><\/div><\/div><div class=\"x-section e16-e50 mg-0\" id=\"how\"><div class=\"x-row x-container max width e16-e51 mg-1 mg-2 mg-3 mg-b mg-j\"><div class=\"x-row-inner\"><div class=\"x-col e16-e52 mg-s mg-t mg-u mg-v mg-w mg-x mg-18\"><div class=\"x-text x-content e16-e53 mg-1d mg-1e mg-1f mg-1g mg-1h mg-1i\"><p>HOW IT WORKS<\/p><\/div><div class=\"x-text x-text-headline e16-e54 mg-1s mg-1u mg-1y mg-1z mg-20 mg-21\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h2 class=\"x-text-content-text-primary\">From idea to live, handled.<\/h2>\n<\/div><\/div><\/div><\/div><div class=\"x-col e16-e55 mg-s mg-t mg-v mg-w mg-x mg-y mg-10\"><hr class=\"x-line e16-e56 mg-2o\"\/><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e57 mg-1 mg-2 mg-3 mg-b mg-k\"><div class=\"x-row-inner\"><div class=\"x-col e16-e58 mg-s mg-t mg-u mg-v mg-w mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e59 mg-1s mg-1z mg-22 mg-23 mg-24 mg-28\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">01<\/h1>\n<\/div><\/div><\/div><div class=\"x-text x-text-headline e16-e60 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">We brainstorm the experience<\/h1>\n<span class=\"x-text-content-text-subheadline\">Your offer, your audience, your assets, the game. We come back with a mechanic worth 30 seconds of someone's day.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e61 mg-s mg-t mg-u mg-v mg-w mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e62 mg-1s mg-1z mg-22 mg-23 mg-24 mg-28\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">02<\/h1>\n<\/div><\/div><\/div><div class=\"x-text x-text-headline e16-e63 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">We build the game<\/h1>\n<span class=\"x-text-content-text-subheadline\">Art, writing, sound, the reward screen, the landing page behind it. You approve, we ship.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e64 mg-s mg-t mg-u mg-v mg-w mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e65 mg-1s mg-1z mg-22 mg-23 mg-24 mg-28\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">03<\/h1>\n<\/div><\/div><\/div><div class=\"x-text x-text-headline e16-e66 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">We help you<br \/>go live<\/h1>\n<span class=\"x-text-content-text-subheadline\">Campaign setup, creative specs, targeting your city. Or we hand you the files and you run it yourself.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e67 mg-s mg-t mg-u mg-v mg-w mg-12 mg-13 mg-16\"><div class=\"x-text x-text-headline e16-e68 mg-1s mg-1z mg-22 mg-23 mg-24 mg-28\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">04<\/h1>\n<\/div><\/div><\/div><div class=\"x-text x-text-headline e16-e69 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">You see what<br \/>it did<\/h1>\n<span class=\"x-text-content-text-subheadline\">Plays, completions, codes claimed, coupons redeemed, new referrals and sales. The number that matters, not impressions.<\/span><\/div><\/div><\/div><\/div><\/div><\/div><\/div><div class=\"x-section e16-e70 mg-0\" id=\"where\"><div class=\"x-row x-container max width e16-e71 mg-1 mg-2 mg-3 mg-b mg-l\"><div class=\"x-row-inner\"><div class=\"x-col e16-e72 mg-s mg-t mg-u mg-v mg-w mg-x mg-18\"><div class=\"x-text x-content e16-e73 mg-1d mg-1e mg-1f mg-1g mg-1h mg-1i\"><span>Where it runs<\/span><\/div><div class=\"x-text x-text-headline e16-e74 mg-1s mg-1u mg-1y mg-1z mg-20 mg-21\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h2 class=\"x-text-content-text-primary\">Built once. Live everywhere that matters.<\/h2>\n<\/div><\/div><\/div><\/div><div class=\"x-col e16-e75 mg-s mg-t mg-v mg-w mg-x mg-y mg-10\"><div class=\"x-text x-content e16-e76 mg-1e mg-1g mg-1i mg-1j mg-1k mg-1l mg-1p\"><p>We publish your game to the networks your customers already play games: targeted to your city or region.<\/p>\n<p>One build, every placement.<\/p><\/div><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e77 mg-1 mg-2 mg-3 mg-b mg-m\"><div class=\"x-row-inner\"><div class=\"x-col e16-e78 mg-s mg-t mg-u mg-v mg-w mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e79 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">Meta Ads<\/h1>\n<span class=\"x-text-content-text-subheadline\">Radius targeting down to your neighbourhood. The cheapest way to test a new game.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e80 mg-s mg-t mg-u mg-v mg-w mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e81 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">TikTok<\/h1>\n<span class=\"x-text-content-text-subheadline\">Cheap attention and younger reach. Strong for food, fitness, events and campuses.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e82 mg-s mg-t mg-u mg-v mg-w mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e83 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">Google Ads<\/h1>\n<span class=\"x-text-content-text-subheadline\">Google's app and display inventory, plus search intent pointed straight at your game.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e84 mg-s mg-t mg-u mg-v mg-w mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e85 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">AppLovin<\/h1>\n<span class=\"x-text-content-text-subheadline\">In-game placements inside the apps people play such as Candy Crush, Wordscapes, Solitaire and 100+ other titles.<\/span><\/div><\/div><\/div><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e86 mg-1 mg-3 mg-5 mg-9 mg-b mg-n\"><div class=\"x-row-inner\"><div class=\"x-col e16-e87 mg-s mg-u mg-w mg-11 mg-12 mg-15 mg-17 mg-19 mg-1a\"><div class=\"x-text x-text-headline e16-e88 mg-1s mg-1z mg-22 mg-24 mg-29\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">3B+<\/h1>\n<\/div><\/div><\/div><div class=\"x-text x-text-headline e16-e89 mg-1s mg-22 mg-24 mg-2a mg-2b\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">people play mobile games every day. AppLovin alone reports over a billion daily active users across 140,000+ apps and it opened to advertisers who aren't selling an app. <br \/><br \/>Your city is a slice of that.<\/h1>\n<\/div><\/div><\/div><\/div><div class=\"x-col e16-e90 mg-w mg-12 mg-16 mg-1a mg-1b\"><div class=\"x-text x-text-headline e16-e91 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">And your own channels, 100% free<\/h1>\n<span class=\"x-text-content-text-subheadline\">The same game embeds on your homepage, drops into an email, or sits behind a QR code on the window, the receipt, the table tent. No media spend required.<\/span><\/div><\/div><\/div><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e92 mg-1 mg-3 mg-4 mg-5 mg-b mg-o\"><div class=\"x-row-inner\"><div class=\"x-col e16-e93 mg-s mg-t mg-u mg-v mg-w mg-x mg-y\"><div class=\"x-text x-content e16-e94 mg-1d mg-1e mg-1f mg-1g mg-1h mg-1i\"><p><span class=\"chip\">WHY PLAYABLE ADS<\/span><\/p><\/div><div class=\"x-text x-text-headline e16-e95 mg-1s mg-1u mg-1y mg-1z mg-20 mg-21\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h2 class=\"x-text-content-text-primary\">Attention you don't have to interrupt for.&nbsp;<\/h2>\n<\/div><\/div><\/div><\/div><div class=\"x-col e16-e96 mg-s mg-t mg-v mg-w mg-x mg-y mg-10\"><hr class=\"x-line e16-e97 mg-2o\"\/><\/div><\/div><\/div><div class=\"x-row x-container max width e16-e98 mg-1 mg-3 mg-5 mg-6 mg-7 mg-b mg-p\"><div class=\"x-row-inner\"><div class=\"x-col e16-e99 mg-s mg-t mg-u mg-w mg-11 mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e100 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">They opt in<\/h1>\n<span class=\"x-text-content-text-subheadline\">Nobody taps \"play\" by accident. The people who finish your game chose to spend time with your brand, THAT is a different kind of lead.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e101 mg-s mg-t mg-u mg-w mg-11 mg-12 mg-13 mg-14\"><div class=\"x-text x-text-headline e16-e102 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">It closes the loop<\/h1>\n<span class=\"x-text-content-text-subheadline\">Unique codes mean you can trace a play all the way to a register. Try doing that with a billboard.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e103 mg-s mg-t mg-u mg-w mg-11 mg-12 mg-13 mg-16\"><div class=\"x-text x-text-headline e16-e104 mg-1s mg-1v mg-1w mg-1x mg-1z mg-22 mg-23 mg-24 mg-25\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h1 class=\"x-text-content-text-primary\">You'd be first in your market<\/h1>\n<span class=\"x-text-content-text-subheadline\">Playable ads are standard practice for game studios and almost unheard of for local business. That gap is the whole opportunity.<\/span><\/div><\/div><\/div><\/div><\/div><\/div><\/div><div class=\"x-section e16-e105 mg-0\" id=\"faq\"><div class=\"x-row x-container max width e16-e106 mg-1 mg-2 mg-3 mg-b mg-q\"><div class=\"x-row-inner\"><div class=\"x-col e16-e107 mg-s mg-t mg-u mg-v mg-w mg-x mg-y\"><div class=\"x-text x-text-headline e16-e108 mg-1s mg-1u mg-1v mg-1x mg-1y mg-1z mg-20 mg-2c\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h2 class=\"x-text-content-text-primary\">FAQ<\/h2>\n<span class=\"x-text-content-text-subheadline\">Can't find your answer here? Ask it on the call, we answer everything before you spend a dollar.<\/span><\/div><\/div><\/div><a class=\"x-anchor x-anchor-button e16-e109 mg-2g mg-2h mg-2i mg-2j mg-2l\" tabindex=\"0\" href=\"mailto:joab@mapp.io?subject=Question about playable ads\"><div class=\"x-anchor-content\"><div class=\"x-anchor-text\"><span class=\"x-anchor-text-primary\">Ask A Question<\/span><\/div><\/div><\/a><\/div><div class=\"x-col e16-e110 mg-w mg-x mg-y\"><div class=\"x-acc e16-e111 mg-2p\" id=\"x-acc-e16-e111\"><div class=\"e16-e112 x-acc-item\"><button id=\"tab-e16-e112\" class=\"x-acc-header x-active\" role=\"button\" aria-expanded=\"true\" aria-controls=\"panel-e16-e112\" data-x-toggle=\"collapse\" data-x-toggleable=\"e16-e112\" type=\"button\"><span class=\"x-acc-header-content\"><span class=\"x-acc-header-indicator\">&#x25b8;<\/span><span class=\"x-acc-header-text\">Do you work with small businesses?<\/span><\/span><\/button><div id=\"panel-e16-e112\" role=\"tabpanel\" aria-hidden=\"false\" aria-labelledby=\"tab-e16-e112\" data-x-toggleable=\"e16-e112\" data-x-toggle-collapse=\"1\"><div class=\"x-acc-content\"><div class=\"x-text x-content e16-e113 mg-1d mg-1e mg-1g mg-1h mg-1l mg-1o mg-1q\"><span>Yes! That is exactly who this is built for. If you have an offer worth claiming and a city you're targeting, the format works at your size.<\/span><\/div><\/div><\/div><\/div><div class=\"e16-e114 x-acc-item\"><button id=\"tab-e16-e114\" class=\"x-acc-header\" role=\"button\" aria-expanded=\"false\" aria-controls=\"panel-e16-e114\" data-x-toggle=\"collapse\" data-x-toggleable=\"e16-e114\" type=\"button\"><span class=\"x-acc-header-content\"><span class=\"x-acc-header-indicator\">&#x25b8;<\/span><span class=\"x-acc-header-text\">Where do these ads actually run?<\/span><\/span><\/button><div id=\"panel-e16-e114\" role=\"tabpanel\" aria-hidden=\"true\" aria-labelledby=\"tab-e16-e114\" data-x-toggleable=\"e16-e114\" data-x-toggle-collapse=\"1\" class=\"x-collapsed\"><div class=\"x-acc-content\"><div class=\"x-text x-content e16-e115 mg-1d mg-1e mg-1g mg-1h mg-1i mg-1l mg-1q\"><span>Inside mobile games and apps, on social, on your own website, and in-store through a QR code. We recommend the mix on the call.<\/span><\/div><\/div><\/div><\/div><div class=\"e16-e116 x-acc-item\"><button id=\"tab-e16-e116\" class=\"x-acc-header\" role=\"button\" aria-expanded=\"false\" aria-controls=\"panel-e16-e116\" data-x-toggle=\"collapse\" data-x-toggleable=\"e16-e116\" type=\"button\"><span class=\"x-acc-header-content\"><span class=\"x-acc-header-indicator\">&#x25b8;<\/span><span class=\"x-acc-header-text\">Do I need my own app?<\/span><\/span><\/button><div id=\"panel-e16-e116\" role=\"tabpanel\" aria-hidden=\"true\" aria-labelledby=\"tab-e16-e116\" data-x-toggleable=\"e16-e116\" data-x-toggle-collapse=\"1\" class=\"x-collapsed\"><div class=\"x-acc-content\"><div class=\"x-text x-content e16-e117 mg-1d mg-1e mg-1h mg-1l mg-1m mg-1o mg-1q\"><span>No. The game lives on a page we host. People play it in their browser and claim the reward right there, with nothing to download.<\/span><\/div><\/div><\/div><\/div><div class=\"e16-e118 x-acc-item\"><button id=\"tab-e16-e118\" class=\"x-acc-header\" role=\"button\" aria-expanded=\"false\" aria-controls=\"panel-e16-e118\" data-x-toggle=\"collapse\" data-x-toggleable=\"e16-e118\" type=\"button\"><span class=\"x-acc-header-content\"><span class=\"x-acc-header-indicator\">&#x25b8;<\/span><span class=\"x-acc-header-text\">Does mApp manage the ad spend too?<\/span><\/span><\/button><div id=\"panel-e16-e118\" role=\"tabpanel\" aria-hidden=\"true\" aria-labelledby=\"tab-e16-e118\" data-x-toggleable=\"e16-e118\" data-x-toggle-collapse=\"1\" class=\"x-collapsed\"><div class=\"x-acc-content\"><div class=\"x-text x-content e16-e119 mg-1d mg-1e mg-1h mg-1l mg-1m mg-1o mg-1q\"><span>We can. Some clients hand us the media entirely; others run it in-house and just want the game built and delivered.<\/span><\/div><\/div><\/div><\/div><div class=\"e16-e120 x-acc-item\"><button id=\"tab-e16-e120\" class=\"x-acc-header\" role=\"button\" aria-expanded=\"false\" aria-controls=\"panel-e16-e120\" data-x-toggle=\"collapse\" data-x-toggleable=\"e16-e120\" type=\"button\"><span class=\"x-acc-header-content\"><span class=\"x-acc-header-indicator\">&#x25b8;<\/span><span class=\"x-acc-header-text\">What is the cost?<\/span><\/span><\/button><div id=\"panel-e16-e120\" role=\"tabpanel\" aria-hidden=\"true\" aria-labelledby=\"tab-e16-e120\" data-x-toggleable=\"e16-e120\" data-x-toggle-collapse=\"1\" class=\"x-collapsed\"><div class=\"x-acc-content\"><div class=\"x-text x-content e16-e121 mg-1d mg-1e mg-1h mg-1l mg-1m mg-1o mg-1q\"><span>It starts at $3000 for the game but that all depends on the mechanic and the scope. Book a call and you will leave with a real number.<\/span><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><\/div><div class=\"x-section e16-e122 mg-0\" id=\"book\"><div class=\"x-row x-container max width e16-e123 mg-1 mg-2 mg-a mg-b mg-r\"><div class=\"x-row-inner\"><div class=\"x-col e16-e124 mg-s mg-t mg-v mg-w mg-x mg-y mg-10\"><div class=\"x-text x-text-headline e16-e125 mg-1s mg-1x mg-1z mg-20 mg-22 mg-25 mg-27 mg-2b mg-2d\"><div class=\"x-text-content\"><div class=\"x-text-content-text\"><h2 class=\"x-text-content-text-primary\">Let's find the game inside your business.<\/h2>\n<span class=\"x-text-content-text-subheadline\">Thirty minutes. We'll bring two or three ideas for a playable built around your offer ABSOLUTELY free, whether or not you hire us.<\/span><\/div><\/div><\/div><\/div><div class=\"x-col e16-e126 mg-s mg-t mg-u mg-w mg-x mg-1c\"><a class=\"x-anchor x-anchor-button e16-e127 mg-2g mg-2h mg-2l mg-2m\" tabindex=\"0\" href=\"https:\/\/calendly.com\/joab-mapp\/30min\"><div class=\"x-anchor-content\"><div class=\"x-anchor-text\"><span class=\"x-anchor-text-primary\">Book A Meeting<\/span><\/div><\/div><\/a><div class=\"x-text x-content e16-e128 mg-1e mg-1g mg-1h mg-1i mg-1k mg-1l mg-1r\"><p>Bring your own ideas and we'll make them come alive!<\/p><\/div><\/div><\/div><\/div><\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>Playable ad studioPeople skip ads. Nobody skips a game. mApp builds playable ads for your business \u2014 short, custom mini-games that promote your product using high engagement.Book A 30-Minute Call(opens in a new tab)Email Us Ideal for restaurants, dealerships, retail, gyms, clinics, law offices and universities. Loading\u2026 Playable ad studioAn ad they play, not an ad they wait out. A &#8230; <\/p>\n<div><a href=\"https:\/\/mapp.io\/\" class=\"more-link\">Read More<\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-blank-4.php","meta":{"footnotes":""},"class_list":["post-16","page","type-page","status-publish","hentry","no-post-thumbnail"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>mApp.io Home \u2022 We make playable ads - mApp Marketing \u2022 We make playable ads!<\/title>\n<meta name=\"description\" content=\"mApp builds playable ads for your business: short, custom mini-games that promote your product using high engagement.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/mapp.io\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"mApp.io Home \u2022 We make playable ads - mApp Marketing \u2022 We make playable ads!\" \/>\n<meta property=\"og:description\" content=\"mApp builds playable ads for your business: short, custom mini-games that promote your product using high engagement.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/mapp.io\/\" \/>\n<meta property=\"og:site_name\" content=\"mApp Marketing \u2022 We make playable ads!\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-25T22:22:59+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/meta.png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/mapp.io\\\/\",\"url\":\"https:\\\/\\\/mapp.io\\\/\",\"name\":\"mApp.io Home \u2022 We make playable ads - mApp Marketing \u2022 We make playable ads!\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/mapp.io\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/mapp.io\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/mapp.io\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/mapp.io\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/meta.png\",\"datePublished\":\"2026-09-25T21:53:17+00:00\",\"dateModified\":\"2026-09-25T22:22:59+00:00\",\"description\":\"mApp builds playable ads for your business: short, custom mini-games that promote your product using high engagement.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/mapp.io\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/mapp.io\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/mapp.io\\\/#primaryimage\",\"url\":\"https:\\\/\\\/mapp.io\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/meta.png\",\"contentUrl\":\"https:\\\/\\\/mapp.io\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/meta.png\",\"width\":1422,\"height\":600},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/mapp.io\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/mapp.io\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"mApp.io Home \u2022 We make playable ads\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/mapp.io\\\/#website\",\"url\":\"https:\\\/\\\/mapp.io\\\/\",\"name\":\"mApp Marketing \u2022 We make playable ads!\",\"description\":\"Your customers are playing mobile games. We&#039;ll introduce you.\",\"publisher\":{\"@id\":\"https:\\\/\\\/mapp.io\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/mapp.io\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/mapp.io\\\/#organization\",\"name\":\"mApp Marketing \u2022 We make playable ads!\",\"url\":\"https:\\\/\\\/mapp.io\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/mapp.io\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/mapp.io\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/mappio-dark.png\",\"contentUrl\":\"https:\\\/\\\/mapp.io\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/mappio-dark.png\",\"width\":1000,\"height\":242,\"caption\":\"mApp Marketing \u2022 We make playable ads!\"},\"image\":{\"@id\":\"https:\\\/\\\/mapp.io\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"mApp.io Home \u2022 We make playable ads - mApp Marketing \u2022 We make playable ads!","description":"mApp builds playable ads for your business: short, custom mini-games that promote your product using high engagement.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/mapp.io\/","og_locale":"en_US","og_type":"article","og_title":"mApp.io Home \u2022 We make playable ads - mApp Marketing \u2022 We make playable ads!","og_description":"mApp builds playable ads for your business: short, custom mini-games that promote your product using high engagement.","og_url":"https:\/\/mapp.io\/","og_site_name":"mApp Marketing \u2022 We make playable ads!","article_modified_time":"2026-09-25T22:22:59+00:00","og_image":[{"url":"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/meta.png","type":"","width":"","height":""}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/mapp.io\/","url":"https:\/\/mapp.io\/","name":"mApp.io Home \u2022 We make playable ads - mApp Marketing \u2022 We make playable ads!","isPartOf":{"@id":"https:\/\/mapp.io\/#website"},"primaryImageOfPage":{"@id":"https:\/\/mapp.io\/#primaryimage"},"image":{"@id":"https:\/\/mapp.io\/#primaryimage"},"thumbnailUrl":"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/meta.png","datePublished":"2026-09-25T21:53:17+00:00","dateModified":"2026-09-25T22:22:59+00:00","description":"mApp builds playable ads for your business: short, custom mini-games that promote your product using high engagement.","breadcrumb":{"@id":"https:\/\/mapp.io\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/mapp.io\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/mapp.io\/#primaryimage","url":"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/meta.png","contentUrl":"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/meta.png","width":1422,"height":600},{"@type":"BreadcrumbList","@id":"https:\/\/mapp.io\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/mapp.io\/"},{"@type":"ListItem","position":2,"name":"mApp.io Home \u2022 We make playable ads"}]},{"@type":"WebSite","@id":"https:\/\/mapp.io\/#website","url":"https:\/\/mapp.io\/","name":"mApp Marketing \u2022 We make playable ads!","description":"Your customers are playing mobile games. We&#039;ll introduce you.","publisher":{"@id":"https:\/\/mapp.io\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/mapp.io\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/mapp.io\/#organization","name":"mApp Marketing \u2022 We make playable ads!","url":"https:\/\/mapp.io\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/mapp.io\/#\/schema\/logo\/image\/","url":"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/mappio-dark.png","contentUrl":"https:\/\/mapp.io\/wp-content\/uploads\/2026\/09\/mappio-dark.png","width":1000,"height":242,"caption":"mApp Marketing \u2022 We make playable ads!"},"image":{"@id":"https:\/\/mapp.io\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/mapp.io\/index.php?rest_route=\/wp\/v2\/pages\/16","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mapp.io\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/mapp.io\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/mapp.io\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mapp.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=16"}],"version-history":[{"count":5,"href":"https:\/\/mapp.io\/index.php?rest_route=\/wp\/v2\/pages\/16\/revisions"}],"predecessor-version":[{"id":52,"href":"https:\/\/mapp.io\/index.php?rest_route=\/wp\/v2\/pages\/16\/revisions\/52"}],"wp:attachment":[{"href":"https:\/\/mapp.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=16"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}