1(function () { 2 const BUILD_TITLE_SINGLE_LINE = 3 "The Defence & Dual-Use pilot cohort is underway, with future cohorts planned every Spring and Fall. Future streams are being developed with industry, investors, and ecosystem leaders."; 4 const BUILD_TITLE_SOFT_BREAK = 5 "The Defence & Dual-Use pilot cohort is underway, with future cohorts planned every Spring and Fall.\nFuture streams are being developed with industry, investors, and ecosystem leaders."; 6 const BUILD_TITLE_WITH_BREAK = 7 "The Defence & Dual-Use pilot cohort is underway, with future cohorts planned every Spring and Fall.\n\nFuture streams are being developed with industry, investors, and ecosystem leaders."; 8 9 const DEFAULT_LANDING_CONTENT = { 10 navigation: { 11 eyebrow: "Get in touch", 12 interestLabel: "Founders - Express Interest", 13 interestHref: "https://airtable.com/app4M8raEWsyOVktS/pagEzxLGODRsnV5N9/form", 14 applyHref: "mailto:[email protected]", 15 }, 16 chapters: { 17 brand: { 18 title: 19 "Scale Up is a cohort-based growth-stage platform helping founders transition from building products to operating and scaling companiesâbringing together experienced operators, sector experts, investors, and partners to build Canadaâs next generation of scaling companies.", 20 secondary: ["Built at UBC Sauder School of Business", "Informed by the success of Creative Destruction Lab Vancouver"], 21 visualLines: [ 22 "From Traction to Scalable Growth", 23 "Built at UBC Sauder School of Business", 24 "Informed by the success of Creative Destruction Lab Vancouver", 25 ], 26 mobileVisualLines: [ 27 "From Traction to\nScalable Growth", 28 "Built at UBC Sauder School of Business", 29 "Informed by the success of Creative Destruction Lab Vancouver", 30 ], 31 showSecondaryVisualLines: false, 32 desktopVisual: { 33 kind: "video", 34 src: "./public/_videos/SCALEUP FOOTAGE Clip 76.m4v", 35 poster: "./public/_photos/SCALEUPxZAK03546.jpg", 36 alt: "Scale Up participants in session.", 37 }, 38 mobileVisual: { 39 kind: "video", 40 src: "./public/_videos/SCALEUP FOOTAGE Clip 76.m4v", 41 poster: "./public/_photos/SCALEUPxZAK03546.jpg", 42 alt: "Scale Up participants in session.", 43 }, 44 }, 45 context: { 46 title: 47 "Canada produces strong early-stage ventures, but relatively few scale into globally competitive companies. Scale Up exists to help high potential companies with traction make the transition from promising venture to the next great Canadian company.", 48 secondary: [ 49 "Our mission is to to domicile the next great Canadian ventures here at home.", 50 "Our mandate is economic development.", 51 ], 52 visualLines: ["Why Scale", "Up Exists"], 53 mobileVisualLines: ["Why Scale", "Up Exists"], 54 }, 55 network: { 56 title: 57 "There are few programs designed to identify Canada's highest-potential scale ups and invest sustained time, mentorship, and operating experience into their growth.", 58 secondary: [ 59 "Built with founders, operators, investors, sector experts, and corporate partners.", 60 "Designed for companies beyond early traction.", 61 ], 62 visualLines: ["A Different", "Kind of Support"], 63 mobileVisualLines: ["A Different", "Kind of Support"], 64 desktopVisual: { 65 kind: "video", 66 src: "./public/_videos/SCALEUP FOOTAGE Clip 11.mp4", 67 alt: "", 68 }, 69 mobileVisual: { 70 kind: "image", 71 src: "./public/_photos/SCALEUPxZAK03443.jpg", 72 alt: "Scale Up session participant seated in discussion.", 73 }, 74 }, 75 operators: { 76 title: 77 "Through more than 10 years of running Creative Destruction Lab at UBC Sauder, we observed a consistent challenge: the shift from building a product to operating and scaling a Company.", 78 secondary: [ 79 "Building teams and organizational systems.", 80 "Creating repeatable enterprise sales.", 81 "Navigating complex markets and operational complexity.", 82 ], 83 visualLines: ["Operating Company", "Challenges"], 84 mobileVisualLines: ["Operating Company", "Challenges"], 85 }, 86 scale: { 87 title: 88 "Scale Up combines applied learning, deep operator mentorship, and founder leadership support for founders of companies entering their next stage of growth.", 89 secondary: [ 90 "Deep-dive discussions with experienced operators and functional experts.", 91 "Support for the transition from execution-focused foun
91der to organizational leader.", 92 ], 93 visualLines: ["Education", "Mentorship", "Leadership"], 94 mobileVisualLines: ["Education", "Mentorship", "Leadership"], 95 desktopVisual: { 96 kind: "video", 97 src: "./public/_videos/SCALEUP FOOTAGE Clip 23.mp4", 98 alt: "Scale Up education, mentorship, and leadership footage.", 99 }, 100 mobileVisual: { 101 kind: "video", 102 src: "./public/_videos/SCALEUP FOOTAGE Clip 23.mp4", 103 alt: "Scale Up education, mentorship, and leadership footage.", 104 }, 105 }, 106 build: { 107 title: BUILD_TITLE_WITH_BREAK, 108 secondary: [ 109 "Launching with a Defence & Dual-Use Stream.", 110 "Interested in shaping a future stream? Letâs talk.", 111 ], 112 visualLines: [ 113 "Supporting high-potential Canadian ventures scale into defence, dual-use, and advanced industrial markets", 114 ], 115 mobileVisualLines: [ 116 "Supporting high-potential Canadian ventures scale into defence, dual-use, and advanced industrial markets", 117 ], 118 }, 119 support: { 120 title: "Supported By:", 121 secondary: ["[email protected]"], 122 desktopVisual: { 123 kind: "video", 124 src: "./public/_videos/SCALEUP FOOTAGE Clip 45.mp4", 125 alt: "Scale Up gathering footage.", 126 }, 127 mobileVisual: { 128 kind: "video", 129 src: "./public/_videos/SCALEUP FOOTAGE Clip 45.mp4", 130 alt: "Scale Up gathering footage.", 131 }, 132 logoWall: { 133 src: "./assets/partner-logos/logo-wall.png", 134 alt: "BDC, Innovate BC, Fasken, PacifiCan, and Mitsubishi Canada Ltd. logos", 135 }, 136 }, 137 }, 138 }; 139 140 const query = `*[_type == "landingPage" && _id == "landingPage"][0]{ 141 navigation, 142 "chapters": chapters[]{ 143 key, 144 title, 145 secondary, 146 visualLines, 147 mobileVisualLines, 148 showSecondaryVisualLines, 149 actions, 150 contactLabel, 151 contactSite, 152 contactSiteHref, 153 contactEmail, 154 contactEmailHref, 155 desktopVisual{kind, alt, existingSrc, "uploadedSrc": asset->url, poster{existingSrc, "uploadedSrc": asset->url}}, 156 mobileVisual{kind, alt, existingSrc, "uploadedSrc": asset->url, poster{existingSrc, "uploadedSrc": asset->url}}, 157 logoWall{kind, alt, existingSrc, "uploadedSrc": asset->url} 158 } 159 }`; 160 161 const mergeObjects = (base, override) => { 162 if (!override || Array.isArray(override) || typeof override !== "object") { 163 return override ?? base; 164 } 165 166 return Object.fromEntries( 167 Object.keys({ ...base, ...override }).map((key) => [ 168 key, 169 mergeObjects(base?.[key], override[key]), 170 ]), 171 ); 172 }; 173 174 const normalizeMedia = (media) => { 175 const source = media && typeof media === "object" ? media : {}; 176 177 return { 178 kind: source.kind || "image", 179 src: source.uploadedSrc || source.existingSrc || source.src || "", 180 alt: source.alt || "", 181 poster: source.poster?.uploadedSrc || source.poster?.existingSrc || source.poster || "", 182 }; 183 }; 184 185 function normalizeSanityContent(content) { 186 if (!content) { 187 return DEFAULT_LANDING_CONTENT; 188 } 189 190 const chapters = {}; 191 (content.chapters || []).forEach((chapter) => { 192 if (!chapter?.key) { 193 return; 194 } 195 196 const normalizedChapter = { 197 ...chapter, 198 desktopVisual: normalizeMedia(chapter.desktopVisual), 199 mobileVisual: normalizeMedia(chapter.mobileVisual), 200 logoWall: normalizeMedia(chapter.logoWall), 201 }; 202 203 if ( 204 normalizedChapter.key === "build" && 205 [BUILD_TITLE_SINGLE_LINE, BUILD_TITLE_SOFT_BREAK].includes(normalizedChapter.title) 206 ) { 207 normalizedChapter.title = BUILD_TITLE_WITH_BREAK; 208 } 209 210 if ( 211 normalizedChapter.key === "build" && 212 normalizedChapter.secondary?.[0] === "Pilot cohort underway" && 213 normalizedChapter.secondary?.[1] === "Future cohorts every Spring & Fall" 214 ) { 215 normalizedChapter.secondary = DEFAULT_LANDING_CONTENT.chapters.build.secondary; 216 } 217
218 chapters[chapter.key] = normalizedChapter; 219 }); 220 221 return mergeObjects(DEFAULT_LANDING_CONTENT, { 222 navigation: content.navigation, 223 chapters, 224 }); 225 } 226 227 function getPathValue(content, path) { 228 return path.split(".").reduce((value, part) => value?.[part], content); 229 } 230 231 function setText(element, value) { 232 if (value === undefined || value === null) { 233 return; 234 } 235 236 if (Array.isArray(value)) { 237 const children = Array.from(element.children); 238 value.forEach((line, index) => { 239 const target = children[index] || document.createElement("span"); 240 target.textContent = line; 241 if (!target.parentElement) { 242 element.append(target); 243 } 244 }); 245 children.slice(value.length).forEach((child) => child.remove()); 246 return; 247 } 248 249 element.textContent = value; 250 } 251 252 function linkBuildSecondaryContact(content) { 253 const element = document.querySelectorAll?.('[data-cms-text="chapters.build.secondary"]')?.[0]; 254 const href = content.navigation?.applyHref; 255 256 if (!element || !href) { 257 return; 258 } 259 260 const paragraphs = Array.from(element.children); 261 const contactParagraph = paragraphs[1]; 262 const marker = "Letâs talk."; 263 264 if (!contactParagraph || !contactParagraph.textContent.includes(marker)) { 265 return; 266 } 267 268 const text = contactParagraph.textContent; 269 const [before] = text.split(marker); 270 const link = document.createElement("a"); 271 272 contactParagraph.textContent = before; 273 link.href = href; 274 link.textContent = marker; 275 link.dataset.cmsHref = "navigation.applyHref"; 276 contactParagraph.append(link); 277 } 278 279 function setSecondaryVisualLineVisibility(element, value) { 280 const showSecondaryLines = value === true; 281 Array.from(element.children).forEach((child, index) => { 282 child.hidden = !showSecondaryLines && index > 0; 283 }); 284 } 285 286 function setHref(element, value) { 287 if (value) { 288 element.setAttribute("href", value); 289 } 290 } 291 292 function setVideo(element, value) { 293 if (!value) { 294 return; 295 } 296 297 if (!/\.(mp4|m4v|webm)(?:[?#].*)?$/i.test(value)) { 298 return; 299 } 300 301 const video = element.matches("video") ? element : element.querySelector("video"); 302 const source = video?.querySelector("source"); 303 304 if (!video || !source) { 305 return; 306 } 307 308 source.setAttribute("src", value); 309 video.load(); 310 } 311 312 function setImage(element, value) { 313 if (!value) { 314 return; 315 } 316 317 const image = element.matches("img") ? element : element.querySelector("img"); 318 image?.setAttribute("src", value); 319 } 320 321 function setAlt(element, value) { 322 if (value === undefined || value === null) { 323 return; 324 } 325 326 if (element.matches("img")) { 327 element.setAttribute("alt", value); 328 } else if (element.matches("video")) { 329 element.setAttribute("aria-label", value); 330 } 331 } 332 333 function setPoster(element, value) { 334 if (value && element.matches("video")) { 335 element.setAttribute("poster", value); 336 } 337 } 338 339 function applyLandingContent(content) { 340 document.querySelectorAll("[data-cms-text]").forEach((element) => { 341 setText(element, getPathValue(content, element.dataset.cmsText)); 342 }); 343 344 linkBuildSecondaryContact(content); 345 346 document.querySelectorAll("[data-cms-secondary-visual-lines]").forEach((element) => { 347 setSecondaryVisualLineVisibility( 348 element, 349 getPathValue(content, element.dataset.cmsSecondaryVisualLines), 350 ); 351 }); 352 353 document.querySelectorAll("[data-cms-href]").forEach((element) => { 354 setHref(element, getPathValue(content, element.dataset.cmsHref)); 355 }); 356 357 document.querySelectorAll("[data-cms-action-text]").forEach((element) => { 358 setText(element.querySelector(".story-action-list__copy") || element, getPathValue(content, element.dataset.cmsActionText)); 359 }); 360 361 document.querySelectorAll("[data-cms-video]").forEach((element) => { 362 setVideo(element, getPathValue(content, element.dataset.cmsVideo)); 363 }); 364 365 document.querySelectorAll("[data-cms-image]").forEach((element) => { 366 setImage(element, getPathValue(content, element.dataset.cmsImage)); 367 }); 368 369 document.querySelectorAll("[data-cms-alt]").forEach((element) => { 370 setAlt(element, getPathValue(content, element.dataset.cmsAlt)); 371 }); 372 373 document.querySelectorAll("[data-cms-poster]").forEach((element) => { 374 setPoster(element, getPathValue(content, element.dataset.cmsPoster)); 375 }); 376 } 377 378 async function fetchSanityLandingContent() { 379 const config = window.SCALEUP_SANITY_CONFIG || {}; 380 381 if (!config.projectId || !config.dataset) { 382 return DEFAULT_LANDING_CONTENT; 383 } 384 385 const encodedQuery = encodeURIComponent(query); 386 const cdn = config.useCdn === false ? "api" : "apicdn"; 387 const endpoint = `https://${config.projectId}.${cdn}.sanity.io/v${config.apiVersion || "2025-05-11"}/data/query/${config.dataset}?query=${encodedQuery}`; 388 const response = await fetch(endpoint); 389 390 if (!response.ok) { 391 throw new Error(`Sanity content request failed with ${response.status}`); 392 } 393 394 const payload = await response.json(); 395 return normalizeSanityContent(payload.result); 396 } 397 398 async function initLandingContent() { 399 try { 400 const content = await fetchSanityLandingContent(); 401 applyLandingContent(content); 402 return content; 403 } catch (error) {
404 console.warn("[Scale Up CMS] Using static fallback content.", error); 405 applyLandingContent(DEFAULT_LANDING_CONTENT); 406 return DEFAULT_LANDING_CONTENT; 407 } 408 } 409 410 window.ScaleUpContent = { 411 DEFAULT_LANDING_CONTENT, 412 applyLandingContent, 413 fetchSanityLandingContent, 414 initLandingContent, 415 }; 416})();
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.