1<!DOCTYPE html> 2<html lang="en-GB"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1"> 6 <link rel="icon" href="https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/images/favicon.png" type="image/png"> 7
7<script type="text/javascript" data-cookieconsent="ignore"> 8 window.dataLayer = window.dataLayer || []; 9 10 function gtag() { 11 dataLayer.push(arguments); 12 } 13 14 gtag("consent", "default", { 15 ad_personalization: "denied", 16 ad_storage: "denied", 17 ad_user_data: "denied", 18 analytics_storage: "denied", 19 functionality_storage: "denied", 20 personalization_storage: "denied", 21 security_storage: "granted", 22 wait_for_update: 500, 23 }); 24 gtag("set", "ads_data_redaction", true); 25 </script>
vendor: 1 bytes, line 25
25
26<script type="text/javascript" data-cookieconsent="ignore"> 27 (function (w, d, s, l, i) { 28 w[l] = w[l] || []; 29 w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'}); 30 var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l !== 'dataLayer' ? '&l=' + l : ''; 31 j.async = true; 32 j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; 33 f.parentNode.insertBefore(j, f); 34 })( 35 window, 36 document, 37 'script', 38 'dataLayer', 39 'GTM-T3BH7W7' 40 ); 41</script>
vendor: 1 bytes, line 41
41
42<script type="text/javascript" 43 id="Cookiebot" 44 src="https://consent.cookiebot.com/uc.js" 45 data-implementation="wp" 46 data-cbid="b06ede66-e802-4a55-93d8-86b7bbd26af9" 47 data-blockingmode="auto" 48 ></script>
48 49<meta name='robots' content='index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1' /> 50 51 <!-- This site is optimized with the Yoast SEO plugin v28.6 - https://yoast.com/product/yoast-seo-wordpress/ --> 52 <title>portfolio - Flyingshapes</title> 53 <link rel="canonical" href="https://www.flyingshapes.com/portfolio/" /> 54 <meta property="og:locale" content="en_GB" /> 55 <meta property="og:type" content="article" /> 56 <meta property="og:title" content="portfolio - Flyingshapes" /> 57 <meta property="og:url" content="https://www.flyingshapes.com/portfolio/" /> 58 <meta property="og:site_name" content="Flyingshapes" /> 59 <meta property="article:modified_time" content="2026-09-09T07:21:33+00:00" /> 60 <meta name="twitter:card" content="summary_large_image" /> 61
61<script type="application/ld+json" class="yoast-schema-graph">{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.flyingshapes.com\/portfolio\/","url":"https:\/\/www.flyingshapes.com\/portfolio\/","name":"portfolio - Flyingshapes","isPartOf":{"@id":"https:\/\/www.flyingshapes.com\/#website"},"datePublished":"2026-09-04T14:56:03+00:00","dateModified":"2026-09-09T07:21:33+00:00","breadcrumb":{"@id":"https:\/\/www.flyingshapes.com\/portfolio\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.flyingshapes.com\/portfolio\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.flyingshapes.com\/portfolio\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.flyingshapes.com\/"},{"@type":"ListItem","position":2,"name":"portfolio"}]},{"@type":"WebSite","@id":"https:\/\/www.flyingshapes.com\/#website","url":"https:\/\/www.flyingshapes.com\/","name":"Flyingshapes","description":"Instant Interactive 3D Ideation","publisher":{"@id":"https:\/\/www.flyingshapes.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.flyingshapes.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":"Organization","@id":"https:\/\/www.flyingshapes.com\/#organization","name":"Flyingshapes GmbH","url":"https:\/\/www.flyingshapes.com\/","logo":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/www.flyingshapes.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.flyingshapes.com\/wp-content\/uploads\/2026\/09\/Icon-2026-black-on-white-1600.png","contentUrl":"https:\/\/www.flyingshapes.com\/wp-content\/uploads\/2026\/09\/Icon-2026-black-on-white-1600.png","width":1600,"height":1600,"caption":"Flyingshapes GmbH"},"image":{"@id":"https:\/\/www.flyingshapes.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/de.linkedin.com\/company\/flyingshapes"]}]}</script>
61 62 <!-- / Yoast SEO plugin. --> 63 64 65<link rel='dns-prefetch' href='//www.googletagmanager.com' /> 66<link rel="alternate" title="oEmbed (JSON)" type="application/json+oembed" href="https://www.flyingshapes.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fwww.flyingshapes.com%2Fportfolio%2F" /> 67<link rel="alternate" title="oEmbed (XML)" type="text/xml+oembed" href="https://www.flyingshapes.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fwww.flyingshapes.com%2Fportfolio%2F&format=xml" /> 68<style id="wp-img-auto-sizes-contain-inline-css"> 69img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px} 70/*# sourceURL=wp-img-auto-sizes-contain-inline-css */ 71</style> 72<style id="wp-emoji-styles-inline-css"> 73 74 img.wp-smiley, img.emoji { 75 display: inline !important; 76 border: none !important; 77 box-shadow: none !important; 78 height: 1em !important; 79 width: 1em !important; 80 margin: 0 0.07em !important; 81 vertical-align: -0.1em !important; 82 background: none !important; 83 padding: 0 !important; 84 } 85/*# sourceURL=wp-emoji-styles-inline-css */ 86</style> 87<style id="wp-block-library-inline-css"> 88:root{--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122,0,223;--wp-bound-block-color:var(--wp-block-synced-color);--wp-editor-canvas-background:#ddd;--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0,124,186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0,107,160.5;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0,90,135;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}.wp-element-button{cursor:pointer}:root .has-very-light-gray-background-color{background-color:#eee}:root .has-very-dark-gray-background-color{background-color:#313131}:root .has-very-light-gray-color{color:#eee}:root .has-very-dark-gray-color{color:#313131}:root .has-vivid-green-cyan-to-vivid-cyan-blue-gradient-background{background:linear-gradient(135deg,#00d084,#0693e3)}:root .has-purple-crush-gradient-background{background:linear-gradient(135deg,#34e2e4,#4721fb 50%,#ab1dfe)}:root .has-hazy-dawn-gradient-background{background:linear-gradient(135deg,#faaca8,#dad0ec)}:root .has-subdued-olive-gradient-background{background:linear-gradient(135deg,#fafae1,#67a671)}:root .has-atomic-cream-gradient-background{background:linear-gradient(135deg,#fdd79a,#004a59)}:root .has-nightshade-gradient-background{background:linear-gradient(135deg,#330968,#31cdcf)}:root .has-midnight-gradient-background{background:linear-gradient(135deg,#020381,#2874fc)}:root{--wp--preset--font-size--normal:16px;
88--wp--preset--font-size--huge:42px}.has-regular-font-size{font-size:1em}.has-larger-font-size{font-size:2.625em}.has-normal-font-size{font-size:var(--wp--preset--font-size--normal)}.has-huge-font-size{font-size:var(--wp--preset--font-size--huge)}:root .has-text-align-center{text-align:center}:root .has-text-align-left{text-align:left}:root .has-text-align-right{text-align:right}.has-fit-text{white-space:nowrap!important}#end-resizable-editor-section{display:none}.aligncenter{clear:both}.items-justified-left{justify-content:flex-start}.items-justified-center{justify-content:center}.items-justified-right{justify-content:flex-end}.items-justified-space-between{justify-content:space-between}.screen-reader-text{word-wrap:normal!important;border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-break:normal!important}.screen-reader-text:focus{background-color:#ddd;clip-path:none;color:#444;display:block;font-size:1em;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}html :where(.has-border-color){border-style:solid}html :where([style^=border-color],[style*=";border-color"],[style*="; border-color"]){border-style:solid}html :where([style^=border-top-color],[style*=";border-top-color"],[style*="; border-top-color"]){border-top-style:solid}html :where([style^=border-right-color],[style*=";border-right-color"],[style*="; border-right-color"]){border-right-style:solid}html :where([style^=border-bottom-color],[style*=";border-bottom-color"],[style*="; border-bottom-color"]){border-bottom-style:solid}html :where([style^=border-left-color],[style*=";border-left-color"],[style*="; border-left-color"]){border-left-style:solid}html :where([style^=border-width],[style*=";border-width"],[style*="; border-width"]){border-style:solid}html :where([style^=border-top-width],[style*=";border-top-width"],[style*="; border-top-width"]){border-top-style:solid}html :where([style^=border-right-width],[style*=";border-right-width"],[style*="; border-right-width"]){border-right-style:solid}html :where([style^=border-bottom-width],[style*=";border-bottom-width"],[style*="; border-bottom-width"]){border-bottom-style:solid}html :where([style^=border-left-width],[style*=";border-left-width"],[style*="; border-left-width"]){border-left-style:solid}html :where(img[class*=wp-image-]){height:auto;max-width:100%}:where(figure){margin:0 0 1em}html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:var(--wp-admin--admin-bar--height,0px)}@media screen and (max-width:600px){html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:0px}} 89 90/*# sourceURL=/wp-includes/css/dist/block-library/common.min.css */ 91</style> 92 93<style id="global-styles-inline-css"> 94:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--color--ink: #0a0a0a;--wp--preset--color--near-black: #141414;--wp--preset--color--charcoal: #1b1b1b;--wp--preset--color--muted: rgba(255,255,255,0.6);--wp--preset--color--soft: rgba(255,255,255,0.85);--wp--preset--color--paper: #ffffff;--wp--preset--color--accent: #ffffff;--wp--preset--color--accent-hover: rgb(56, 56, 56);--wp--preset--color--line: rgba(255,255,255,0.12);--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,
940) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 0.875rem;--wp--preset--font-size--medium: clamp(0.875rem, 0.875rem + ((1vw - 0.2rem) * 0.455), 1.125rem);--wp--preset--font-size--large: clamp(0.984rem, 0.984rem + ((1vw - 0.2rem) * 0.938), 1.5rem);--wp--preset--font-size--x-large: clamp(2rem, 4vw, 3rem);--wp--preset--font-size--xx-large: clamp(2.75rem, 7vw, 5rem);--wp--preset--font-family--roboto: Roboto, sans-serif;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgb(255, 255, 255), 6px 6px rgb(0, 0, 0);--wp--preset--shadow--crisp: 6px 6px 0px rgb(0, 0, 0);}.wp-block-button{--wp--preset--dimension--25: 25%;--wp--preset--dimension--50: 50%;--wp--preset--dimension--75: 75%;--wp--preset--dimension--100: 100%;}:root { --wp--style--global--content-size: 720px;--wp--style--global--wide-size: 1200px; }:where(body) { margin: 0; }.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }.has-global-padding :where(:not(.alignfull.is-layout-flow) > .has-global-padding:not(.wp-block-block, .alignfull)) { padding-right: 0; padding-left: 0; }.has-global-padding :where(:not(.alignfull.is-layout-flow) > .has-global-padding:not(.wp-block-block, .alignfull)) > .alignfull { margin-left: 0; margin-right: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 24px; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 24px; }:root :where(.is-layout-flow) > :first-child{margin-block-start: 0;}:root :where(.is-layout-flow) > :last-child{margin-block-end: 0;}:root :where(.is-layout-flow) > *{margin-block-start: 24px;margin-block-end: 0;}:root :where(.is-layout-constrained) > :first-child{margin-block-start: 0;}:root :where(.is-layout-constrained) > :last-child{margin-block-end: 0;}:root :where(.is-layout-constrained) > *{margin-block-start: 24px;margin-block-end: 0;}:root :where(.is-layout-flex){gap: 24px;}:root :where(.is-layout-grid){gap: 24px;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained >
94 :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}body{background-color: var(--wp--preset--color--ink);color: var(--wp--preset--color--paper);font-family: var(--wp--preset--font-family--roboto);font-size: var(--wp--preset--font-size--medium);font-weight: 400;line-height: 1.55;--wp--style--root--padding-top: 0px;--wp--style--root--padding-right: 0px;--wp--style--root--padding-bottom: 0px;--wp--style--root--padding-left: 0px;}a:where(:not(.wp-element-button)){color: var(--wp--preset--color--paper);}:root :where(a:where(:not(.wp-element-button)):hover){color: var(--wp--preset--color--accent);}h1, h2, h3, h4, h5, h6{color: var(--wp--preset--color--paper);font-family: var(--wp--preset--font-family--roboto);font-weight: 700;line-height: 1.1;}h1{font-size: var(--wp--preset--font-size--xx-large);}h2{font-size: var(--wp--preset--font-size--x-large);}h3{font-size: var(--wp--preset--font-size--large);}:root :where(.wp-element-button, .wp-block-button__link){background-color: var(--wp--preset--color--ink);border-radius: 980px;border-width: 0;color: var(--wp--preset--color--paper);font-family: var(--wp--preset--font-family--roboto);font-size: clamp(0.875rem, 0.875rem + ((1vw - 0.2rem) * 0.227), 1rem);font-style: inherit;font-weight: 400;letter-spacing: inherit;line-height: inherit;padding-top: 0.75rem;padding-right: 1.375rem;padding-bottom: 0.75rem;padding-left: 1.375rem;text-decoration: none;text-transform: inherit;}:root :where(.wp-element-button:hover, .wp-block-button__link:hover){background-color: var(--wp--preset--color--near-black);color: var(--wp--preset--color--paper);}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-ink-color{color: var(--wp--preset--color--ink) !important;}.has-near-black-color{color: var(--wp--preset--color--near-black) !important;}.has-charcoal-color{color: var(--wp--preset--color--charcoal) !important;}.has-muted-color{color: var(--wp--preset--color--muted) !important;}.has-soft-color{color: var(--wp--preset--color--soft) !important;}.has-paper-color{color: var(--wp--preset--color--paper) !important;}.has-accent-color{color: var(--wp--preset--color--accent) !important;}.has-accent-hover-color{color: var(--wp--preset--color--accent-hover) !important;}.has-line-color{color: var(--wp--preset--color--line) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-ink-background-color{background-color: var(--wp--preset--color--ink) !important;}.has-near-black-background-color{background-color: var(--wp--preset--color--near-black) !important;}.has-charcoal-background-color{background-color: var(--wp--preset--color--charcoal) !important;}.has-muted-background-color{background-color: var(--wp--preset--color--muted) !important;}.has-soft-background-color{background-color: var(--wp--preset--color--soft) !important;}.has-paper-background-color{background-color: var(--wp--preset--color--paper) !important;}.has-accent-background-color{background-color: var(--wp--preset--color--accent) !important;}.has-accent-hover-background-color{background-color: var(--wp--preset--color--accent-hover) !important;}.has-line-background-color{background-color: var(--wp--preset--color--line) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-ink-border-color{border-color: var(--wp--preset--color--ink) !important;}.has-near-black-border-color{border-color: var(--wp--preset--color--near-black) !important;}.has-charcoal-border-color{border-color: var(--wp--preset--color--charcoal) !important;}.has-muted-border-color{border-color: var(--wp--preset--color--muted) !important;}.has-soft-border-color{border-color: var(--wp--preset--color--soft) !important;}.has-paper-border-color{border-color: var(--wp--preset--color--paper) !important;}.has-accent-border-color{border-color: var(--wp--preset--color--accent) !important;}.has-accent-hover-border-color{border-color: var(--wp--preset--color--accent-hover) !important;}.has-line-border-color{border-color: var(--wp--preset--color--line) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}
94.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}.has-xx-large-font-size{font-size: var(--wp--preset--font-size--xx-large) !important;}.has-roboto-font-family{font-family: var(--wp--preset--font-family--roboto) !important;} 95/*# sourceURL=global-styles-inline-css */ 96</style> 97 98<link rel='stylesheet' id='flyingshapes-main-css' href='https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/css/main.css?ver=1790940220' media='all' /> 99<link rel='stylesheet' id='flyingshapes-lightbox-css' href='https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/css/lightbox.css?ver=1789135126' media='all' /> 100 101<!-- Google tag (gtag.js) snippet added by Site Kit --> 102<!-- Google Analytics snippet added by Site Kit -->
vendor: 80 bytes, lines 102-103
102 103<script id="google_gtagjs-js" src="https://www.googletagmanager.com/gtag/js?id=
103G-CLFT2P9W9L
vendor: 18 bytes, line 103
103" async></script>
104<script id="google_gtagjs-js-after"> 105window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);} 106gtag("set","linker",{"domains":["www.flyingshapes.com"]}); 107gtag("js", new Date()); 108gtag("set", "developer_id.dZTNiMT", true); 109gtag("config", "G-CLFT2P9W9L", {"googlesitekit_post_type":"page"}); 110 window._googlesitekit = window._googlesitekit || {}; window._googlesitekit.throttledEvents = []; window._googlesitekit.gtagEvent = (name, data) => { var key = JSON.stringify( { name, data } ); if ( !! window._googlesitekit.throttledEvents[ key ] ) { return; } window._googlesitekit.throttledEvents[ key ] = true; setTimeout( () => { delete window._googlesitekit.throttledEvents[ key ]; }, 5 ); gtag( "event", name, { ...data, event_source: "site-kit" } ); }; 111//# sourceURL=google_gtagjs-js-after 112</script>
112 113<link rel="https://api.w.org/" href="https://www.flyingshapes.com/wp-json/" /><link rel="alternate" title="JSON" type="application/json" href="https://www.flyingshapes.com/wp-json/wp/v2/pages/24" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://www.flyingshapes.com/xmlrpc.php?rsd" /> 114<meta name="generator" content="WordPress 7.1.2" /> 115<link rel='shortlink' href='https://www.flyingshapes.com/?p=24' /> 116<meta name="generator" content="Site Kit by Google 1.188.0" /><style class="wp-fonts-local"> 117@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url('https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/fonts/roboto-latin-400-normal.woff2') format('woff2');} 118@font-face{font-family:Roboto;font-style:italic;font-weight:400;font-display:swap;src:url('https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/fonts/roboto-latin-400-italic.woff2') format('woff2');} 119@font-face{font-family:Roboto;font-style:normal;font-weight:500;font-display:swap;src:url('https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/fonts/roboto-latin-500-normal.woff2') format('woff2');} 120@font-face{font-family:Roboto;font-style:normal;font-weight:700;font-display:swap;src:url('https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/fonts/roboto-latin-700-normal.woff2') format('woff2');} 121@font-face{font-family:Roboto;font-style:italic;font-weight:700;font-display:swap;src:url('https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/fonts/roboto-latin-700-italic.woff2') format('woff2');} 122</style> 123<link rel="icon" href="https://www.flyingshapes.com/wp-content/uploads/2026/09/cropped-FS-Favicon-x256-32x32.png" sizes="32x32" /> 124<link rel="icon" href="https://www.flyingshapes.com/wp-content/uploads/2026/09/cropped-FS-Favicon-x256-192x192.png" sizes="192x192" /> 125<link rel="apple-touch-icon" href="https://www.flyingshapes.com/wp-content/uploads/2026/09/cropped-FS-Favicon-x256-180x180.png" /> 126<meta name="msapplication-TileImage" content="https://www.flyingshapes.com/wp-content/uploads/2026/09/cropped-FS-Favicon-x256-270x270.png" /> 127</head> 128<body class="wp-singular page-template-default page page-id-24 wp-embed-responsive wp-theme-flyingshapes fs-theme"> 129<a class="fs-skip-link" href="#fs-main">Skip to content</a> 130 131<header class="fs-header"> 132 <div class="fs-header__inner"> 133 <a class="fs-brand" href="https://www.flyingshapes.com/"> 134 <img class="fs-brand__wordmark" src="https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/images/logo-wordmark.png" width="281" height="16" alt="Flyingshapes" /> 135 </a> 136 137 <button type="button" class="fs-nav-toggle" data-nav-toggle aria-expanded="false" aria-controls="fs-primary-nav" aria-label="Menu"> 138 <span class="fs-nav-toggle__bar" aria-hidden="true"></span> 139 <span class="fs-nav-toggle__bar" aria-hidden="true"></span> 140 <span class="fs-nav-toggle__bar" aria-hidden="true"></span> 141 </button> 142 143 <nav aria-label="Primary"> 144 <ul id="fs-primary-nav" class="fs-nav" data-nav> 145 <li> 146 <a href="https://www.flyingshapes.com/">Home</a> 147 </li> 148 <li> 149 <a href="https://www.flyingshapes.com/portfolio/" aria-current="page">Portfolio</a> 150 </li> 151 <li><button type="button" data-lightbox="contact">Contact</button></li> 152 </ul> 153 </nav> 154 </div> 155</header> 156<main id="fs-main" class="fs-main"> 157 <article class="fs-section fs-section--tight fs-section--portfolio"> 158 <div class="fs-container"> 159 <h1 class="fs-visually-hidden">Portfolio</h1> 160 161 <div class="fs-portfolio-grid"> 162 <div class="fs-portfolio-card"> 163 <img 164 class="fs-portfolio-card__image" 165 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Periscopio-2.png" 166 alt="" 167 width="800" 168 height="400" 169 fetchpriority="high" /> 170 <div class="fs-portfolio-card__actions"> 171 <a 172 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 173 href="https://app.flyingshapes.com/12a47eb9-739b-40d3-879f-315712ac2284?domeEyeHeight=.6&shadowPlaneOpacity=1" 174 target="_blank" rel="noopener noreferrer" aria-label="Open Periscopio in 3D" 175 > 176 <span class="fs-portfolio-card__icon" aria-hidden="true"> 177 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false">
178 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 179 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 180 </svg> 181 </span> 182 </a> 183 </div> 184 </div> 185 <div class="fs-portfolio-card fs-portfolio-card--split"> 186 <img 187 class="fs-portfolio-card__image" 188 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Molsheim-Coupe.png" 189 alt="" 190 width="800" 191 height="400" 192 fetchpriority="high" /> 193 <div class="fs-portfolio-card__actions"> 194 <button 195 type="button" 196 class="fs-portfolio-card__hit fs-portfolio-card__hit--play" 197 data-media-lightbox="https://www.flyingshapes.com/wp-content/uploads/2023/10/Molsheim_Coupe-compressed.mp4" 198 aria-label="Play video: Molsheim Coupe" 199 > 200 <span class="fs-portfolio-card__icon" aria-hidden="true"> 201 <span class="fs-portfolio-card__play-glyph"></span> 202 </span> 203 </button> 204 <a 205 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 206 href="https://app.flyingshapes.com/f2a08e5c-b42b-498d-acef-68b841247756?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 207 target="_blank" rel="noopener noreferrer" aria-label="Open Molsheim Coupe in 3D" 208 > 209 <span class="fs-portfolio-card__icon" aria-hidden="true"> 210 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 211 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 212 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 213 </svg> 214 </span> 215 </a> 216 </div> 217 </div> 218 <div class="fs-portfolio-card fs-portfolio-card--split"> 219 <img 220 class="fs-portfolio-card__image" 221 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Experimental-Coupe.png" 222 alt="" 223 width="800" 224 height="400" 225 fetchpriority="high" /> 226 <div class="fs-portfolio-card__actions"> 227 <button 228 type="button" 229 class="fs-portfolio-card__hit fs-portfolio-card__hit--play" 230 data-media-lightbox="https://www.flyingshapes.com/wp-content/uploads/2024/06/experimental-coupe-ai.mp4" 231 aria-label="Play video: Experimental Coupe" 232 > 233 <span class="fs-portfolio-card__icon" aria-hidden="true"> 234 <span class="fs-portfolio-card__play-glyph"></span> 235 </span> 236 </button> 237 <a 238 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 239 href="https://app.flyingshapes.com/966f8596-9243-428e-ac83-98478cbd48a3?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 240 target="_blank" rel="noopener noreferrer" aria-label="Open Experimental Coupe in 3D" 241 > 242 <span class="fs-portfolio-card__icon" aria-hidden="true"> 243 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 244 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 245 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 246 </svg> 247 </span> 248 </a> 249 </div> 250 </div> 251 <div class="fs-portfolio-card"> 252 <img 253 class="fs-portfolio-card__image" 254 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Battista.png" 255 alt="" 256 width="800" 257 height="400" 258 loading="lazy" decoding="async" /> 259 <div class="fs-portfolio-card__actions"> 260 <a 261 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 262 href="https://app.flyingshapes.com/1d4fe6e4-4e5e-4a2b-8596-c939a3a03a02?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 263 target="_blank" rel="noopener noreferrer" aria-label="Open Battista in 3D" 264 > 265 <span class="fs-portfolio-card__icon" aria-hidden="true"> 266 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false">
267 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 268 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 269 </svg> 270 </span> 271 </a> 272 </div> 273 </div> 274 <div class="fs-portfolio-card"> 275 <img 276 class="fs-portfolio-card__image" 277 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Battista-Interior-2.png" 278 alt="" 279 width="800" 280 height="400" 281 loading="lazy" decoding="async" /> 282 <div class="fs-portfolio-card__actions"> 283 <a 284 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 285 href="https://app.flyingshapes.com/55e686da-ae2e-4ae7-8d2c-8dfdd5ef5ff7?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 286 target="_blank" rel="noopener noreferrer" aria-label="Open Battista Interior in 3D" 287 > 288 <span class="fs-portfolio-card__icon" aria-hidden="true"> 289 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 290 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 291 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 292 </svg> 293 </span> 294 </a> 295 </div> 296 </div> 297 <div class="fs-portfolio-card"> 298 <img 299 class="fs-portfolio-card__image" 300 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/EV9-Interior-2.png" 301 alt="" 302 width="800" 303 height="400" 304 loading="lazy" decoding="async" /> 305 <div class="fs-portfolio-card__actions"> 306 <a 307 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 308 href="https://app.flyingshapes.com/2703b08e-9d09-4bd1-83d4-45d9e3a19189?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 309 target="_blank" rel="noopener noreferrer" aria-label="Open EV9 Interior in 3D" 310 > 311 <span class="fs-portfolio-card__icon" aria-hidden="true"> 312 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 313 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 314 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 315 </svg> 316 </span> 317 </a> 318 </div> 319 </div> 320 <div class="fs-portfolio-card fs-portfolio-card--split"> 321 <img 322 class="fs-portfolio-card__image" 323 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Wind.png" 324 alt="" 325 width="800" 326 height="400" 327 loading="lazy" decoding="async" /> 328 <div class="fs-portfolio-card__actions"> 329 <button 330 type="button" 331 class="fs-portfolio-card__hit fs-portfolio-card__hit--play" 332 data-media-lightbox="https://www.flyingshapes.com/wp-content/uploads/2023/10/Wind-compressed.mp4" 333 aria-label="Play video: Wind" 334 > 335 <span class="fs-portfolio-card__icon" aria-hidden="true"> 336 <span class="fs-portfolio-card__play-glyph"></span> 337 </span> 338 </button> 339 <a 340 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 341 href="https://app.flyingshapes.com/d6eee81c-8501-4bab-a337-17010dce2b21?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 342 target="_blank" rel="noopener noreferrer" aria-label="Open Wind in 3D" 343 > 344 <span class="fs-portfolio-card__icon" aria-hidden="true"> 345 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false">
346 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 347 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 348 </svg> 349 </span> 350 </a> 351 </div> 352 </div> 353 <div class="fs-portfolio-card fs-portfolio-card--split"> 354 <img 355 class="fs-portfolio-card__image" 356 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/EV9-2.png" 357 alt="" 358 width="800" 359 height="400" 360 loading="lazy" decoding="async" /> 361 <div class="fs-portfolio-card__actions"> 362 <button 363 type="button" 364 class="fs-portfolio-card__hit fs-portfolio-card__hit--play" 365 data-media-lightbox="https://www.flyingshapes.com/wp-content/uploads/2023/12/EV9.mp4" 366 aria-label="Play video: EV9" 367 > 368 <span class="fs-portfolio-card__icon" aria-hidden="true"> 369 <span class="fs-portfolio-card__play-glyph"></span> 370 </span> 371 </button> 372 <a 373 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 374 href="https://app.flyingshapes.com/dd69a480-42c4-4e91-9925-42c42063787e?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 375 target="_blank" rel="noopener noreferrer" aria-label="Open EV9 in 3D" 376 > 377 <span class="fs-portfolio-card__icon" aria-hidden="true"> 378 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 379 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 380 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 381 </svg> 382 </span> 383 </a> 384 </div> 385 </div> 386 <div class="fs-portfolio-card"> 387 <img 388 class="fs-portfolio-card__image" 389 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Sphere-RS.png" 390 alt="" 391 width="800" 392 height="400" 393 loading="lazy" decoding="async" /> 394 <div class="fs-portfolio-card__actions"> 395 <a 396 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 397 href="https://app.flyingshapes.com/1d5612dd-cb74-4e02-8e15-04bcd9ef8655?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 398 target="_blank" rel="noopener noreferrer" aria-label="Open Sphere RS in 3D" 399 > 400 <span class="fs-portfolio-card__icon" aria-hidden="true"> 401 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 402 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 403 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 404 </svg> 405 </span> 406 </a> 407 </div> 408 </div> 409 <div class="fs-portfolio-card fs-portfolio-card--split"> 410 <img 411 class="fs-portfolio-card__image" 412 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Classy-Bavarian.png" 413 alt="" 414 width="800" 415 height="400" 416 loading="lazy" decoding="async" /> 417 <div class="fs-portfolio-card__actions"> 418 <button 419 type="button" 420 class="fs-portfolio-card__hit fs-portfolio-card__hit--play" 421 data-media-lightbox="https://www.flyingshapes.com/wp-content/uploads/2023/10/Classy_Bavarian-compressed.mp4" 422 aria-label="Play video: Classy Bavarian" 423 > 424 <span class="fs-portfolio-card__icon" aria-hidden="true"> 425 <span class="fs-portfolio-card__play-glyph"></span> 426 </span> 427 </button> 428 <a 429 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 430 href="https://app.flyingshapes.com/6918f186-6d60-4b89-a28a-0ebbf853f503?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 431 target="_blank" rel="noopener noreferrer" aria-label="Open Classy Bavarian in 3D" 432 > 433 <span class="fs-portfolio-card__icon" aria-hidden="true"> 434 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false">
435 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 436 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 437 </svg> 438 </span> 439 </a> 440 </div> 441 </div> 442 <div class="fs-portfolio-card fs-portfolio-card--split"> 443 <img 444 class="fs-portfolio-card__image" 445 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Aang.png" 446 alt="" 447 width="800" 448 height="400" 449 loading="lazy" decoding="async" /> 450 <div class="fs-portfolio-card__actions"> 451 <button 452 type="button" 453 class="fs-portfolio-card__hit fs-portfolio-card__hit--play" 454 data-media-lightbox="https://www.flyingshapes.com/wp-content/uploads/2023/10/Avatr-compressed-1.mp4" 455 aria-label="Play video: Aang" 456 > 457 <span class="fs-portfolio-card__icon" aria-hidden="true"> 458 <span class="fs-portfolio-card__play-glyph"></span> 459 </span> 460 </button> 461 <a 462 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 463 href="https://app.flyingshapes.com/5498660c-fd1d-4781-8ff3-ea0a7e48d2b4?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 464 target="_blank" rel="noopener noreferrer" aria-label="Open Aang in 3D" 465 > 466 <span class="fs-portfolio-card__icon" aria-hidden="true"> 467 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 468 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 469 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 470 </svg> 471 </span> 472 </a> 473 </div> 474 </div> 475 <div class="fs-portfolio-card fs-portfolio-card--split"> 476 <img 477 class="fs-portfolio-card__image" 478 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Silver-Arrow.png" 479 alt="" 480 width="800" 481 height="400" 482 loading="lazy" decoding="async" /> 483 <div class="fs-portfolio-card__actions"> 484 <button 485 type="button" 486 class="fs-portfolio-card__hit fs-portfolio-card__hit--play" 487 data-media-lightbox="https://www.flyingshapes.com/wp-content/uploads/2023/10/Silver_Arrow-compressed.mp4" 488 aria-label="Play video: Silver Arrow" 489 > 490 <span class="fs-portfolio-card__icon" aria-hidden="true"> 491 <span class="fs-portfolio-card__play-glyph"></span> 492 </span> 493 </button> 494 <a 495 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 496 href="https://app.flyingshapes.com/70a39edf-8642-48e3-8e5b-9a154426f0e7?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 497 target="_blank" rel="noopener noreferrer" aria-label="Open Silver Arrow in 3D" 498 > 499 <span class="fs-portfolio-card__icon" aria-hidden="true"> 500 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 501 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 502 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 503 </svg> 504 </span> 505 </a> 506 </div> 507 </div> 508 <div class="fs-portfolio-card fs-portfolio-card--split"> 509 <img 510 class="fs-portfolio-card__image" 511 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Italian-Bull.png" 512 alt="" 513 width="800" 514 height="400" 515 loading="lazy" decoding="async" /> 516 <div class="fs-portfolio-card__actions"> 517 <button 518 type="button" 519 class="fs-portfolio-card__hit fs-portfolio-card__hit--play" 520 data-media-lightbox="https://www.flyingshapes.com/wp-content/uploads/2023/10/Italian-Bull-compressed.mp4" 521 aria-label="Play video: Italian Bull" 522 > 523 <span class="fs-portfolio-card__icon" aria-hidden="true"> 524 <span class="fs-portfolio-card__play-glyph"></span> 525 </span> 526 </button> 527 <a 528 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 529 href="https://app.flyingshapes.com/65440530-e52e-4c12-9fd9-4ecb9c218bb9?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 530 target="_blank" rel="noopener noreferrer" aria-label="Open Italian Bull in 3D" 531 > 532 <span class="fs-portfolio-card__icon" aria-hidden="true"> 533 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false">
534 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 535 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 536 </svg> 537 </span> 538 </a> 539 </div> 540 </div> 541 <div class="fs-portfolio-card"> 542 <img 543 class="fs-portfolio-card__image" 544 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Ringtaxi.png" 545 alt="" 546 width="800" 547 height="400" 548 loading="lazy" decoding="async" /> 549 <div class="fs-portfolio-card__actions"> 550 <a 551 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 552 href="https://app.flyingshapes.com/20fb55fd-da68-4af3-912e-e3bb4602c84f?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 553 target="_blank" rel="noopener noreferrer" aria-label="Open Ringtaxi in 3D" 554 > 555 <span class="fs-portfolio-card__icon" aria-hidden="true"> 556 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 557 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 558 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 559 </svg> 560 </span> 561 </a> 562 </div> 563 </div> 564 <div class="fs-portfolio-card fs-portfolio-card--split"> 565 <img 566 class="fs-portfolio-card__image" 567 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/Nordic-Coupe.png" 568 alt="" 569 width="800" 570 height="400" 571 loading="lazy" decoding="async" /> 572 <div class="fs-portfolio-card__actions"> 573 <button 574 type="button" 575 class="fs-portfolio-card__hit fs-portfolio-card__hit--play" 576 data-media-lightbox="https://www.flyingshapes.com/wp-content/uploads/2023/10/Nordic-Coupe-compressed.mp4" 577 aria-label="Play video: Nordic Coupe" 578 > 579 <span class="fs-portfolio-card__icon" aria-hidden="true"> 580 <span class="fs-portfolio-card__play-glyph"></span> 581 </span> 582 </button> 583 <a 584 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 585 href="https://app.flyingshapes.com/ed305e6b-0f78-458a-a9d2-66b10724d74b?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 586 target="_blank" rel="noopener noreferrer" aria-label="Open Nordic Coupe in 3D" 587 > 588 <span class="fs-portfolio-card__icon" aria-hidden="true"> 589 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 590 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 591 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 592 </svg> 593 </span> 594 </a> 595 </div> 596 </div> 597 <div class="fs-portfolio-card"> 598 <img 599 class="fs-portfolio-card__image" 600 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/R5.png" 601 alt="" 602 width="800" 603 height="400" 604 loading="lazy" decoding="async" /> 605 <div class="fs-portfolio-card__actions"> 606 <a 607 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 608 href="https://app.flyingshapes.com/94f4dd54-afa1-43f5-a03d-b09b796b4c25?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 609 target="_blank" rel="noopener noreferrer" aria-label="Open R5 in 3D" 610 > 611 <span class="fs-portfolio-card__icon" aria-hidden="true"> 612 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false">
613 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 614 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 615 </svg> 616 </span> 617 </a> 618 </div> 619 </div> 620 <div class="fs-portfolio-card"> 621 <img 622 class="fs-portfolio-card__image" 623 src="https://www.flyingshapes.com/wp-content/uploads/2024/01/VGT.png" 624 alt="" 625 width="800" 626 height="400" 627 loading="lazy" decoding="async" /> 628 <div class="fs-portfolio-card__actions"> 629 <a 630 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 631 href="https://app.flyingshapes.com/36056834-c6c8-4212-81d8-48bb4236aa0e?domeEyeHeight=.6&moodBoard=false&shadowPlaneOpacity=1" 632 target="_blank" rel="noopener noreferrer" aria-label="Open VGT in 3D" 633 > 634 <span class="fs-portfolio-card__icon" aria-hidden="true"> 635 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 636 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 637 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 638 </svg> 639 </span> 640 </a> 641 </div> 642 </div> 643 <div class="fs-portfolio-card"> 644 <img 645 class="fs-portfolio-card__image" 646 src="https://www.flyingshapes.com/wp-content/uploads/2024/03/id-gta.webp" 647 alt="" 648 width="800" 649 height="400" 650 loading="lazy" decoding="async" /> 651 <div class="fs-portfolio-card__actions"> 652 <a 653 class="fs-portfolio-card__hit fs-portfolio-card__hit--3d" 654 href="https://www.flyingshapes.com/id-gti" 655 aria-label="Open ID GTI in 3D" 656 > 657 <span class="fs-portfolio-card__icon" aria-hidden="true"> 658 <svg class="fs-portfolio-card__glyph" viewBox="0 0 24 24" focusable="false"> 659 <path fill="currentColor" d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-4.31-4.01-.83 1.52zM23.95 11C23.44 4.84 18.29 0 12 0l-.66.03 4.31 4.01.83-1.49C19.75 4.06 22.09 7.24 22.45 11h1.5z"/> 660 <text x="12" y="12" dy="0.35em" text-anchor="middle" fill="currentColor" font-size="7" font-weight="700" font-family="Roboto, sans-serif">3D</text> 661 </svg> 662 </span> 663 </a> 664 </div> 665 </div> 666 </div> 667 668 <p class="fs-disclaimer"> 669 Disclaimer: Our software is independent and not affiliated with the original manufacturers of the depicted vehicles. The shown models are replicas and not original products of the respective automotive manufacturers. All trademarks and designs are owned by their respective rights holders and are used for demonstration purposes only. 670 </p> 671 </div> 672</article></main> 673<footer class="fs-footer"> 674 <div class="fs-footer__grid"> 675 <div> 676 <h4>get started</h4> 677 <ul> 678 <li><button type="button" data-lightbox="trial">free trial</button></li> 679 <li><a href="https://www.flyingshapes.com/faq/">faq</a></li> 680 <li><a href="https://www.flyingshapes.com/setup/">setup XR</a></li> 681 </ul> 682 </div> 683 <div> 684 <h4>community</h4> 685 <ul> 686 <li><a href="https://app.flyingshapes.com" rel="noopener noreferrer">login</a></li> 687 <li><a href="https://www.flyingshapes.com/support/">support</a></li> 688 <li><button type="button" data-lightbox="newsletter">newsletter</button></li> 689 </ul> 690 </div> 691 <div> 692 <h4>reach out</h4> 693 <ul> 694 <li><button type="button" data-lightbox="contact">contact</button></li> 695 <!-- <li><a href="https://www.flyingshapes.com/careers/">careers</a></li> --> 696 <!-- <li><a href="https://www.flyingshapes.com/press/">press</a></li> --> 697 </ul> 698 </div> 699 <div> 700 <h4>legal information</h4> 701 <ul> 702 <li><a href="https://www.flyingshapes.com/imprint/">imprint</a></li> 703 <li><a href="https://www.flyingshapes.com/privacy/">orivacy policy</a></li> 704 </ul> 705 </div> 706 </div> 707 <div class="fs-footer__bottom"> 708 © 2026 flyingshapes GmbH 709 </div> 710</footer> 711 712 <dialog class="fs-lightbox" id="fs-lightbox-newsletter" data-lightbox-panel="newsletter" aria-labelledby="fs-lightbox-title-newsletter"> 713 <div class="fs-lightbox__panel"> 714 <button type="button" class="fs-lightbox__close" data-lightbox-close aria-label="Close"> 715 <span aria-hidden="true">×</span> 716 </button> 717 <div class="fs-lightbox__body"> 718 <h2 id="fs-lightbox-title-newsletter" class="fs-lightbox__title">Stay up to date</h2> 719 <p class="fs-lightbox__desc">If you sign up for our newsletter, we will occasionally send you updates about our company, our upcoming product, beta launches and we will share some information on the latest trends in product design, virtual reality and CAD.</p> 720 <div class="fs-lightbox__form" data-ac-form="newsletter" data-fs-form-slot="newsletter"> 721 <form method="POST" action="https://flyingshapes.activehosted.com/proc.php" id="_form_1_" class="_form _form_1 _inline-form _dark" novalidate data-styles-version="5"> 722 <input type="hidden" name="u" value="1" /> 723 <input type="hidden" name="f" value="1" /> 724 <input type="hidden" name="s" />
725 <input type="hidden" name="c" value="0" /> 726 <input type="hidden" name="m" value="0" /> 727 <input type="hidden" name="act" value="sub" /> 728 <input type="hidden" name="v" value="2" /> 729 <input type="hidden" name="or" value="bd96b2eb-9b61-9dec-8861-59ebe557602c" /> 730 <div class="_form-content"> 731 <div class="_form_element _x98082402 _full_width " > 732 <label for="fullname" class="_form-label"> 733 Name<span class="field-required"> 734 * 735 </span> 736 </label> 737 <div class="_field-wrapper"> 738 <input type="text" id="fullname" name="fullname" placeholder="How may we call you?" required/> 739 </div> 740 </div> 741 <div class="_form_element _x05723213 _full_width " > 742 <label for="email" class="_form-label"> 743 E-mail<span class="field-required"> 744 * 745 </span> 746 </label> 747 <div class="_field-wrapper"> 748 <input type="text" id="email" name="email" placeholder="" required/> 749 </div> 750</div> 751<div class="_button-wrapper _full_width"> 752 <button id="_form_1_submit" class="_submit" type="submit"> 753 subscribe 754 </button> 755</div> 756<div class="_clear-element"> 757</div> 758</div> 759<div class="_form-thank-you" style="display:none;"> 760</div> 761</form>
761<script> 762window.cfields = []; 763window._show_thank_you = function(id, message, trackcmp_url, email) { 764 var form = document.getElementById('_form_' + id + '_'), thank_you = form.querySelector('._form-thank-you'); 765 form.querySelector('._form-content').style.display = 'none'; 766 thank_you.innerHTML = message; 767 thank_you.style.display = 'block'; 768 const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias; 769 var visitorObject = window[vgoAlias]; 770 if (email && typeof visitorObject !== 'undefined') { 771 visitorObject('setEmail', email); 772 visitorObject('update'); 773 } else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) { 774 // Site tracking URL to use after inline form submission. 775 _load_script(trackcmp_url); 776 } 777 if (typeof window._form_callback !== 'undefined') window._form_callback(id); 778 thank_you.setAttribute('tabindex', '-1'); 779 thank_you.focus(); 780}; 781window._show_unsubscribe = function(id, message, trackcmp_url, email) { 782 var form = document.getElementById('_form_' + id + '_'), unsub = form.querySelector('._form-thank-you'); 783 var branding = form.querySelector('._form-branding'); 784 if (branding) { 785 branding.style.display = 'none'; 786 } 787 form.querySelector('._form-content').style.display = 'none'; 788 unsub.style.display = 'block'; 789 form.insertAdjacentHTML('afterend', message) 790 const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias; 791 var visitorObject = window[vgoAlias]; 792 if (email && typeof visitorObject !== 'undefined') { 793 visitorObject('setEmail', email); 794 visitorObject('update'); 795 } else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) { 796 // Site tracking URL to use after inline form submission. 797 _load_script(trackcmp_url); 798 } 799 if (typeof window._form_callback !== 'undefined') window._form_callback(id); 800}; 801window._show_error = function(id, message, html) { 802 var form = document.getElementById('_form_' + id + '_'), 803 err = document.createElement('div'), 804 button = form.querySelector('button[type="submit"]'), 805 old_error = form.querySelector('._form_error'); 806 if (old_error) old_error.parentNode.removeChild(old_error); 807 err.innerHTML = message; 808 err.className = '_error-inner _form_error _no_arrow'; 809 var wrapper = document.createElement('div'); 810 wrapper.className = '_form-inner _show_be_error'; 811 wrapper.appendChild(err); 812 button.parentNode.insertBefore(wrapper, button); 813 var submitButton = form.querySelector('[id^="_form"][id$="_submit"]'); 814 submitButton.disabled = false; 815 submitButton.classList.remove('processing'); 816 if (html) { 817 var div = document.createElement('div'); 818 div.className = '_error-html'; 819 div.innerHTML = html; 820 err.appendChild(div); 821 } 822}; 823window._show_pc_confirmation = function(id, header, detail, show, email) { 824 var form = document.getElementById('_form_' + id + '_'), pc_confirmation = form.querySelector('._form-pc-confirmation'); 825 if (pc_confirmation.style.display === 'none') { 826 form.querySelector('._form-content').style.display = 'none'; 827 pc_confirmation.innerHTML = "<div class='_form-title'>" + header + "</div>" + "<p>" + detail + "</p>" + 828 "<button class='_submit' id='hideButton'>Manage preferences</button>"; 829 pc_confirmation.style.display = 'block'; 830 var mp = document.querySelector('input[name="mp"]'); 831 mp.value = '0'; 832 } else { 833 form.querySelector('._form-content').style.display = 'inline'; 834 pc_confirmation.style.display = 'none'; 835 } 836 837 var hideButton = document.getElementById('hideButton'); 838 // Add event listener to the button 839 hideButton.addEventListener('click', function() { 840 var submitButton = document.querySelector('#_form_1_submit'); 841 submitButton.disabled = false; 842 submitButton.classList.remove('processing'); 843 var mp = document.querySelector('input[name="mp"]'); 844 mp.value = '1'; 845 const cacheBuster = new URL(window.location.href); 846 cacheBuster.searchParams.set('v', new Date().getTime()); 847 window.location.href = cacheBuster.toString(); 848 }); 849 850 const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias; 851 var visitorObject = window[vgoAlias]; 852 if (email && typeof visitorObject !== 'undefined') { 853 visitorObject('setEmail', email); 854 visitorObject('update'); 855 } else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) { 856 // Site tracking URL to use after inline form submission. 857 _load_script(trackcmp_url); 858 } 859 if (typeof window._form_callback !== 'undefined') window._form_callback(id); 860}; 861window._load_script = function(url, callback, isSubmit) { 862 var head = document.querySelector('head'), script = document.createElement('script'), r = false;
863 var submitButton = document.querySelector('#_form_1_submit'); 864 script.charset = 'utf-8'; 865 script.src = url; 866 if (callback) { 867 script.onload = script.onreadystatechange = function() { 868 if (!r && (!this.readyState || this.readyState == 'complete')) { 869 r = true; 870 callback(); 871 } 872 }; 873 } 874 script.onerror = function() { 875 if (isSubmit) { 876 if (script.src.length > 10000) { 877 _show_error("1", "Sorry, your submission failed. Please shorten your responses and try again."); 878 } else { 879 _show_error("1", "Sorry, your submission failed. Please try again."); 880 } 881 submitButton.disabled = false; 882 submitButton.classList.remove('processing'); 883 } 884 } 885 886 head.appendChild(script); 887}; 888(function() { 889 var iti; 890 if (window.location.search.search("excludeform") !== -1) return false; 891 var getCookie = function(name) { 892 var match = document.cookie.match(new RegExp('(^|; )' + name + '=([^;]+)')); 893 return match ? match[2] : localStorage.getItem(name); 894 } 895 var setCookie = function(name, value) { 896 var now = new Date(); 897 var time = now.getTime(); 898 var expireTime = time + 1000 * 60 * 60 * 24 * 365; 899 now.setTime(expireTime); 900 document.cookie = name + '=' + value + '; expires=' + now + ';path=/; Secure; SameSite=Lax;'; 901 localStorage.setItem(name, value); 902 } 903 var addEvent = function(element, event, func) { 904 if (element.addEventListener) { 905 element.addEventListener(event, func); 906 } else { 907 var oldFunc = element['on' + event]; 908 element['on' + event] = function() { 909 oldFunc.apply(this, arguments); 910 func.apply(this, arguments); 911 }; 912 } 913 } 914 var _removed = false; 915 var form_to_submit = document.getElementById('_form_1_'); 916 var allInputs = form_to_submit.querySelectorAll('input, select, textarea'), tooltips = [], submitted = false; 917 918 var getUrlParam = function(name) { 919 if (name.toLowerCase() !== 'email') { 920 var params = new URLSearchParams(window.location.search); 921 return params.get(name) || false; 922 } 923 // email is a special case because a plus is valid in the email address 924 var qString = window.location.search; 925 if (!qString) { 926 return false; 927 } 928 var parameters = qString.substr(1).split('&'); 929 for (var i = 0; i < parameters.length; i++) { 930 var parameter = parameters[i].split('='); 931 if (parameter[0].toLowerCase() === 'email') { 932 return parameter[1] === undefined ? true : decodeURIComponent(parameter[1]); 933 } 934 } 935 return false; 936 }; 937 938 var acctDateFormat = "%B-%d-%Y"; 939 var getNormalizedDate = function(date, acctFormat) { 940 var decodedDate = decodeURIComponent(date); 941 if (acctFormat && acctFormat.match(/(%d|%e).*%m/gi) !== null) { 942 return decodedDate.replace(/(\d{2}).*(\d{2}).*(\d{4})/g, '$3-$2-$1'); 943 } else if (Date.parse(decodedDate)) { 944 var dateObj = new Date(decodedDate); 945 var year = dateObj.getFullYear(); 946 var month = dateObj.getMonth() + 1; 947 var day = dateObj.getDate(); 948 return `${year}-${month < 10 ? `0${month}` : month}-${day < 10 ? `0${day}` : day}`; 949 } 950 return false; 951 }; 952 953 var getNormalizedTime = function(time) { 954 var hour, minutes; 955 var decodedTime = decodeURIComponent(time); 956 var timeParts = Array.from(decodedTime.matchAll(/(\d{1,2}):(\d{1,2})\W*([AaPp][Mm])?/gm))[0]; 957 if (timeParts[3]) { // 12 hour format 958 var isPM = timeParts[3].toLowerCase() === 'pm'; 959 if (isPM) { 960 hour = parseInt(timeParts[1]) === 12 ? '12' : `${parseInt(timeParts[1]) + 12}`; 961 } else { 962 hour = parseInt(timeParts[1]) === 12 ? '0' : timeParts[1]; 963 } 964 } else { // 24 hour format 965 hour = timeParts[1]; 966 } 967 var normalizedHour = parseInt(hour) < 10 ? `0${parseInt(hour)}` : hour; 968 var minutes = timeParts[2]; 969 return `${normalizedHour}:${minutes}`; 970 }; 971 972 for (var i = 0; i < allInputs.length; i++) { 973 var regexStr = "field\\[(\\d+)\\]"; 974 var results = new RegExp(regexStr).exec(allInputs[i].name); 975 if (results != undefined) { 976 allInputs[i].dataset.name = allInputs[i].name.match(/\[time\]$/) 977 ? `${window.cfields[results[1]]}_time` 978 : window.cfields[results[1]]; 979 } else { 980 allInputs[i].dataset.name = allInputs[i].name; 981 } 982 var fieldVal = getUrlParam(allInputs[i].dataset.name); 983 984 if (fieldVal) {
985 if (allInputs[i].dataset.autofill === "false") { 986 continue; 987 } 988 if (allInputs[i].type == "radio" || allInputs[i].type == "checkbox") { 989 if (allInputs[i].value == fieldVal) { 990 allInputs[i].checked = true; 991 } 992 } else if (allInputs[i].type == "date") { 993 allInputs[i].value = getNormalizedDate(fieldVal, acctDateFormat); 994 } else if (allInputs[i].type == "time") { 995 allInputs[i].value = getNormalizedTime(fieldVal); 996 } else { 997 allInputs[i].value = fieldVal; 998 } 999 } 1000 } 1001 1002 var remove_tooltips = function() { 1003 for (var i = 0; i < tooltips.length; i++) { 1004 tooltips[i].tip.parentNode.removeChild(tooltips[i].tip); 1005 } 1006 tooltips = []; 1007 }; 1008 var remove_tooltip = function(elem) { 1009 for (var i = 0; i < tooltips.length; i++) { 1010 if (tooltips[i].elem === elem) { 1011 tooltips[i].tip.parentNode.removeChild(tooltips[i].tip); 1012 tooltips.splice(i, 1); 1013 return; 1014 } 1015 } 1016 }; 1017 var create_tooltip = function(elem, text) { 1018 var tooltip = document.createElement('div'), 1019 arrow = document.createElement('div'), 1020 inner = document.createElement('div'), new_tooltip = {}; 1021 tooltip.id = `${elem.id}-error`; 1022 tooltip.setAttribute('role', 'alert') 1023 if (elem.type != 'radio' && (elem.type != 'checkbox' || elem.name === 'sms_consent')) { 1024 tooltip.className = '_error'; 1025 arrow.className = '_error-arrow'; 1026 inner.className = '_error-inner'; 1027 inner.innerHTML = text; 1028 tooltip.appendChild(arrow); 1029 tooltip.appendChild(inner); 1030 elem.parentNode.appendChild(tooltip); 1031 } else { 1032 tooltip.className = '_error-inner _no_arrow'; 1033 tooltip.innerHTML = text; 1034 elem.parentNode.insertBefore(tooltip, elem); 1035 new_tooltip.no_arrow = true; 1036 } 1037 new_tooltip.tip = tooltip; 1038 new_tooltip.elem = elem; 1039 tooltips.push(new_tooltip); 1040 return new_tooltip; 1041 }; 1042 var resize_tooltip = function(tooltip) { 1043 var rect = tooltip.elem.getBoundingClientRect(); 1044 var doc = document.documentElement, 1045 scrollPosition = rect.top - ((window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)); 1046 if (scrollPosition < 40) { 1047 tooltip.tip.className = tooltip.tip.className.replace(/ ?(_above|_below) ?/g, '') + ' _below'; 1048 } else { 1049 tooltip.tip.className = tooltip.tip.className.replace(/ ?(_above|_below) ?/g, '') + ' _above'; 1050 } 1051 }; 1052 var resize_tooltips = function() { 1053 if (_removed) return; 1054 for (var i = 0; i < tooltips.length; i++) { 1055 if (!tooltips[i].no_arrow) resize_tooltip(tooltips[i]); 1056 } 1057 }; 1058 var validate_field = function(elem, remove) { 1059 var tooltip = null, value = elem.value, no_error = true; 1060 remove ? remove_tooltip(elem) : false; 1061 elem.removeAttribute('aria-invalid'); 1062 elem.removeAttribute('aria-describedby'); 1063 if (elem.type != 'checkbox') elem.className = elem.className.replace(/ ?_has_error ?/g, ''); 1064 if (elem.getAttribute('required') !== null) { 1065 if (elem.type == 'radio' || (elem.type == 'checkbox' && /any/.test(elem.className))) { 1066 var elems = form_to_submit.elements[elem.name]; 1067 if (!(elems instanceof NodeList || elems instanceof HTMLCollection) || elems.length <= 1) { 1068 no_error = elem.checked; 1069 } 1070 else { 1071 no_error = false; 1072 for (var i = 0; i < elems.length; i++) { 1073 if (elems[i].checked) no_error = true; 1074 } 1075 } 1076 if (!no_error) { 1077 tooltip = create_tooltip(elem, "Please select an option."); 1078 } 1079 } else if (elem.type =='checkbox') { 1080 var elems = form_to_submit.elements[elem.name], found = false, err = []; 1081 no_error = true; 1082 for (var i = 0; i < elems.length; i++) { 1083 if (elems[i].getAttribute('required') === null) continue; 1084 if (!found && elems[i] !== elem) return true; 1085 found = true; 1086 elems[i].className = elems[i].className.replace(/ ?_has_error ?/g, ''); 1087 if (!elems[i].checked) { 1088 no_error = false;
1089 elems[i].className = elems[i].className + ' _has_error'; 1090 err.push("Checking %s is required".replace("%s", elems[i].value)); 1091 } 1092 } 1093 if (!no_error) { 1094 tooltip = create_tooltip(elem, err.join('<br/>')); 1095 } 1096 } else if (elem.tagName == 'SELECT') { 1097 var selected = true; 1098 if (elem.multiple) { 1099 selected = false; 1100 for (var i = 0; i < elem.options.length; i++) { 1101 if (elem.options[i].selected) { 1102 selected = true; 1103 break; 1104 } 1105 } 1106 } else { 1107 for (var i = 0; i < elem.options.length; i++) { 1108 if (elem.options[i].selected 1109 && (!elem.options[i].value 1110 || (elem.options[i].value.match(/\n/g))) 1111 ) { 1112 selected = false; 1113 } 1114 } 1115 } 1116 if (!selected) { 1117 elem.className = elem.className + ' _has_error'; 1118 no_error = false; 1119 tooltip = create_tooltip(elem, "Please select an option."); 1120 } 1121 } else if (value === undefined || value === null || value === '') { 1122 elem.className = elem.className + ' _has_error'; 1123 no_error = false; 1124 tooltip = create_tooltip(elem, "This field is required."); 1125 } 1126 } 1127 if (no_error && elem.name == 'email') { 1128 if (!value.match(/^[\+_a-z0-9-'&=]+(\.[\+_a-z0-9-']+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/i)) { 1129 elem.className = elem.className + ' _has_error'; 1130 no_error = false; 1131 tooltip = create_tooltip(elem, "Enter a valid email address."); 1132 } 1133 } 1134 if (no_error && (elem.id == 'phone')) { 1135 if (elem.value.trim() && typeof iti != 'undefined' && !iti.isValidNumber()) { 1136 elem.className = elem.className + ' _has_error'; 1137 no_error = false; 1138 tooltip = create_tooltip(elem, "Enter a valid phone number."); 1139 } 1140 } 1141 if (no_error && /date_field/.test(elem.className)) { 1142 if (!value.match(/^\d\d\d\d-\d\d-\d\d$/)) { 1143 elem.className = elem.className + ' _has_error'; 1144 no_error = false; 1145 tooltip = create_tooltip(elem, "Enter a valid date."); 1146 } 1147 } 1148 1149 if (no_error && elem.name === 'sms_consent') { 1150 const showError = !!elem.attributes.required && !elem.checked; 1151 if (showError) { 1152 elem.className = elem.className + ' _has_error'; 1153 no_error = false; 1154 tooltip = create_tooltip(elem, "Please check this box to continue"); 1155 } else { 1156 elem.className = elem.className.replace(/ ?_has_error ?/g, ''); 1157 } 1158 } 1159 tooltip ? resize_tooltip(tooltip) : false; 1160 if (!no_error && elem.hasAttribute('id')) { 1161 elem.setAttribute('aria-invalid', 'true'); 1162 elem.setAttribute('aria-describedby', `${elem.id}-error`); 1163 } 1164 return no_error; 1165 }; 1166 var needs_validate = function(el) { 1167 if(el.getAttribute('required') !== null){ 1168 return true; 1169 } 1170 if((el.name === 'email' || el.name === 'phone' || el.id === 'sms_consent') && el.value !== ""){ 1171 return true; 1172 } 1173 1174 return false; 1175 }; 1176 var validate_email_or_phone_required = function() { 1177 var emailInput = form_to_submit.querySelector('input[name="email"]'); 1178 var phoneInput = form_to_submit.querySelector('input[name="phone"]'); 1179 if (!emailInput && !phoneInput) { 1180 return true; 1181 } 1182 var hasEmailValue = emailInput && emailInput.value.trim() !== '';
1183 var hasPhoneValue = phoneInput && phoneInput.value.trim() !== ''; 1184 if (hasEmailValue || hasPhoneValue) { 1185 return true; 1186 } 1187 var errorField = emailInput || phoneInput; 1188 errorField.className = errorField.className.replace(/ ?_has_error ?/g, '') + ' _has_error'; 1189 var tooltip = create_tooltip( 1190 errorField, 1191 "Forms must have an email field or a phone field present" 1192 ); 1193 resize_tooltip(tooltip); 1194 errorField.setAttribute('aria-invalid', 'true'); 1195 if (errorField.hasAttribute('id')) { 1196 errorField.setAttribute('aria-describedby', errorField.id + '-error'); 1197 } 1198 return false; 1199 }; 1200 var validate_form = function(e) { 1201 var err = form_to_submit.querySelector('._form_error'), no_error = true; 1202 if (!submitted) { 1203 submitted = true; 1204 for (var i = 0, len = allInputs.length; i < len; i++) { 1205 var input = allInputs[i]; 1206 if (needs_validate(input)) { 1207 if (input.type == 'text' || input.type == 'number' || input.type == 'time' || input.type == 'tel') { 1208 addEvent(input, 'blur', function() { 1209 this.value = this.value.trim(); 1210 validate_field(this, true); 1211 }); 1212 addEvent(input, 'input', function() { 1213 validate_field(this, true); 1214 }); 1215 } else if (input.type == 'radio' || input.type == 'checkbox') { 1216 (function(el) { 1217 function getElementsArray(name){ 1218 const value = form_to_submit.elements[name]; 1219 if (Array.isArray(value)){ 1220 return value; 1221 } 1222 return [value]; 1223 } 1224 var radios = getElementsArray(el.name); 1225 for (var i = 0; i < radios.length; i++) { 1226 addEvent(radios[i], 'change', function() { 1227 validate_field(el, true); 1228 }); 1229 } 1230 })(input); 1231 } else if (input.tagName == 'SELECT') { 1232 addEvent(input, 'change', function() { 1233 validate_field(this, true); 1234 }); 1235 } else if (input.type == 'textarea'){ 1236 addEvent(input, 'input', function() { 1237 validate_field(this, true); 1238 }); 1239 } 1240 } 1241 } 1242 } 1243 remove_tooltips(); 1244 for (var i = 0, len = allInputs.length; i < len; i++) { 1245 var elem = allInputs[i]; 1246 if (needs_validate(elem)) { 1247 if (elem.tagName.toLowerCase() !== "select") { 1248 elem.value = elem.value.trim(); 1249 } 1250 validate_field(elem) ? true : no_error = false; 1251 } 1252 } 1253 if (!validate_email_or_phone_required()) { 1254 no_error = false; 1255 } 1256 if (!no_error && e) { 1257 e.preventDefault(); 1258 } 1259 if (!no_error) { 1260 const firstFocusableError = form_to_submit.querySelector('._has_error:not([disabled])'); 1261 if (firstFocusableError && typeof firstFocusableError.focus === 'function') { 1262 firstFocusableError.focus(); 1263 } 1264 } 1265 resize_tooltips(); 1266 return no_error; 1267 }; 1268 addEvent(window, 'resize', resize_tooltips); 1269 addEvent(window, 'scroll', resize_tooltips); 1270 1271 var _form_serialize = function(form){if(!form||form.nodeName!=="FORM"){return }var i,j,q=[];for(i=0;i<form.elements.length;i++){if(form.elements[i].name===""){continue}switch(form.elements[i].nodeName){case"INPUT":switch(form.elements[i].type){case"tel":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].previousSibling.querySelector('div.iti__selected-dial-code').innerText)+encodeURIComponent(" ")+encodeURIComponent(form.elements[i].value));break;case"text":case"number":case"date":case"time":case"hidden":case"password":case"button":case"reset":case"submit":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break;case"checkbox":case"radio":if(form.elements[i].checked){q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value))}break;case"file":break}break;case"TEXTAREA":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break;case"SELECT":switch(form.elements[i].type){case"select-one":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break;case"select-multiple":for(j=0;j<form.elements[i].options.length;j++){if(form.elements[i].options[j].selected){q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].options[j].value))}}break}break;case"BUTTON":switch(form.elements[i].type){case"reset":case"submit":case"button":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break}break}}return q.join("&")}; 1272 1273 const formSupportsPost = false;
1274 var form_submit = function(e) { 1275 1276 e.preventDefault(); 1277 if(form_to_submit.querySelector('input[name="phone"]') && typeof iti != 'undefined') { 1278 form_to_submit.querySelector('input[name="phone"]').value = iti.getNumber(); 1279 } 1280 if (validate_form()) { 1281 // use this trick to get the submit button & disable it using plain javascript 1282 var submitButton = e.target.querySelector('#_form_1_submit'); 1283 submitButton.disabled = true; 1284 submitButton.classList.add('processing'); 1285 var serialized = _form_serialize(document.getElementById('_form_1_')).replace(/%0A/g, '\\n'); 1286 var err = form_to_submit.querySelector('._form_error'); 1287 err ? err.parentNode.removeChild(err) : false; 1288 async function submitForm() { 1289 var formData = new FormData(); 1290 const searchParams = new URLSearchParams(serialized); 1291 searchParams.forEach((value, key) => { 1292 if (key !== 'hideButton') { 1293 formData.append(key, value); 1294 } 1295 }); 1296 let request = { 1297 headers: { 1298 "Accept": "application/json" 1299 }, 1300 body: formData, 1301 method: "POST" 1302 }; 1303 1304 let pageUrlParams = new URLSearchParams(window.location.search); 1305 if (pageUrlParams.has('t')) { 1306 request.headers.Authorization = 'Bearer ' + pageUrlParams.get('t'); 1307 } 1308 const response = await fetch('https://flyingshapes.activehosted.com/proc.php?jsonp=true', request); 1309 1310 return response.json(); 1311 } 1312 if (formSupportsPost) { 1313 submitForm().then((data) => { 1314 eval(data.js); 1315 }).catch(() => { 1316 _show_error("1", "Sorry, your submission failed. Please try again."); 1317 }); 1318 } else { 1319 _load_script('https://flyingshapes.activehosted.com/proc.php?' + serialized + '&jsonp=true', null, true); 1320 } 1321 } 1322 return false; 1323 }; 1324 addEvent(form_to_submit, 'submit', form_submit); 1325})(); 1326 1327</script>
1327 </div> 1328 <p class="fs-lightbox__legal">Our <a href="https://www.flyingshapes.com/privacy/">Privacy Policy</a> applies.</p> 1329 </div> 1330 </div> 1331 </dialog> 1332 <dialog class="fs-lightbox" id="fs-lightbox-contact" data-lightbox-panel="contact" aria-labelledby="fs-lightbox-title-contact"> 1333 <div class="fs-lightbox__panel"> 1334 <button type="button" class="fs-lightbox__close" data-lightbox-close aria-label="Close"> 1335 <span aria-hidden="true">×</span> 1336 </button> 1337 <div class="fs-lightbox__body"> 1338 <h2 id="fs-lightbox-title-contact" class="fs-lightbox__title">How can we help?</h2> 1339 <p class="fs-lightbox__desc">You have questions regarding our software? We are looking forward to get in touch with you!</p> 1340 <div class="fs-lightbox__form" data-ac-form="contact" data-fs-form-slot="contact"> 1341 <form method="POST" action="https://flyingshapes.activehosted.com/proc.php" id="_form_14_" class="_form _form_14 _inline-form _dark" novalidate data-styles-version="5"> 1342 <input type="hidden" name="u" value="14" /> 1343 <input type="hidden" name="f" value="14" /> 1344 <input type="hidden" name="s" /> 1345 <input type="hidden" name="c" value="0" /> 1346 <input type="hidden" name="m" value="0" /> 1347 <input type="hidden" name="act" value="sub" /> 1348 <input type="hidden" name="v" value="2" /> 1349 <input type="hidden" name="or" value="d94998e4-e031-48a8-b23e-2b5a9d94695a" /> 1350 <div class="_form-content"> 1351 <div class="_form_element _x98082402 _full_width " > 1352 <label for="fullname" class="_form-label"> 1353 </label> 1354 <div class="_field-wrapper"> 1355 <input type="text" id="fullname" name="fullname" placeholder="How may we call you?" /> 1356 </div> 1357 </div> 1358 <div class="_form_element _x43160217 _full_width " > 1359 <label for="phone" class="_form-label"> 1360 </label> 1361 <div class="_field-wrapper"> 1362 <input type="text" id="phone" name="phone" placeholder="Type your phone number" /> 1363 </div> 1364 </div> 1365 <div class="_form_element _x05723213 _full_width " > 1366 <label for="email" class="_form-label"> 1367 </label> 1368 <div class="_field-wrapper"> 1369 <input type="text" id="email" name="email" placeholder="Type your email" required/> 1370 </div> 1371 </div> 1372 <div class="_form_element _x72819360 _full_width _clear" > 1373 <div class="_html-code"> 1374 </div> 1375 </div> 1376 <div class="_form_element _x14647724 _full_width " > 1377 <label for="field[33]" class="_form-label"> 1378 </label> 1379 <div class="_field-wrapper"> 1380 <textarea id="field[33]" name="field[33]" placeholder="How can we help you?" ></textarea> 1381 </div> 1382 </div> 1383 <div class="_button-wrapper _full_width"> 1384 <button id="_form_14_submit" class="_submit" type="submit"> 1385 send 1386 </button> 1387 </div> 1388 <div class="_clear-element"> 1389 </div> 1390 </div> 1391 <div class="_form-thank-you" style="display:none;"> 1392 </div> 1393 </form>
1393<script> 1394window.cfields = {"33":"request"}; 1395window._show_thank_you = function(id, message, trackcmp_url, email) { 1396 var form = document.getElementById('_form_' + id + '_'), thank_you = form.querySelector('._form-thank-you'); 1397 form.querySelector('._form-content').style.display = 'none'; 1398 thank_you.innerHTML = message; 1399 thank_you.style.display = 'block'; 1400 const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias; 1401 var visitorObject = window[vgoAlias]; 1402 if (email && typeof visitorObject !== 'undefined') { 1403 visitorObject('setEmail', email); 1404 visitorObject('update'); 1405 } else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) { 1406 // Site tracking URL to use after inline form submission. 1407 _load_script(trackcmp_url); 1408 } 1409 if (typeof window._form_callback !== 'undefined') window._form_callback(id); 1410 thank_you.setAttribute('tabindex', '-1'); 1411 thank_you.focus(); 1412}; 1413window._show_unsubscribe = function(id, message, trackcmp_url, email) { 1414 var form = document.getElementById('_form_' + id + '_'), unsub = form.querySelector('._form-thank-you'); 1415 var branding = form.querySelector('._form-branding'); 1416 if (branding) { 1417 branding.style.display = 'none'; 1418 } 1419 form.querySelector('._form-content').style.display = 'none'; 1420 unsub.style.display = 'block'; 1421 form.insertAdjacentHTML('afterend', message) 1422 const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias; 1423 var visitorObject = window[vgoAlias]; 1424 if (email && typeof visitorObject !== 'undefined') { 1425 visitorObject('setEmail', email); 1426 visitorObject('update'); 1427 } else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) { 1428 // Site tracking URL to use after inline form submission. 1429 _load_script(trackcmp_url); 1430 } 1431 if (typeof window._form_callback !== 'undefined') window._form_callback(id); 1432}; 1433window._show_error = function(id, message, html) { 1434 var form = document.getElementById('_form_' + id + '_'), 1435 err = document.createElement('div'), 1436 button = form.querySelector('button[type="submit"]'), 1437 old_error = form.querySelector('._form_error'); 1438 if (old_error) old_error.parentNode.removeChild(old_error); 1439 err.innerHTML = message; 1440 err.className = '_error-inner _form_error _no_arrow'; 1441 var wrapper = document.createElement('div'); 1442 wrapper.className = '_form-inner _show_be_error'; 1443 wrapper.appendChild(err); 1444 button.parentNode.insertBefore(wrapper, button); 1445 var submitButton = form.querySelector('[id^="_form"][id$="_submit"]'); 1446 submitButton.disabled = false; 1447 submitButton.classList.remove('processing'); 1448 if (html) { 1449 var div = document.createElement('div'); 1450 div.className = '_error-html'; 1451 div.innerHTML = html; 1452 err.appendChild(div); 1453 } 1454}; 1455window._show_pc_confirmation = function(id, header, detail, show, email) { 1456 var form = document.getElementById('_form_' + id + '_'), pc_confirmation = form.querySelector('._form-pc-confirmation'); 1457 if (pc_confirmation.style.display === 'none') { 1458 form.querySelector('._form-content').style.display = 'none'; 1459 pc_confirmation.innerHTML = "<div class='_form-title'>" + header + "</div>" + "<p>" + detail + "</p>" + 1460 "<button class='_submit' id='hideButton'>Manage preferences</button>"; 1461 pc_confirmation.style.display = 'block'; 1462 var mp = document.querySelector('input[name="mp"]'); 1463 mp.value = '0'; 1464 } else { 1465 form.querySelector('._form-content').style.display = 'inline'; 1466 pc_confirmation.style.display = 'none'; 1467 } 1468 1469 var hideButton = document.getElementById('hideButton'); 1470 // Add event listener to the button 1471 hideButton.addEventListener('click', function() { 1472 var submitButton = document.querySelector('#_form_14_submit'); 1473 submitButton.disabled = false; 1474 submitButton.classList.remove('processing'); 1475 var mp = document.querySelector('input[name="mp"]'); 1476 mp.value = '1'; 1477 const cacheBuster = new URL(window.location.href); 1478 cacheBuster.searchParams.set('v', new Date().getTime()); 1479 window.location.href = cacheBuster.toString(); 1480 }); 1481 1482 const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias; 1483 var visitorObject = window[vgoAlias]; 1484 if (email && typeof visitorObject !== 'undefined') { 1485 visitorObject('setEmail', email); 1486 visitorObject('update'); 1487 } else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) { 1488 // Site tracking URL to use after inline form submission. 1489 _load_script(trackcmp_url); 1490 } 1491 if (typeof window._form_callback !== 'undefined') window._form_callback(id); 1492}; 1493window._load_script = function(url, callback, isSubmit) { 1494 var head = document.querySelector('head'), script = document.createElement('script'), r = false;
1495 var submitButton = document.querySelector('#_form_14_submit'); 1496 script.charset = 'utf-8'; 1497 script.src = url; 1498 if (callback) { 1499 script.onload = script.onreadystatechange = function() { 1500 if (!r && (!this.readyState || this.readyState == 'complete')) { 1501 r = true; 1502 callback(); 1503 } 1504 }; 1505 } 1506 script.onerror = function() { 1507 if (isSubmit) { 1508 if (script.src.length > 10000) { 1509 _show_error("14", "Sorry, your submission failed. Please shorten your responses and try again."); 1510 } else { 1511 _show_error("14", "Sorry, your submission failed. Please try again."); 1512 } 1513 submitButton.disabled = false; 1514 submitButton.classList.remove('processing'); 1515 } 1516 } 1517 1518 head.appendChild(script); 1519}; 1520(function() { 1521 var iti; 1522 if (window.location.search.search("excludeform") !== -1) return false; 1523 var getCookie = function(name) { 1524 var match = document.cookie.match(new RegExp('(^|; )' + name + '=([^;]+)')); 1525 return match ? match[2] : localStorage.getItem(name); 1526 } 1527 var setCookie = function(name, value) { 1528 var now = new Date(); 1529 var time = now.getTime(); 1530 var expireTime = time + 1000 * 60 * 60 * 24 * 365; 1531 now.setTime(expireTime); 1532 document.cookie = name + '=' + value + '; expires=' + now + ';path=/; Secure; SameSite=Lax;'; 1533 localStorage.setItem(name, value); 1534 } 1535 var addEvent = function(element, event, func) { 1536 if (element.addEventListener) { 1537 element.addEventListener(event, func); 1538 } else { 1539 var oldFunc = element['on' + event]; 1540 element['on' + event] = function() { 1541 oldFunc.apply(this, arguments); 1542 func.apply(this, arguments); 1543 }; 1544 } 1545 } 1546 var _removed = false; 1547 var form_to_submit = document.getElementById('_form_14_'); 1548 var allInputs = form_to_submit.querySelectorAll('input, select, textarea'), tooltips = [], submitted = false; 1549 1550 var getUrlParam = function(name) { 1551 if (name.toLowerCase() !== 'email') { 1552 var params = new URLSearchParams(window.location.search); 1553 return params.get(name) || false; 1554 } 1555 // email is a special case because a plus is valid in the email address 1556 var qString = window.location.search; 1557 if (!qString) { 1558 return false; 1559 } 1560 var parameters = qString.substr(1).split('&'); 1561 for (var i = 0; i < parameters.length; i++) { 1562 var parameter = parameters[i].split('='); 1563 if (parameter[0].toLowerCase() === 'email') { 1564 return parameter[1] === undefined ? true : decodeURIComponent(parameter[1]); 1565 } 1566 } 1567 return false; 1568 }; 1569 1570 var acctDateFormat = "%B-%d-%Y"; 1571 var getNormalizedDate = function(date, acctFormat) { 1572 var decodedDate = decodeURIComponent(date); 1573 if (acctFormat && acctFormat.match(/(%d|%e).*%m/gi) !== null) { 1574 return decodedDate.replace(/(\d{2}).*(\d{2}).*(\d{4})/g, '$3-$2-$1'); 1575 } else if (Date.parse(decodedDate)) { 1576 var dateObj = new Date(decodedDate); 1577 var year = dateObj.getFullYear(); 1578 var month = dateObj.getMonth() + 1; 1579 var day = dateObj.getDate(); 1580 return `${year}-${month < 10 ? `0${month}` : month}-${day < 10 ? `0${day}` : day}`; 1581 } 1582 return false; 1583 }; 1584 1585 var getNormalizedTime = function(time) { 1586 var hour, minutes; 1587 var decodedTime = decodeURIComponent(time); 1588 var timeParts = Array.from(decodedTime.matchAll(/(\d{1,2}):(\d{1,2})\W*([AaPp][Mm])?/gm))[0]; 1589 if (timeParts[3]) { // 12 hour format 1590 var isPM = timeParts[3].toLowerCase() === 'pm'; 1591 if (isPM) { 1592 hour = parseInt(timeParts[1]) === 12 ? '12' : `${parseInt(timeParts[1]) + 12}`; 1593 } else { 1594 hour = parseInt(timeParts[1]) === 12 ? '0' : timeParts[1]; 1595 } 1596 } else { // 24 hour format 1597 hour = timeParts[1]; 1598 } 1599 var normalizedHour = parseInt(hour) < 10 ? `0${parseInt(hour)}` : hour; 1600 var minutes = timeParts[2]; 1601 return `${normalizedHour}:${minutes}`; 1602 }; 1603 1604 for (var i = 0; i < allInputs.length; i++) { 1605 var regexStr = "field\\[(\\d+)\\]"; 1606 var results = new RegExp(regexStr).exec(allInputs[i].name); 1607 if (results != undefined) { 1608 allInputs[i].dataset.name = allInputs[i].name.match(/\[time\]$/) 1609 ? `${window.cfields[results[1]]}_time` 1610 : window.cfields[results[1]]; 1611 } else { 1612 allInputs[i].dataset.name = allInputs[i].name; 1613 } 1614 var fieldVal = getUrlParam(allInputs[i].dataset.name); 1615 1616 if (fieldVal) {
1617 if (allInputs[i].dataset.autofill === "false") { 1618 continue; 1619 } 1620 if (allInputs[i].type == "radio" || allInputs[i].type == "checkbox") { 1621 if (allInputs[i].value == fieldVal) { 1622 allInputs[i].checked = true; 1623 } 1624 } else if (allInputs[i].type == "date") { 1625 allInputs[i].value = getNormalizedDate(fieldVal, acctDateFormat); 1626 } else if (allInputs[i].type == "time") { 1627 allInputs[i].value = getNormalizedTime(fieldVal); 1628 } else { 1629 allInputs[i].value = fieldVal; 1630 } 1631 } 1632 } 1633 1634 var remove_tooltips = function() { 1635 for (var i = 0; i < tooltips.length; i++) { 1636 tooltips[i].tip.parentNode.removeChild(tooltips[i].tip); 1637 } 1638 tooltips = []; 1639 }; 1640 var remove_tooltip = function(elem) { 1641 for (var i = 0; i < tooltips.length; i++) { 1642 if (tooltips[i].elem === elem) { 1643 tooltips[i].tip.parentNode.removeChild(tooltips[i].tip); 1644 tooltips.splice(i, 1); 1645 return; 1646 } 1647 } 1648 }; 1649 var create_tooltip = function(elem, text) { 1650 var tooltip = document.createElement('div'), 1651 arrow = document.createElement('div'), 1652 inner = document.createElement('div'), new_tooltip = {}; 1653 tooltip.id = `${elem.id}-error`; 1654 tooltip.setAttribute('role', 'alert') 1655 if (elem.type != 'radio' && (elem.type != 'checkbox' || elem.name === 'sms_consent')) { 1656 tooltip.className = '_error'; 1657 arrow.className = '_error-arrow'; 1658 inner.className = '_error-inner'; 1659 inner.innerHTML = text; 1660 tooltip.appendChild(arrow); 1661 tooltip.appendChild(inner); 1662 elem.parentNode.appendChild(tooltip); 1663 } else { 1664 tooltip.className = '_error-inner _no_arrow'; 1665 tooltip.innerHTML = text; 1666 elem.parentNode.insertBefore(tooltip, elem); 1667 new_tooltip.no_arrow = true; 1668 } 1669 new_tooltip.tip = tooltip; 1670 new_tooltip.elem = elem; 1671 tooltips.push(new_tooltip); 1672 return new_tooltip; 1673 }; 1674 var resize_tooltip = function(tooltip) { 1675 var rect = tooltip.elem.getBoundingClientRect(); 1676 var doc = document.documentElement, 1677 scrollPosition = rect.top - ((window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)); 1678 if (scrollPosition < 40) { 1679 tooltip.tip.className = tooltip.tip.className.replace(/ ?(_above|_below) ?/g, '') + ' _below'; 1680 } else { 1681 tooltip.tip.className = tooltip.tip.className.replace(/ ?(_above|_below) ?/g, '') + ' _above'; 1682 } 1683 }; 1684 var resize_tooltips = function() { 1685 if (_removed) return; 1686 for (var i = 0; i < tooltips.length; i++) { 1687 if (!tooltips[i].no_arrow) resize_tooltip(tooltips[i]); 1688 } 1689 }; 1690 var validate_field = function(elem, remove) { 1691 var tooltip = null, value = elem.value, no_error = true; 1692 remove ? remove_tooltip(elem) : false; 1693 elem.removeAttribute('aria-invalid'); 1694 elem.removeAttribute('aria-describedby'); 1695 if (elem.type != 'checkbox') elem.className = elem.className.replace(/ ?_has_error ?/g, ''); 1696 if (elem.getAttribute('required') !== null) { 1697 if (elem.type == 'radio' || (elem.type == 'checkbox' && /any/.test(elem.className))) { 1698 var elems = form_to_submit.elements[elem.name]; 1699 if (!(elems instanceof NodeList || elems instanceof HTMLCollection) || elems.length <= 1) { 1700 no_error = elem.checked; 1701 } 1702 else { 1703 no_error = false; 1704 for (var i = 0; i < elems.length; i++) { 1705 if (elems[i].checked) no_error = true; 1706 } 1707 } 1708 if (!no_error) { 1709 tooltip = create_tooltip(elem, "Please select an option."); 1710 } 1711 } else if (elem.type =='checkbox') { 1712 var elems = form_to_submit.elements[elem.name], found = false, err = []; 1713 no_error = true; 1714 for (var i = 0; i < elems.length; i++) { 1715 if (elems[i].getAttribute('required') === null) continue; 1716 if (!found && elems[i] !== elem) return true; 1717 found = true; 1718 elems[i].className = elems[i].className.replace(/ ?_has_error ?/g, ''); 1719 if (!elems[i].checked) { 1720 no_error = false;
1721 elems[i].className = elems[i].className + ' _has_error'; 1722 err.push("Checking %s is required".replace("%s", elems[i].value)); 1723 } 1724 } 1725 if (!no_error) { 1726 tooltip = create_tooltip(elem, err.join('<br/>')); 1727 } 1728 } else if (elem.tagName == 'SELECT') { 1729 var selected = true; 1730 if (elem.multiple) { 1731 selected = false; 1732 for (var i = 0; i < elem.options.length; i++) { 1733 if (elem.options[i].selected) { 1734 selected = true; 1735 break; 1736 } 1737 } 1738 } else { 1739 for (var i = 0; i < elem.options.length; i++) { 1740 if (elem.options[i].selected 1741 && (!elem.options[i].value 1742 || (elem.options[i].value.match(/\n/g))) 1743 ) { 1744 selected = false; 1745 } 1746 } 1747 } 1748 if (!selected) { 1749 elem.className = elem.className + ' _has_error'; 1750 no_error = false; 1751 tooltip = create_tooltip(elem, "Please select an option."); 1752 } 1753 } else if (value === undefined || value === null || value === '') { 1754 elem.className = elem.className + ' _has_error'; 1755 no_error = false; 1756 tooltip = create_tooltip(elem, "This field is required."); 1757 } 1758 } 1759 if (no_error && elem.name == 'email') { 1760 if (!value.match(/^[\+_a-z0-9-'&=]+(\.[\+_a-z0-9-']+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/i)) { 1761 elem.className = elem.className + ' _has_error'; 1762 no_error = false; 1763 tooltip = create_tooltip(elem, "Enter a valid email address."); 1764 } 1765 } 1766 if (no_error && (elem.id == 'phone')) { 1767 if (elem.value.trim() && typeof iti != 'undefined' && !iti.isValidNumber()) { 1768 elem.className = elem.className + ' _has_error'; 1769 no_error = false; 1770 tooltip = create_tooltip(elem, "Enter a valid phone number."); 1771 } 1772 } 1773 if (no_error && /date_field/.test(elem.className)) { 1774 if (!value.match(/^\d\d\d\d-\d\d-\d\d$/)) { 1775 elem.className = elem.className + ' _has_error'; 1776 no_error = false; 1777 tooltip = create_tooltip(elem, "Enter a valid date."); 1778 } 1779 } 1780 1781 if (no_error && elem.name === 'sms_consent') { 1782 const showError = !!elem.attributes.required && !elem.checked; 1783 if (showError) { 1784 elem.className = elem.className + ' _has_error'; 1785 no_error = false; 1786 tooltip = create_tooltip(elem, "Please check this box to continue"); 1787 } else { 1788 elem.className = elem.className.replace(/ ?_has_error ?/g, ''); 1789 } 1790 } 1791 tooltip ? resize_tooltip(tooltip) : false; 1792 if (!no_error && elem.hasAttribute('id')) { 1793 elem.setAttribute('aria-invalid', 'true'); 1794 elem.setAttribute('aria-describedby', `${elem.id}-error`); 1795 } 1796 return no_error; 1797 }; 1798 var needs_validate = function(el) { 1799 if(el.getAttribute('required') !== null){ 1800 return true; 1801 } 1802 if((el.name === 'email' || el.name === 'phone' || el.id === 'sms_consent') && el.value !== ""){ 1803 return true; 1804 } 1805 1806 return false; 1807 }; 1808 var validate_email_or_phone_required = function() { 1809 var emailInput = form_to_submit.querySelector('input[name="email"]'); 1810 var phoneInput = form_to_submit.querySelector('input[name="phone"]'); 1811 if (!emailInput && !phoneInput) { 1812 return true; 1813 } 1814 var hasEmailValue = emailInput && emailInput.value.trim() !== '';
1815 var hasPhoneValue = phoneInput && phoneInput.value.trim() !== ''; 1816 if (hasEmailValue || hasPhoneValue) { 1817 return true; 1818 } 1819 var errorField = emailInput || phoneInput; 1820 errorField.className = errorField.className.replace(/ ?_has_error ?/g, '') + ' _has_error'; 1821 var tooltip = create_tooltip( 1822 errorField, 1823 "Forms must have an email field or a phone field present" 1824 ); 1825 resize_tooltip(tooltip); 1826 errorField.setAttribute('aria-invalid', 'true'); 1827 if (errorField.hasAttribute('id')) { 1828 errorField.setAttribute('aria-describedby', errorField.id + '-error'); 1829 } 1830 return false; 1831 }; 1832 var validate_form = function(e) { 1833 var err = form_to_submit.querySelector('._form_error'), no_error = true; 1834 if (!submitted) { 1835 submitted = true; 1836 for (var i = 0, len = allInputs.length; i < len; i++) { 1837 var input = allInputs[i]; 1838 if (needs_validate(input)) { 1839 if (input.type == 'text' || input.type == 'number' || input.type == 'time' || input.type == 'tel') { 1840 addEvent(input, 'blur', function() { 1841 this.value = this.value.trim(); 1842 validate_field(this, true); 1843 }); 1844 addEvent(input, 'input', function() { 1845 validate_field(this, true); 1846 }); 1847 } else if (input.type == 'radio' || input.type == 'checkbox') { 1848 (function(el) { 1849 function getElementsArray(name){ 1850 const value = form_to_submit.elements[name]; 1851 if (Array.isArray(value)){ 1852 return value; 1853 } 1854 return [value]; 1855 } 1856 var radios = getElementsArray(el.name); 1857 for (var i = 0; i < radios.length; i++) { 1858 addEvent(radios[i], 'change', function() { 1859 validate_field(el, true); 1860 }); 1861 } 1862 })(input); 1863 } else if (input.tagName == 'SELECT') { 1864 addEvent(input, 'change', function() { 1865 validate_field(this, true); 1866 }); 1867 } else if (input.type == 'textarea'){ 1868 addEvent(input, 'input', function() { 1869 validate_field(this, true); 1870 }); 1871 } 1872 } 1873 } 1874 } 1875 remove_tooltips(); 1876 for (var i = 0, len = allInputs.length; i < len; i++) { 1877 var elem = allInputs[i]; 1878 if (needs_validate(elem)) { 1879 if (elem.tagName.toLowerCase() !== "select") { 1880 elem.value = elem.value.trim(); 1881 } 1882 validate_field(elem) ? true : no_error = false; 1883 } 1884 } 1885 if (!validate_email_or_phone_required()) { 1886 no_error = false; 1887 } 1888 if (!no_error && e) { 1889 e.preventDefault(); 1890 } 1891 if (!no_error) { 1892 const firstFocusableError = form_to_submit.querySelector('._has_error:not([disabled])'); 1893 if (firstFocusableError && typeof firstFocusableError.focus === 'function') { 1894 firstFocusableError.focus(); 1895 } 1896 } 1897 resize_tooltips(); 1898 return no_error; 1899 }; 1900 addEvent(window, 'resize', resize_tooltips); 1901 addEvent(window, 'scroll', resize_tooltips); 1902 var initializePhoneInput = function(inputPhone) { 1903 1904 const stylesheetLink = document.createElement('link'); 1905 stylesheetLink.rel = 'stylesheet'; 1906 stylesheetLink.href = 'https://cdn.jsdelivr.net/npm/[email protected]/build/css/intlTelInput.css'; 1907 document.head.appendChild(stylesheetLink); 1908 1909 window._load_script('https://cdn.jsdelivr.net/npm/[email protected]/build/js/intlTelInput.min.js', function() { 1910 inputPhone.setAttribute("name", "phone-iti"); 1911 iti = intlTelInput(inputPhone, { 1912 loadUtils: () => import('https://cdn.jsdelivr.net/npm/[email protected]/build/js/utils.js'), 1913 hiddenInput: (telInputName) => ({ 1914 phone: 'phone' 1915 }), 1916 separateDialCode: true, 1917 autoPlaceholder: 'aggressive', 1918 initialCountry: "us", 1919 }); 1920 }, false); 1921 } 1922 var inputPhone = form_to_submit.querySelector('input[name="phone"]'); 1923 if(inputPhone) { 1924 initializePhoneInput(inputPhone); 1925 } 1926 1927 var _form_serialize = function(form){if(!form||form.nodeName!=="FORM"){return }var i,j,q=[];for(i=0;i<form.elements.length;i++){if(form.elements[i].name===""){continue}switch(form.elements[i].nodeName){case"INPUT":switch(form.elements[i].type){case"tel":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].previousSibling.querySelector('div.iti__selected-dial-code').innerText)+encodeURIComponent(" ")+encodeURIComponent(form.elements[i].value));break;case"text":case"number":case"date":case"time":case"hidden":case"password":case"button":case"reset":case"submit":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break;case"checkbox":case"radio":if(form.elements[i].checked){q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value))}break;case"file":break}break;case"TEXTAREA":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break;case"SELECT":switch(form.elements[i].type){case"select-one":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break;case"select-multiple":for(j=0;j<form.elements[i].options.length;j++){if(form.elements[i].options[j].selected){q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].options[j].value))}}break}break;case"BUTTON":switch(form.elements[i].type){case"reset":case"submit":case"button":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break}break}}return q.join("&")}; 1928 1929 const formSupportsPost = false;
1930 var form_submit = function(e) { 1931 1932 e.preventDefault(); 1933 if(form_to_submit.querySelector('input[name="phone"]') && typeof iti != 'undefined') { 1934 form_to_submit.querySelector('input[name="phone"]').value = iti.getNumber(); 1935 } 1936 if (validate_form()) { 1937 // use this trick to get the submit button & disable it using plain javascript 1938 var submitButton = e.target.querySelector('#_form_14_submit'); 1939 submitButton.disabled = true; 1940 submitButton.classList.add('processing'); 1941 var serialized = _form_serialize(document.getElementById('_form_14_')).replace(/%0A/g, '\\n'); 1942 var err = form_to_submit.querySelector('._form_error'); 1943 err ? err.parentNode.removeChild(err) : false; 1944 async function submitForm() { 1945 var formData = new FormData(); 1946 const searchParams = new URLSearchParams(serialized); 1947 searchParams.forEach((value, key) => { 1948 if (key !== 'hideButton') { 1949 formData.append(key, value); 1950 } 1951 }); 1952 let request = { 1953 headers: { 1954 "Accept": "application/json" 1955 }, 1956 body: formData, 1957 method: "POST" 1958 }; 1959 1960 let pageUrlParams = new URLSearchParams(window.location.search); 1961 if (pageUrlParams.has('t')) { 1962 request.headers.Authorization = 'Bearer ' + pageUrlParams.get('t'); 1963 } 1964 const response = await fetch('https://flyingshapes.activehosted.com/proc.php?jsonp=true', request); 1965 1966 return response.json(); 1967 } 1968 if (formSupportsPost) { 1969 submitForm().then((data) => { 1970 eval(data.js); 1971 }).catch(() => { 1972 _show_error("14", "Sorry, your submission failed. Please try again."); 1973 }); 1974 } else { 1975 _load_script('https://flyingshapes.activehosted.com/proc.php?' + serialized + '&jsonp=true', null, true); 1976 } 1977 } 1978 return false; 1979 }; 1980 addEvent(form_to_submit, 'submit', form_submit); 1981})(); 1982 1983</script>
1983 </div> 1984 <p class="fs-lightbox__legal">Our <a href="https://www.flyingshapes.com/privacy/">Privacy Policy</a> applies.</p> 1985 </div> 1986 </div> 1987 </dialog> 1988 <dialog class="fs-lightbox" id="fs-lightbox-trial" data-lightbox-panel="trial" aria-labelledby="fs-lightbox-title-trial"> 1989 <div class="fs-lightbox__panel"> 1990 <button type="button" class="fs-lightbox__close" data-lightbox-close aria-label="Close"> 1991 <span aria-hidden="true">×</span> 1992 </button> 1993 <div class="fs-lightbox__body"> 1994 <h2 id="fs-lightbox-title-trial" class="fs-lightbox__title">Request Trial Version</h2> 1995 <p class="fs-lightbox__desc">Take full advantage of our free trial and discover a completely new way of turning your design ideas into 3D models.</p> 1996 <div class="fs-lightbox__form" data-ac-form="trial" data-fs-form-slot="trial"> 1997 <form method="POST" action="https://flyingshapes.activehosted.com/proc.php" id="_form_28_" class="_form _form_28 _inline-form _dark" novalidate data-styles-version="5"> 1998 <input type="hidden" name="u" value="28" /> 1999 <input type="hidden" name="f" value="28" /> 2000 <input type="hidden" name="s" /> 2001 <input type="hidden" name="c" value="0" /> 2002 <input type="hidden" name="m" value="0" /> 2003 <input type="hidden" name="act" value="sub" /> 2004 <input type="hidden" name="v" value="2" /> 2005 <input type="hidden" name="or" value="bf58d73a-8ed6-4c48-a28b-f0ddb818b734" /> 2006 <div class="_form-content"> 2007 <div class="_form_element _x98082402 _full_width " > 2008 <label for="fullname" class="_form-label"> 2009 </label> 2010 <div class="_field-wrapper"> 2011 <input type="text" id="fullname" name="fullname" placeholder="How may we call you?" required/> 2012 </div> 2013 </div> 2014 <div class="_form_element _x05723213 _full_width " > 2015 <label for="email" class="_form-label"> 2016 </label> 2017 <div class="_field-wrapper"> 2018 <input type="text" id="email" name="email" placeholder="" required/> 2019 </div> 2020 </div> 2021 <div class="_form_element _x75804092 _full_width " > 2022 <label for="phone" class="_form-label"> 2023 </label> 2024 <div class="_field-wrapper"> 2025 <input type="text" id="phone" name="phone" placeholder="Type your phone number" /> 2026 </div> 2027 </div> 2028 <div class="_form_element _x81693921 _full_width " > 2029 <fieldset class="_form-fieldset"> 2030 <div class="_row"> 2031 <legend for="field[34][]" class="_form-label"> 2032 </legend> 2033 </div> 2034 <input data-autofill="false" type="hidden" id="field[34][]" name="field[34][]" value="~|"> 2035 <div class="_row _checkbox-radio"> 2036 <input id="field_34Subscribe to our Newsletter" type="checkbox" name="field[34][]" 2037 value="Subscribe to our Newsletter" > 2038 <span> 2039 <label for="field_34Subscribe to our Newsletter"> 2040 Subscribe to our Newsletter 2041 </label> 2042 </span> 2043 </div> 2044 </fieldset> 2045 </div> 2046 <div class="_button-wrapper _full_width"> 2047 <button id="_form_28_submit" class="_submit" type="submit"> 2048 send 2049 </button> 2050 </div> 2051 <div class="_clear-element"> 2052 </div> 2053 </div> 2054 <div class="_form-thank-you" style="display:none;"> 2055 </div> 2056</form>
2056<script> 2057window.cfields = {"34":"requestnewsletter"}; 2058window._show_thank_you = function(id, message, trackcmp_url, email) { 2059 var form = document.getElementById('_form_' + id + '_'), thank_you = form.querySelector('._form-thank-you'); 2060 form.querySelector('._form-content').style.display = 'none'; 2061 thank_you.innerHTML = message; 2062 thank_you.style.display = 'block'; 2063 const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias; 2064 var visitorObject = window[vgoAlias]; 2065 if (email && typeof visitorObject !== 'undefined') { 2066 visitorObject('setEmail', email); 2067 visitorObject('update'); 2068 } else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) { 2069 // Site tracking URL to use after inline form submission. 2070 _load_script(trackcmp_url); 2071 } 2072 if (typeof window._form_callback !== 'undefined') window._form_callback(id); 2073 thank_you.setAttribute('tabindex', '-1'); 2074 thank_you.focus(); 2075}; 2076window._show_unsubscribe = function(id, message, trackcmp_url, email) { 2077 var form = document.getElementById('_form_' + id + '_'), unsub = form.querySelector('._form-thank-you'); 2078 var branding = form.querySelector('._form-branding'); 2079 if (branding) { 2080 branding.style.display = 'none'; 2081 } 2082 form.querySelector('._form-content').style.display = 'none'; 2083 unsub.style.display = 'block'; 2084 form.insertAdjacentHTML('afterend', message) 2085 const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias; 2086 var visitorObject = window[vgoAlias]; 2087 if (email && typeof visitorObject !== 'undefined') { 2088 visitorObject('setEmail', email); 2089 visitorObject('update'); 2090 } else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) { 2091 // Site tracking URL to use after inline form submission. 2092 _load_script(trackcmp_url); 2093 } 2094 if (typeof window._form_callback !== 'undefined') window._form_callback(id); 2095}; 2096window._show_error = function(id, message, html) { 2097 var form = document.getElementById('_form_' + id + '_'), 2098 err = document.createElement('div'), 2099 button = form.querySelector('button[type="submit"]'), 2100 old_error = form.querySelector('._form_error'); 2101 if (old_error) old_error.parentNode.removeChild(old_error); 2102 err.innerHTML = message; 2103 err.className = '_error-inner _form_error _no_arrow'; 2104 var wrapper = document.createElement('div'); 2105 wrapper.className = '_form-inner _show_be_error'; 2106 wrapper.appendChild(err); 2107 button.parentNode.insertBefore(wrapper, button); 2108 var submitButton = form.querySelector('[id^="_form"][id$="_submit"]'); 2109 submitButton.disabled = false; 2110 submitButton.classList.remove('processing'); 2111 if (html) { 2112 var div = document.createElement('div'); 2113 div.className = '_error-html'; 2114 div.innerHTML = html; 2115 err.appendChild(div); 2116 } 2117}; 2118window._show_pc_confirmation = function(id, header, detail, show, email) { 2119 var form = document.getElementById('_form_' + id + '_'), pc_confirmation = form.querySelector('._form-pc-confirmation'); 2120 if (pc_confirmation.style.display === 'none') { 2121 form.querySelector('._form-content').style.display = 'none'; 2122 pc_confirmation.innerHTML = "<div class='_form-title'>" + header + "</div>" + "<p>" + detail + "</p>" + 2123 "<button class='_submit' id='hideButton'>Manage preferences</button>"; 2124 pc_confirmation.style.display = 'block'; 2125 var mp = document.querySelector('input[name="mp"]'); 2126 mp.value = '0'; 2127 } else { 2128 form.querySelector('._form-content').style.display = 'inline'; 2129 pc_confirmation.style.display = 'none'; 2130 } 2131 2132 var hideButton = document.getElementById('hideButton'); 2133 // Add event listener to the button 2134 hideButton.addEventListener('click', function() { 2135 var submitButton = document.querySelector('#_form_28_submit'); 2136 submitButton.disabled = false; 2137 submitButton.classList.remove('processing'); 2138 var mp = document.querySelector('input[name="mp"]'); 2139 mp.value = '1'; 2140 const cacheBuster = new URL(window.location.href); 2141 cacheBuster.searchParams.set('v', new Date().getTime()); 2142 window.location.href = cacheBuster.toString(); 2143 }); 2144 2145 const vgoAlias = typeof visitorGlobalObjectAlias === 'undefined' ? 'vgo' : visitorGlobalObjectAlias; 2146 var visitorObject = window[vgoAlias]; 2147 if (email && typeof visitorObject !== 'undefined') { 2148 visitorObject('setEmail', email); 2149 visitorObject('update'); 2150 } else if (typeof(trackcmp_url) != 'undefined' && trackcmp_url) { 2151 // Site tracking URL to use after inline form submission. 2152 _load_script(trackcmp_url); 2153 } 2154 if (typeof window._form_callback !== 'undefined') window._form_callback(id); 2155}; 2156window._load_script = function(url, callback, isSubmit) { 2157 var head = document.querySelector('head'), script = document.createElement('script'), r = false;
2158 var submitButton = document.querySelector('#_form_28_submit'); 2159 script.charset = 'utf-8'; 2160 script.src = url; 2161 if (callback) { 2162 script.onload = script.onreadystatechange = function() { 2163 if (!r && (!this.readyState || this.readyState == 'complete')) { 2164 r = true; 2165 callback(); 2166 } 2167 }; 2168 } 2169 script.onerror = function() { 2170 if (isSubmit) { 2171 if (script.src.length > 10000) { 2172 _show_error("28", "Sorry, your submission failed. Please shorten your responses and try again."); 2173 } else { 2174 _show_error("28", "Sorry, your submission failed. Please try again."); 2175 } 2176 submitButton.disabled = false; 2177 submitButton.classList.remove('processing'); 2178 } 2179 } 2180 2181 head.appendChild(script); 2182}; 2183(function() { 2184 var iti; 2185 if (window.location.search.search("excludeform") !== -1) return false; 2186 var getCookie = function(name) { 2187 var match = document.cookie.match(new RegExp('(^|; )' + name + '=([^;]+)')); 2188 return match ? match[2] : localStorage.getItem(name); 2189 } 2190 var setCookie = function(name, value) { 2191 var now = new Date(); 2192 var time = now.getTime(); 2193 var expireTime = time + 1000 * 60 * 60 * 24 * 365; 2194 now.setTime(expireTime); 2195 document.cookie = name + '=' + value + '; expires=' + now + ';path=/; Secure; SameSite=Lax;'; 2196 localStorage.setItem(name, value); 2197 } 2198 var addEvent = function(element, event, func) { 2199 if (element.addEventListener) { 2200 element.addEventListener(event, func); 2201 } else { 2202 var oldFunc = element['on' + event]; 2203 element['on' + event] = function() { 2204 oldFunc.apply(this, arguments); 2205 func.apply(this, arguments); 2206 }; 2207 } 2208 } 2209 var _removed = false; 2210 var form_to_submit = document.getElementById('_form_28_'); 2211 var allInputs = form_to_submit.querySelectorAll('input, select, textarea'), tooltips = [], submitted = false; 2212 2213 var getUrlParam = function(name) { 2214 if (name.toLowerCase() !== 'email') { 2215 var params = new URLSearchParams(window.location.search); 2216 return params.get(name) || false; 2217 } 2218 // email is a special case because a plus is valid in the email address 2219 var qString = window.location.search; 2220 if (!qString) { 2221 return false; 2222 } 2223 var parameters = qString.substr(1).split('&'); 2224 for (var i = 0; i < parameters.length; i++) { 2225 var parameter = parameters[i].split('='); 2226 if (parameter[0].toLowerCase() === 'email') { 2227 return parameter[1] === undefined ? true : decodeURIComponent(parameter[1]); 2228 } 2229 } 2230 return false; 2231 }; 2232 2233 var acctDateFormat = "%B-%d-%Y"; 2234 var getNormalizedDate = function(date, acctFormat) { 2235 var decodedDate = decodeURIComponent(date); 2236 if (acctFormat && acctFormat.match(/(%d|%e).*%m/gi) !== null) { 2237 return decodedDate.replace(/(\d{2}).*(\d{2}).*(\d{4})/g, '$3-$2-$1'); 2238 } else if (Date.parse(decodedDate)) { 2239 var dateObj = new Date(decodedDate); 2240 var year = dateObj.getFullYear(); 2241 var month = dateObj.getMonth() + 1; 2242 var day = dateObj.getDate(); 2243 return `${year}-${month < 10 ? `0${month}` : month}-${day < 10 ? `0${day}` : day}`; 2244 } 2245 return false; 2246 }; 2247 2248 var getNormalizedTime = function(time) { 2249 var hour, minutes; 2250 var decodedTime = decodeURIComponent(time); 2251 var timeParts = Array.from(decodedTime.matchAll(/(\d{1,2}):(\d{1,2})\W*([AaPp][Mm])?/gm))[0]; 2252 if (timeParts[3]) { // 12 hour format 2253 var isPM = timeParts[3].toLowerCase() === 'pm'; 2254 if (isPM) { 2255 hour = parseInt(timeParts[1]) === 12 ? '12' : `${parseInt(timeParts[1]) + 12}`; 2256 } else { 2257 hour = parseInt(timeParts[1]) === 12 ? '0' : timeParts[1]; 2258 } 2259 } else { // 24 hour format 2260 hour = timeParts[1]; 2261 } 2262 var normalizedHour = parseInt(hour) < 10 ? `0${parseInt(hour)}` : hour; 2263 var minutes = timeParts[2]; 2264 return `${normalizedHour}:${minutes}`; 2265 }; 2266 2267 for (var i = 0; i < allInputs.length; i++) { 2268 var regexStr = "field\\[(\\d+)\\]"; 2269 var results = new RegExp(regexStr).exec(allInputs[i].name); 2270 if (results != undefined) { 2271 allInputs[i].dataset.name = allInputs[i].name.match(/\[time\]$/) 2272 ? `${window.cfields[results[1]]}_time` 2273 : window.cfields[results[1]]; 2274 } else { 2275 allInputs[i].dataset.name = allInputs[i].name; 2276 } 2277 var fieldVal = getUrlParam(allInputs[i].dataset.name); 2278 2279 if (fieldVal) {
2280 if (allInputs[i].dataset.autofill === "false") { 2281 continue; 2282 } 2283 if (allInputs[i].type == "radio" || allInputs[i].type == "checkbox") { 2284 if (allInputs[i].value == fieldVal) { 2285 allInputs[i].checked = true; 2286 } 2287 } else if (allInputs[i].type == "date") { 2288 allInputs[i].value = getNormalizedDate(fieldVal, acctDateFormat); 2289 } else if (allInputs[i].type == "time") { 2290 allInputs[i].value = getNormalizedTime(fieldVal); 2291 } else { 2292 allInputs[i].value = fieldVal; 2293 } 2294 } 2295 } 2296 2297 var remove_tooltips = function() { 2298 for (var i = 0; i < tooltips.length; i++) { 2299 tooltips[i].tip.parentNode.removeChild(tooltips[i].tip); 2300 } 2301 tooltips = []; 2302 }; 2303 var remove_tooltip = function(elem) { 2304 for (var i = 0; i < tooltips.length; i++) { 2305 if (tooltips[i].elem === elem) { 2306 tooltips[i].tip.parentNode.removeChild(tooltips[i].tip); 2307 tooltips.splice(i, 1); 2308 return; 2309 } 2310 } 2311 }; 2312 var create_tooltip = function(elem, text) { 2313 var tooltip = document.createElement('div'), 2314 arrow = document.createElement('div'), 2315 inner = document.createElement('div'), new_tooltip = {}; 2316 tooltip.id = `${elem.id}-error`; 2317 tooltip.setAttribute('role', 'alert') 2318 if (elem.type != 'radio' && (elem.type != 'checkbox' || elem.name === 'sms_consent')) { 2319 tooltip.className = '_error'; 2320 arrow.className = '_error-arrow'; 2321 inner.className = '_error-inner'; 2322 inner.innerHTML = text; 2323 tooltip.appendChild(arrow); 2324 tooltip.appendChild(inner); 2325 elem.parentNode.appendChild(tooltip); 2326 } else { 2327 tooltip.className = '_error-inner _no_arrow'; 2328 tooltip.innerHTML = text; 2329 elem.parentNode.insertBefore(tooltip, elem); 2330 new_tooltip.no_arrow = true; 2331 } 2332 new_tooltip.tip = tooltip; 2333 new_tooltip.elem = elem; 2334 tooltips.push(new_tooltip); 2335 return new_tooltip; 2336 }; 2337 var resize_tooltip = function(tooltip) { 2338 var rect = tooltip.elem.getBoundingClientRect(); 2339 var doc = document.documentElement, 2340 scrollPosition = rect.top - ((window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)); 2341 if (scrollPosition < 40) { 2342 tooltip.tip.className = tooltip.tip.className.replace(/ ?(_above|_below) ?/g, '') + ' _below'; 2343 } else { 2344 tooltip.tip.className = tooltip.tip.className.replace(/ ?(_above|_below) ?/g, '') + ' _above'; 2345 } 2346 }; 2347 var resize_tooltips = function() { 2348 if (_removed) return; 2349 for (var i = 0; i < tooltips.length; i++) { 2350 if (!tooltips[i].no_arrow) resize_tooltip(tooltips[i]); 2351 } 2352 }; 2353 var validate_field = function(elem, remove) { 2354 var tooltip = null, value = elem.value, no_error = true; 2355 remove ? remove_tooltip(elem) : false; 2356 elem.removeAttribute('aria-invalid'); 2357 elem.removeAttribute('aria-describedby'); 2358 if (elem.type != 'checkbox') elem.className = elem.className.replace(/ ?_has_error ?/g, ''); 2359 if (elem.getAttribute('required') !== null) { 2360 if (elem.type == 'radio' || (elem.type == 'checkbox' && /any/.test(elem.className))) { 2361 var elems = form_to_submit.elements[elem.name]; 2362 if (!(elems instanceof NodeList || elems instanceof HTMLCollection) || elems.length <= 1) { 2363 no_error = elem.checked; 2364 } 2365 else { 2366 no_error = false; 2367 for (var i = 0; i < elems.length; i++) { 2368 if (elems[i].checked) no_error = true; 2369 } 2370 } 2371 if (!no_error) { 2372 tooltip = create_tooltip(elem, "Please select an option."); 2373 } 2374 } else if (elem.type =='checkbox') { 2375 var elems = form_to_submit.elements[elem.name], found = false, err = []; 2376 no_error = true; 2377 for (var i = 0; i < elems.length; i++) { 2378 if (elems[i].getAttribute('required') === null) continue; 2379 if (!found && elems[i] !== elem) return true; 2380 found = true; 2381 elems[i].className = elems[i].className.replace(/ ?_has_error ?/g, ''); 2382 if (!elems[i].checked) { 2383 no_error = false;
2384 elems[i].className = elems[i].className + ' _has_error'; 2385 err.push("Checking %s is required".replace("%s", elems[i].value)); 2386 } 2387 } 2388 if (!no_error) { 2389 tooltip = create_tooltip(elem, err.join('<br/>')); 2390 } 2391 } else if (elem.tagName == 'SELECT') { 2392 var selected = true; 2393 if (elem.multiple) { 2394 selected = false; 2395 for (var i = 0; i < elem.options.length; i++) { 2396 if (elem.options[i].selected) { 2397 selected = true; 2398 break; 2399 } 2400 } 2401 } else { 2402 for (var i = 0; i < elem.options.length; i++) { 2403 if (elem.options[i].selected 2404 && (!elem.options[i].value 2405 || (elem.options[i].value.match(/\n/g))) 2406 ) { 2407 selected = false; 2408 } 2409 } 2410 } 2411 if (!selected) { 2412 elem.className = elem.className + ' _has_error'; 2413 no_error = false; 2414 tooltip = create_tooltip(elem, "Please select an option."); 2415 } 2416 } else if (value === undefined || value === null || value === '') { 2417 elem.className = elem.className + ' _has_error'; 2418 no_error = false; 2419 tooltip = create_tooltip(elem, "This field is required."); 2420 } 2421 } 2422 if (no_error && elem.name == 'email') { 2423 if (!value.match(/^[\+_a-z0-9-'&=]+(\.[\+_a-z0-9-']+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/i)) { 2424 elem.className = elem.className + ' _has_error'; 2425 no_error = false; 2426 tooltip = create_tooltip(elem, "Enter a valid email address."); 2427 } 2428 } 2429 if (no_error && (elem.id == 'phone')) { 2430 if (elem.value.trim() && typeof iti != 'undefined' && !iti.isValidNumber()) { 2431 elem.className = elem.className + ' _has_error'; 2432 no_error = false; 2433 tooltip = create_tooltip(elem, "Enter a valid phone number."); 2434 } 2435 } 2436 if (no_error && /date_field/.test(elem.className)) { 2437 if (!value.match(/^\d\d\d\d-\d\d-\d\d$/)) { 2438 elem.className = elem.className + ' _has_error'; 2439 no_error = false; 2440 tooltip = create_tooltip(elem, "Enter a valid date."); 2441 } 2442 } 2443 2444 if (no_error && elem.name === 'sms_consent') { 2445 const showError = !!elem.attributes.required && !elem.checked; 2446 if (showError) { 2447 elem.className = elem.className + ' _has_error'; 2448 no_error = false; 2449 tooltip = create_tooltip(elem, "Please check this box to continue"); 2450 } else { 2451 elem.className = elem.className.replace(/ ?_has_error ?/g, ''); 2452 } 2453 } 2454 tooltip ? resize_tooltip(tooltip) : false; 2455 if (!no_error && elem.hasAttribute('id')) { 2456 elem.setAttribute('aria-invalid', 'true'); 2457 elem.setAttribute('aria-describedby', `${elem.id}-error`); 2458 } 2459 return no_error; 2460 }; 2461 var needs_validate = function(el) { 2462 if(el.getAttribute('required') !== null){ 2463 return true; 2464 } 2465 if((el.name === 'email' || el.name === 'phone' || el.id === 'sms_consent') && el.value !== ""){ 2466 return true; 2467 } 2468 2469 return false; 2470 }; 2471 var validate_email_or_phone_required = function() { 2472 var emailInput = form_to_submit.querySelector('input[name="email"]'); 2473 var phoneInput = form_to_submit.querySelector('input[name="phone"]'); 2474 if (!emailInput && !phoneInput) { 2475 return true; 2476 } 2477 var hasEmailValue = emailInput && emailInput.value.trim() !== '';
2478 var hasPhoneValue = phoneInput && phoneInput.value.trim() !== ''; 2479 if (hasEmailValue || hasPhoneValue) { 2480 return true; 2481 } 2482 var errorField = emailInput || phoneInput; 2483 errorField.className = errorField.className.replace(/ ?_has_error ?/g, '') + ' _has_error'; 2484 var tooltip = create_tooltip( 2485 errorField, 2486 "Forms must have an email field or a phone field present" 2487 ); 2488 resize_tooltip(tooltip); 2489 errorField.setAttribute('aria-invalid', 'true'); 2490 if (errorField.hasAttribute('id')) { 2491 errorField.setAttribute('aria-describedby', errorField.id + '-error'); 2492 } 2493 return false; 2494 }; 2495 var validate_form = function(e) { 2496 var err = form_to_submit.querySelector('._form_error'), no_error = true; 2497 if (!submitted) { 2498 submitted = true; 2499 for (var i = 0, len = allInputs.length; i < len; i++) { 2500 var input = allInputs[i]; 2501 if (needs_validate(input)) { 2502 if (input.type == 'text' || input.type == 'number' || input.type == 'time' || input.type == 'tel') { 2503 addEvent(input, 'blur', function() { 2504 this.value = this.value.trim(); 2505 validate_field(this, true); 2506 }); 2507 addEvent(input, 'input', function() { 2508 validate_field(this, true); 2509 }); 2510 } else if (input.type == 'radio' || input.type == 'checkbox') { 2511 (function(el) { 2512 function getElementsArray(name){ 2513 const value = form_to_submit.elements[name]; 2514 if (Array.isArray(value)){ 2515 return value; 2516 } 2517 return [value]; 2518 } 2519 var radios = getElementsArray(el.name); 2520 for (var i = 0; i < radios.length; i++) { 2521 addEvent(radios[i], 'change', function() { 2522 validate_field(el, true); 2523 }); 2524 } 2525 })(input); 2526 } else if (input.tagName == 'SELECT') { 2527 addEvent(input, 'change', function() { 2528 validate_field(this, true); 2529 }); 2530 } else if (input.type == 'textarea'){ 2531 addEvent(input, 'input', function() { 2532 validate_field(this, true); 2533 }); 2534 } 2535 } 2536 } 2537 } 2538 remove_tooltips(); 2539 for (var i = 0, len = allInputs.length; i < len; i++) { 2540 var elem = allInputs[i]; 2541 if (needs_validate(elem)) { 2542 if (elem.tagName.toLowerCase() !== "select") { 2543 elem.value = elem.value.trim(); 2544 } 2545 validate_field(elem) ? true : no_error = false; 2546 } 2547 } 2548 if (!validate_email_or_phone_required()) { 2549 no_error = false; 2550 } 2551 if (!no_error && e) { 2552 e.preventDefault(); 2553 } 2554 if (!no_error) { 2555 const firstFocusableError = form_to_submit.querySelector('._has_error:not([disabled])'); 2556 if (firstFocusableError && typeof firstFocusableError.focus === 'function') { 2557 firstFocusableError.focus(); 2558 } 2559 } 2560 resize_tooltips(); 2561 return no_error; 2562 }; 2563 addEvent(window, 'resize', resize_tooltips); 2564 addEvent(window, 'scroll', resize_tooltips); 2565 var initializePhoneInput = function(inputPhone) { 2566 2567 const stylesheetLink = document.createElement('link'); 2568 stylesheetLink.rel = 'stylesheet'; 2569 stylesheetLink.href = 'https://cdn.jsdelivr.net/npm/[email protected]/build/css/intlTelInput.css'; 2570 document.head.appendChild(stylesheetLink); 2571 2572 window._load_script('https://cdn.jsdelivr.net/npm/[email protected]/build/js/intlTelInput.min.js', function() { 2573 inputPhone.setAttribute("name", "phone-iti"); 2574 iti = intlTelInput(inputPhone, { 2575 loadUtils: () => import('https://cdn.jsdelivr.net/npm/[email protected]/build/js/utils.js'), 2576 hiddenInput: (telInputName) => ({ 2577 phone: 'phone' 2578 }), 2579 separateDialCode: true, 2580 autoPlaceholder: 'aggressive', 2581 initialCountry: "us", 2582 }); 2583 }, false); 2584 } 2585 var inputPhone = form_to_submit.querySelector('input[name="phone"]'); 2586 if(inputPhone) { 2587 initializePhoneInput(inputPhone); 2588 } 2589 2590 var _form_serialize = function(form){if(!form||form.nodeName!=="FORM"){return }var i,j,q=[];for(i=0;i<form.elements.length;i++){if(form.elements[i].name===""){continue}switch(form.elements[i].nodeName){case"INPUT":switch(form.elements[i].type){case"tel":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].previousSibling.querySelector('div.iti__selected-dial-code').innerText)+encodeURIComponent(" ")+encodeURIComponent(form.elements[i].value));break;case"text":case"number":case"date":case"time":case"hidden":case"password":case"button":case"reset":case"submit":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break;case"checkbox":case"radio":if(form.elements[i].checked){q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value))}break;case"file":break}break;case"TEXTAREA":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break;case"SELECT":switch(form.elements[i].type){case"select-one":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break;case"select-multiple":for(j=0;j<form.elements[i].options.length;j++){if(form.elements[i].options[j].selected){q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].options[j].value))}}break}break;case"BUTTON":switch(form.elements[i].type){case"reset":case"submit":case"button":q.push(form.elements[i].name+"="+encodeURIComponent(form.elements[i].value));break}break}}return q.join("&")}; 2591 2592 const formSupportsPost = false;
2593 var form_submit = function(e) { 2594 2595 e.preventDefault(); 2596 if(form_to_submit.querySelector('input[name="phone"]') && typeof iti != 'undefined') { 2597 form_to_submit.querySelector('input[name="phone"]').value = iti.getNumber(); 2598 } 2599 if (validate_form()) { 2600 // use this trick to get the submit button & disable it using plain javascript 2601 var submitButton = e.target.querySelector('#_form_28_submit'); 2602 submitButton.disabled = true; 2603 submitButton.classList.add('processing'); 2604 var serialized = _form_serialize(document.getElementById('_form_28_')).replace(/%0A/g, '\\n'); 2605 var err = form_to_submit.querySelector('._form_error'); 2606 err ? err.parentNode.removeChild(err) : false; 2607 async function submitForm() { 2608 var formData = new FormData(); 2609 const searchParams = new URLSearchParams(serialized); 2610 searchParams.forEach((value, key) => { 2611 if (key !== 'hideButton') { 2612 formData.append(key, value); 2613 } 2614 }); 2615 let request = { 2616 headers: { 2617 "Accept": "application/json" 2618 }, 2619 body: formData, 2620 method: "POST" 2621 }; 2622 2623 let pageUrlParams = new URLSearchParams(window.location.search); 2624 if (pageUrlParams.has('t')) { 2625 request.headers.Authorization = 'Bearer ' + pageUrlParams.get('t'); 2626 } 2627 const response = await fetch('https://flyingshapes.activehosted.com/proc.php?jsonp=true', request); 2628 2629 return response.json(); 2630 } 2631 if (formSupportsPost) { 2632 submitForm().then((data) => { 2633 eval(data.js); 2634 }).catch(() => { 2635 _show_error("28", "Sorry, your submission failed. Please try again."); 2636 }); 2637 } else { 2638 _load_script('https://flyingshapes.activehosted.com/proc.php?' + serialized + '&jsonp=true', null, true); 2639 } 2640 } 2641 return false; 2642 }; 2643 addEvent(form_to_submit, 'submit', form_submit); 2644})(); 2645 2646</script>
2646 </div> 2647 <p class="fs-lightbox__legal">Our <a href="https://www.flyingshapes.com/privacy/">Privacy Policy</a> applies.</p> 2648 </div> 2649 </div> 2650 </dialog> 2651 <dialog class="fs-lightbox fs-lightbox--media" id="fs-lightbox-media" aria-label="Portfolio video"> 2652 <div class="fs-lightbox__panel fs-lightbox__panel--media"> 2653 <button type="button" class="fs-lightbox__close" data-lightbox-close aria-label="Close"> 2654 <span aria-hidden="true">×</span> 2655 </button> 2656 <video class="fs-lightbox__video" controls playsinline></video> 2657 </div> 2658 </dialog> 2659
2659<script type="speculationrules"> 2660{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/flyingshapes/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} 2661</script>
vendor: 1 bytes, line 2661
2661
2662<script data-wp-strategy="defer" defer id="flyingshapes-lightbox-js" src="https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/js/lightbox.js?ver=1789129308"></script>
vendor: 1 bytes, line 2662
2662
2663<script data-wp-strategy="defer" defer id="flyingshapes-nav-js" src="https://www.flyingshapes.com/wp-content/themes/flyingshapes/assets/js/nav.js?ver=1788530440"></script>
vendor: 1 bytes, line 2663
2663
2664<script id="googlesitekit-events-provider-content-events-js-before"> 2665window._googlesitekit = window._googlesitekit || {}; 2666window._googlesitekit.contentEvents = {"postID":24,"isSinglePost":false,"hasVimeoEmbed":false}; 2667//# sourceURL=googlesitekit-events-provider-content-events-js-before 2668</script>
vendor: 1 bytes, line 2668
2668
2669<script id="googlesitekit-events-provider-content-events-js" src="https://www.flyingshapes.com/wp-content/plugins/google-site-kit/dist/assets/js/googlesitekit-events-provider-content-events-c7172f3fd0e4d5ad62ef.js" defer></script>
vendor: 1 bytes, line 2669
2669
2670<script id="wp-emoji-settings" type="application/json"> 2671{"baseUrl":"https://s.w.org/images/core/emoji/17.0.2/72x72/","ext":".png","svgUrl":"https://s.w.org/images/core/emoji/17.0.2/svg/","svgExt":".svg","source":{"concatemoji":"https://www.flyingshapes.com/wp-includes/js/wp-emoji-release.min.js?ver=7.1.2"}} 2672</script>
vendor: 1 bytes, line 2672
2672
2673<script type="module"> 2674/*! This file is auto-generated */ 2675var e="script#wp-emoji-settings",t=document.querySelector(e);if(!(t instanceof HTMLScriptElement))throw new Error("Element missing: "+e);const r=JSON.parse(t.text),s=(window._wpemojiSettings=r,"wpEmojiSettingsSupports"),o=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(s,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const r=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===r[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,r){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!r(e,"\ud83e\u1fac8")}return!1}function f(e,t,n,r){let a;const s=(a="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),o=(s.textBaseline="top",s.font="600 32px Arial",{});return e.forEach(e=>{o[e]=t(s,e,n,r)}),o}function a(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}r.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(s));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(o),u.toString(),c.toString(),p.toString()].join(",")+"));",r=new Blob([e],{type:"text/javascript"});const a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=e=>{i(n=e.data),a.terminate(),t(n)})}catch(e){}i(n=f(o,u,c,p))}t(n)}).then(e=>{for(const n in e)r.supports[n]=e[n],r.supports.everything=r.supports.everything&&r.supports[n],"flag"!==n&&(r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&r.supports[n]);var t;r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&!r.supports.flag,r.supports.everything||((t=r.source||{}).concatemoji?a(t.concatemoji):t.wpemoji&&t.twemoji&&(a(t.twemoji),a(t.wpemoji)))}); 2676//# sourceURL=https://www.flyingshapes.com/wp-includes/js/wp-emoji-loader.min.js 2677</script>
2677 2678</body> 2679</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.