1// Service Detail Page Handler 2document.addEventListener('DOMContentLoaded', function() { 3 // Query (?service=) or clean SEO path (see seo-service-urls.js + .htaccess) 4 const serviceId = typeof serviceIdFromUrl === 'function' 5 ? serviceIdFromUrl() 6 : new URLSearchParams(window.location.search).get('service'); 7 8 if (!serviceId) { 9 // Redirect to services page if no service ID 10 window.location.href = 'services.html'; 11 return; 12 } 13 14 // Check if servicesData is available 15 if (typeof servicesData === 'undefined') { 16 console.error('servicesData is not defined. Make sure services-pages.js is loaded before service-detail.js'); 17 return; 18 } 19 20 // Find service data 21 const service = servicesData.find(s => s.id === serviceId); 22 23 if (!service) { 24 console.error('Service not found:', serviceId); 25 // Redirect if service not found 26 window.location.href = 'services.html'; 27 return; 28 } 29 30 console.log('Service found:', service.title); 31 console.log('Features:', service.features); 32 console.log('Benefits:', service.benefits); 33 console.log('FAQs:', service.faqs); 34 35 // SEO metadata for each service detail page 36 const serviceSeoMeta = { 37 'website-designing': { 38 title: 'Website Design and Development company in Bangalore | Pinakkaa', 39 description: 'Pinakkaa is a trusted website design and Development agency in Bangalore delivering creative, user-friendly websites that help businesses grow online. Let\'s build your digital success.' 40 }, 41 'seo-digital-marketing': { 42 title: 'Best SEO Agency in Bangalore | SEO Company in Bangalore - Pinakkaa', 43 description: 'Pinakkaa is a Result oriented SEO company in Bangalore delivering real results. Improve SERP rankings, boost traffic, and grow your business with our expert team.' 44 }, 45 'online-reputation-management': { 46 title: 'ORM Services in Bangalore | Online Reputation Management Company - Pinakkaa', 47 description: 'Protect your brand with Pinakkaa\'s Expert ORM services in Bangalore. We remove negative results, improve ratings, build trust, and help your business stand out with a strong online reputation.' 48 }, 49 'social-media-optimization': { 50 title: 'SMO Company in Bangalore | Social Media Optimization Agency - Pinakkaa', 51 description: 'Pinakkaa is a trusted SMO company in Bangalore helping businesses increase reach, engagement, and leads through powerful social media strategies.' 52 }, 53 'search-engine-marketing': { 54 title: 'SEM Services in Bangalore | Search Engine Marketing Agency - Pinakkaa', 55 description: 'Pinakkaa, a reliable search engine marketing company in Bangalore, offers performance-driven SEM services in Bangalore to generate leads, increase sales, and deliver strong ROI as a leading SEM agency.' 56 }, 57 'social-media-marketing': { 58 title: 'Social Media Marketing agency in Bangalore | SMM Company in Bangalore | Pinakkaa', 59 description: 'As a trusted Social Media Marketing agency in Bangalore, Pinakkaa stands out as a reliable SMM company in Bangalore delivering measurable growth through effective social media campaigns.' 60 }, 61 'branding-rebranding': { 62 title: 'Branding Agency in Bangalore | Pinakkaa Brand Identity Creators', 63 description: 'Why choose Pinakkaa? We go beyond visuals to build brands that stand out. Our branding and rebranding services in Bangalore focus on strategy, identity, and growth.' 64 }, 65 'display-advertising': { 66 title: 'Best display advertising agency in Bangalore | Pinakkaa', 67 description: 'Pinakkaa offers display advertising services in Bangalore designed to reach the right audience, improve brand visibility, and generate higher engagement and measurable returns.' 68 }, 69 'ecommerce-solutions': { 70 title: 'E-Commerce Website Development Agency in Bangalore | Pinakkaa', 71 description: 'Pinakkaa offers e-commerce website development Company in Bangalore, building scalable, user-friendly online stores with seamless design, secure systems, and performance-focused solutions.' 72 }, 73 'pr-marketing-services': { 74 title: 'Strategic PR and Marketing Solutions in Bangalore | Pinakkaa', 75 description: 'Pinakkaa is a PR and marketing agency in Bangalore helping brands build credibility, gain media visibility, and connect with the right audience through targeted campaigns and storytelling.' 76 }, 77 'software-development': { 78 title: 'Software Development Company in Bangalore | Pinakkaa Tech Solutions', 79 description: 'Get in touch with Pinakkaa, a custom softw
79are development company in Bangalore delivering tailored solutions for startups, SMEs, and enterprises, including applications, cloud, and system integration.' 80 }, 81 'api-integration': { 82 title: 'API Integration Services in Bangalore | Pinakkaa Seamless System Connectivity', 83 description: 'Pinakkaa provides API integration services in Bangalore enabling smooth data flow between your apps, platforms, CRM, ERP and business systems for unified operations.' 84 }, 85 'email-marketing': { 86 title: 'Email Marketing Services in Bangalore | Top Email marketing company Bangalore', 87 description: 'Pinakkaa Email Marketing Agency in Bangalore that offers result-driven email marketing services to achieve your goals. Hire the Best Email Marketing Company in Bangalore!' 88 }, 89 'sms-marketing': { 90 title: 'SMS Marketing Company in Bangalore | Pinakkaa High-Conversion SMS Campaigns', 91 description: 'Pinakkaa , SMS Marketing agency in Bangalore creates high-impact SMS marketing campaigns for lead generation, customer retention and instant communication with measurable results.' 92 }, 93 'whatsapp-marketing': { 94 title: 'WhatsApp Marketing Agency in Bangalore | Pinakkaa Direct Customer Engagement', 95 description: 'Pinakkaa offers WhatsApp marketing services in Bangalore to boost interaction, automate communication, deliver campaigns and increase conversion through personal outreach.' 96 }, 97 'shopify-website-development': { 98 title: 'Shopify Website Development Services in Bangalore | Pinakkaa', 99 description: 'Pinakkaa offers Shopify website development services in Bangalore, creating scalable, user-friendly online stores designed to improve performance, conversions, and growth.' 100 } 101 }; 102 const seoMeta = serviceSeoMeta[service.id] || {}; 103 const pageTitle = seoMeta.title || `${service.title} in Bangalore | Pinakkaa`; 104 const pageDescription = seoMeta.description || (service.shortDescription || service.fullDescription || '') 105 .toString() 106 .trim() 107 .replace(/\s+/g, ' ') 108 .slice(0, 160); 109 const canonicalPath = typeof serviceDetailHref === 'function' 110 ? serviceDetailHref(service.id) 111 : '/service-detail.html?service=' + encodeURIComponent(service.id); 112 const canonicalUrl = new URL(canonicalPath, window.location.origin).toString(); 113 114 // Update page title 115 document.title = pageTitle; 116 117 const setHeadTag = (selector, createTag, attrs) => { 118 let el = document.head.querySelector(selector); 119 if (!el) { 120 el = document.createElement(createTag); 121 document.head.appendChild(el); 122 } 123 Object.keys(attrs).forEach((key) => { 124 el.setAttribute(key, attrs[key]); 125 }); 126 }; 127 128 setHeadTag('meta[name="description"]', 'meta', { 129 name: 'description', 130 content: pageDescription 131 }); 132 setHeadTag('meta[name="robots"]', 'meta', { 133 name: 'robots', 134 content: 'index,follow' 135 }); 136 setHeadTag('link[rel="canonical"]', 'link', { 137 rel: 'canonical', 138 href: canonicalUrl 139 }); 140 setHeadTag('meta[property="og:title"]', 'meta', { 141 property: 'og:title', 142 content: pageTitle 143 }); 144 setHeadTag('meta[property="og:description"]', 'meta', { 145 property: 'og:description', 146 content: pageDescription 147 }); 148 setHeadTag('meta[property="og:url"]', 'meta', { 149 property: 'og:url', 150 content: canonicalUrl 151 }); 152 setHeadTag('meta[property="og:type"]', 'meta', { 153 property: 'og:type', 154 content: 'website' 155 }); 156 157 // Update hero section 158 const serviceTitleText = document.getElementById('serviceTitleText'); 159 const serviceBreadcrumbName = document.getElementById('serviceBreadcrumbName'); 160 const serviceDetailSubtitle = document.getElementById('serviceDetailSubtitle'); 161 162 if (serviceTitleText) { 163 serviceTitleText.textContent = service.title; 164 } 165 166 if (serviceBreadcrumbName) { 167 serviceBreadcrumbName.textContent = service.title; 168 } 169 170 if (serviceDetailSubtitle) {
171 serviceDetailSubtitle.textContent = service.shortDescription; 172 } 173 174 // Pinakkaa Advantage (dynamic per selected service) 175 const advantageTitleEl = document.getElementById('pinakkaaAdvantageTitle'); 176 const advantageSubtitleEl = document.getElementById('pinakkaaAdvantageSubtitle'); 177 const advantageDesc1 = document.getElementById('pinakkaaAdvantageDesc1'); 178 const advantageDesc2 = document.getElementById('pinakkaaAdvantageDesc2'); 179 const advantageDesc3 = document.getElementById('pinakkaaAdvantageDesc3'); 180 const advantageDesc4 = document.getElementById('pinakkaaAdvantageDesc4'); 181 182 const truncate = (text, max = 150) => { 183 const value = String(text || '').trim(); 184 if (!value) return ''; 185 return value.length > max ? value.slice(0, max - 3) + '...' : value; 186 }; 187 188 const benefitPool = Array.isArray(service.benefits) ? service.benefits : []; 189 const featurePool = Array.isArray(service.features) ? service.features : []; 190 191 // Service-specific titles and micro-copy for Pinakkaa Advantage 192 const advantagePresets = { 193 'website-designing': { 194 heading: 'The Pinakkaa Advantage in Website Design', 195 items: [ 196 'Pixel-Perfect Brand Presence', 197 'Experience-Led Journeys', 198 'Conversion-Ready Layouts', 199 'Analytics-Backed Iteration' 200 ], 201 descriptions: [ 202 'Standout layouts that feel on-brand, modern, and consistent across every screen.', 203 'User journeys mapped to how people actually browse, not how wireframes look.', 204 'Page structures guided to enquiry, signup, or checkout with minimal friction.', 205 'Decisions driven by heatmaps, form analytics, and real behaviour data.' 206 ] 207 }, 208 'seo-digital-marketing': { 209 heading: 'The Pinakkaa Advantage in SEO & Growth', 210 items: [ 211 'Search Visibility that Compounds', 212 'Content that Earns Clicks', 213 'Funnels Built for Conversions', 214 'Always-On Measurement' 215 ], 216 descriptions: [ 217 'Rankings built to last, not spike: technical, on-page, and authority working together.', 218 'Stories written for humans first and algorithms second, so clicks stay and explore.', 219 'Journeys tuned for demo, lead, or sale with clear paths from search term to action.', 220 'Dashboards you can actually read, focused on traffic quality and revenue.' 221 ] 222 }, 223 'social-media-optimization': { 224 heading: 'The Pinakkaa Advantage in Social Media', 225 items: [ 226 'ThumbâStopping Creatives', 227 'Communities, Not Just Followers', 228 'Campaigns that Convert', 229 'Real-Time Performance Insights' 230 ], 231 descriptions: [ 232 'Posts and stories that pause the scroll with clear, on-brand visual language.', 233 'Comments and DMs turned into conversations that build real community.', 234 'Always-on and burst campaigns tied directly to signups, leads, or sales.', 235 'Live metrics instead of monthly surprises, so you can react in real time.' 236 ] 237 }, 238 'online-reputation-management': { 239 heading: 'The Pinakkaa Advantage in Reputation', 240 items: [ 241 'Proactive Brand Protection', 242 'Human, On-Point Responses', 243 'Trust that Converts', 244 'Always-On Monitoring' 245 ], 246 descriptions: [ 247 'Issues spotted before they snowball through constant review and mention tracking.', 248 'Replies that sound like your brand, not a script, even in tough situations.', 249 'Reviews and testimonials shaped into proof and trust across key touchpoints.', 250 '24/7 eyes on review sites and socials, with clear playbooks for action.' 251 ] 252 }, 253 'search-engine-marketing': { 254 heading: 'The Pinakkaa Advantage in SEM', 255 items: [ 256 'Precision Targeting', 257 'Creative that Wins Auctions', 258 'ROI-First Optimisation', 259 'Transparent Reporting' 260 ], 261 descriptions: [ 262 'Ads shown only to real prospects using intent, audience lists, and geos that matter.', 263 'Copy and creatives built to win more auctions without burning your budget.', 264 'Every rupee mapped to outcomes like leads, pipeline, or revenue, not just clicks.', 265 'PlainâEnglish performance breakdowns with clear keep/kill/scale decisions.' 266 ] 267 }, 268 'social-media-marketing': { 269 heading: 'The Pinakkaa Advantage in Paid Social', 270 items: [ 271 'Full-Funnel Ad Strategy', 272 'Audience Intelligence', 273 'Sales-Ready Campaigns', 274 'Continuous Experimentation' 275 ], 276 descriptions: [ 277 'Cold, warm, and hot journeys aligned so each audience sees the right story.', 278 'Segments built from real behaviour, not guesses, and synced across platforms.', 279 'Offers and creatives written to move people from interest to actual revenue.', 280 'Always-on creative and audience tests so performance improves month after month.' 281 ] 282 } 283 }; 284 285 const preset = advantagePresets[service.id] || { 286 heading: `The Pinakkaa Advantage in ${service.title}`, 287 items: [ 288 'Better Brand Visibility', 289 'Stronger Audience Engagement', 290 'Higher Quality Conversions', 291 'Decisions Backed by Data' 292 ], 293 descriptions: [ 294 'More of the right people seeing a clear, consistent message from your brand.', 295 'Interactions that feel genuinely useful instead of just adding to the noise.', 296 'Leads and customers that look like your ideal profile, not random clicks.',
297 'Next steps guided by numbers you understand, not just vanity metrics.' 298 ] 299 }; 300 301 const itemTitleEls = document.querySelectorAll('.pinakkaa-advantage-item-title'); 302 const iconImgs = document.querySelectorAll('.pinakkaa-advantage-icon-img'); 303 304 const iconSets = { 305 'website-designing': [ 306 'services-pages/icons/graphic_11183291.svg', 307 'services-pages/icons/idea_11331946.svg', 308 'services-pages/icons/view_14014506.svg', 309 'services-pages/icons/eye_4367508.svg' 310 ], 311 'seo-digital-marketing': [ 312 'services-pages/icons/growth_12951171.svg', 313 'services-pages/icons/business-strategy_7897981.svg', 314 'services-pages/icons/objective_12209885.svg', 315 'services-pages/icons/strategic-plan_7897776.svg' 316 ], 317 'social-media-optimization': [ 318 'services-pages/icons/speaker_17806860.png', 319 'services-pages/icons/respect_12198286.svg', 320 'services-pages/icons/handshake_8252396.svg', 321 'services-pages/icons/gmail_17844661.svg' 322 ], 323 'online-reputation-management': [ 324 'services-pages/icons/eye_4367508.svg', 325 'services-pages/icons/respect_12198286.svg', 326 'services-pages/icons/handshake_8252396.svg', 327 'services-pages/icons/objective_12209885.svg' 328 ], 329 'search-engine-marketing': [ 330 'services-pages/icons/profits_7895066.svg', 331 'services-pages/icons/growth_12951171.svg', 332 'services-pages/icons/business-strategy_7897981.svg', 333 'services-pages/icons/strategic-plan_7897776.svg' 334 ], 335 'social-media-marketing': [ 336 'services-pages/icons/speaker_17806860.png', 337 'services-pages/icons/growth_12951171.svg', 338 'services-pages/icons/handshake_8252396.svg', 339 'services-pages/icons/gmail_17844661.svg' 340 ] 341 }; 342 343 const fallbackIcons = [ 344 'services-pages/icons/handshake_8252396.svg', 345 'services-pages/icons/growth_12951171.svg', 346 'services-pages/icons/profits_7895066.svg', 347 'services-pages/icons/business-strategy_7897981.svg' 348 ]; 349 const iconSet = iconSets[service.id] || fallbackIcons; 350 351 if (advantageTitleEl) { 352 advantageTitleEl.textContent = preset.heading; 353 } 354 355 preset.items.forEach((label, index) => { 356 if (itemTitleEls[index]) { 357 itemTitleEls[index].textContent = label; 358 } 359 }); 360 361 iconSet.forEach((src, index) => { 362 if (iconImgs[index]) { 363 iconImgs[index].src = src; 364 iconImgs[index].alt = preset.items[index] || 'Pinakkaa advantage'; 365 } 366 }); 367 368 if (advantageSubtitleEl) { 369 advantageSubtitleEl.textContent = `When you partner with Pinakkaa for ${service.title}, you don't just get a service, you get a growth partner.`; 370 } 371 372 const shortDescs = preset.descriptions || []; 373 if (advantageDesc1) advantageDesc1.textContent = truncate(shortDescs[0] || ''); 374 if (advantageDesc2) advantageDesc2.textContent = truncate(shortDescs[1] || ''); 375 if (advantageDesc3) advantageDesc3.textContent = truncate(shortDescs[2] || ''); 376 if (advantageDesc4) advantageDesc4.textContent = truncate(shortDescs[3] || ''); 377 378 // Why Choose Pinakkaa for [Service] 379 const whyChooseSection = document.getElementById('whyChooseService'); 380 const whyChooseNameEl = document.getElementById('whyChooseServiceName'); 381 const whyChooseSubtitleEl = document.getElementById('whyChooseSubtitle'); 382 const whyChooseGrid = document.getElementById('whyChooseGrid'); 383 384 const whyPresets = { 385 'website-designing': { 386 subtitle: 'Design, UX, and performance handled under one roof â from first wireframe to final launch.', 387 items: [ 388 { 389 icon: 'services-pages/New_icons/lamp_9935981.svg', 390 title: 'Strategy Before Screens', 391 desc: 'We start with brand, users, and outcomes, then design pages that each have a clear job.' 392 }, 393 {
394 icon: 'services-pages/New_icons/view_14014506.svg', 395 title: 'Pixel-Level Craft', 396 desc: 'Layouts, typography, and motion tuned to feel premium on desktop and mobile.' 397 }, 398 { 399 icon: 'services-pages/New_icons/sand-clock_11286687.svg', 400 title: 'Fast, Stable Builds', 401 desc: 'Clean code and fast load times so your site feels sharp, not sluggish.' 402 } 403 ] 404 }, 405 'seo-digital-marketing': { 406 subtitle: 'Technical SEO, content, and authority rolled into one program focused on true business KPIs.', 407 items: [ 408 { 409 icon: 'services-pages/New_icons/achievement_7871901.svg', 410 title: 'Proven Playbooks', 411 desc: 'Battleâtested SEO frameworks adapted to your domain, not copyâpasted checklists.' 412 }, 413 { 414 icon: 'services-pages/New_icons/calendar_9642627.svg', 415 title: 'Compounding Gains', 416 desc: 'Roadmaps planned quarter by quarter so improvements stack instead of reset.' 417 }, 418 { 419 icon: 'services-pages/New_icons/eye_4367508.svg',
420 title: 'Radical Transparency', 421 desc: 'Clear tracking and reporting so you always know what moved the needle and why.' 422 } 423 ] 424 }, 425 'social-media-optimization': { 426 subtitle: 'Content, cadence, and community management tuned to how your audience actually behaves.', 427 items: [ 428 { 429 icon: 'services-pages/New_icons/speaker_17806860.png', 430 title: 'Distinct Brand Voice', 431 desc: 'Posts and stories that sound like you, not like a generic social media template.' 432 }, 433 { 434 icon: 'services-pages/New_icons/heart_9548779.svg', 435 title: 'Community Focus', 436 desc: 'DMs and comments turned into real conversations that build loyalty over time.' 437 }, 438 { 439 icon: 'services-pages/New_icons/gmail_17844661.svg', 440 title: 'Always-On Pipeline', 441 desc: 'A steady stream of ideas and assets so your profiles never go silent.' 442 } 443 ] 444 }, 445 'online-reputation-management': { 446 subtitle: 'Monitoring, response, and recovery plans that protect the trust you have already earned.', 447 items: [ 448 { 449 icon: 'services-pages/New_icons/eye_4367508.svg', 450 title: 'Constant Monitoring', 451 desc: 'Mentions and reviews tracked so small issues are caught long before they explode.' 452 }, 453 { 454 icon: 'services-pages/New_icons/respect_12198286.svg', 455 title: 'Human Responses', 456 desc: 'Reply frameworks that respect both your brand voice and the customerâs situation.' 457 }, 458 { 459 icon: 'services-pages/New_icons/flower_17891894.svg', 460 title: 'Rebuild & Strengthen', 461 desc: 'Positive content and review strategies that gradually shift sentiment in your favour.' 462 } 463 ] 464 }, 465 'search-engine-marketing': { 466 subtitle: 'Hands-on campaign management built for profitable growth, not just higher spend.', 467 items: [ 468 { 469 icon: 'services-pages/New_icons/achievement_7871901.svg', 470 title: 'Performance DNA', 471 desc: 'Bids, audiences, and creatives tuned from live data, not setâandâforget rules.' 472 }, 473 { 474 icon: 'services-pages/New_icons/view_14014506.svg', 475 title: 'Goal-Linked KPIs', 476 desc: 'Every campaign wired to leads, pipeline, or revenue instead of surfaceâlevel metrics.' 477 }, 478 { 479 icon: 'services-pages/New_icons/sand-clock_11286687.svg', 480 title: 'Fast Test Cycles', 481 desc: 'New angles tested quickly so winning ideas get budget and weak ones are cut.' 482 } 483 ] 484 }, 485 'social-media-marketing': { 486 subtitle: 'Paid social designed as a full funnel â awareness, consideration, and conversion.', 487 items: [ 488 { 489 icon: 'services-pages/New_icons/speaker_17806860.png', 490 title: 'Platform-Native Ads', 491 desc: 'Creative built for reels, stories, and feeds instead of one resized master file.' 492 }, 493 { 494 icon: 'services-pages/New_icons/flower_18376638.svg', 495 title: 'Deep Audience Maps', 496 desc: 'Cold, warm, and hot segments mapped to messaging that matches intent.' 497 }, 498 { 499 icon: 'services-pages/New_icons/gift_9428742.svg', 500 title: 'Offer Strategy', 501 desc: 'Hooks, bundles, and promos crafted to turn attention into trackable revenue.' 502 } 503 ] 504 } 505 }; 506 507 if (whyChooseSection && whyChooseGrid && whyChooseNameEl) { 508 const config = whyPresets[service.id]; 509 whyChooseNameEl.textContent = `${service.title}?`; 510 511 if (!config) {
512 if (whyChooseSubtitleEl) { 513 whyChooseSubtitleEl.textContent = 'You get a team that thinks about strategy, execution, and reporting as one connected system.'; 514 } 515 whyChooseGrid.innerHTML = ` 516 <div class="why-choose-card"> 517 <div class="why-choose-icon"><img src="services-pages/New_icons/lamp_9935981.svg" alt=""></div> 518 <h3 class="why-choose-card-title">Strategic Partner</h3> 519 <p class="why-choose-card-desc">We learn your model first, then pick the mix of channels and tactics that actually fits.</p> 520 </div> 521 <div class="why-choose-card"> 522 <div class="why-choose-icon"><img src="services-pages/New_icons/achievement_7871901.svg" alt=""></div> 523 <h3 class="why-choose-card-title">Execution Obsessed</h3> 524 <p class="why-choose-card-desc">Clear plans, weekly movement, and campaigns that keep improving instead of stalling.</p> 525 </div> 526 <div class="why-choose-card"> 527 <div class="why-choose-icon"><img src="services-pages/New_icons/calendar_9642627.svg" alt=""></div> 528 <h3 class="why-choose-card-title">Honest Reporting</h3> 529 <p class="why-choose-card-desc">Simple dashboards and nextâstep recommendations you can act on immediately.</p> 530 </div> 531 `; 532 } else { 533 if (whyChooseSubtitleEl) { 534 whyChooseSubtitleEl.textContent = config.subtitle; 535 } 536 whyChooseGrid.innerHTML = config.items.map(item => ` 537 <div class="why-choose-card"> 538 <div class="why-choose-icon"> 539 <img src="${item.icon}" alt=""> 540 </div> 541 <h3 class="why-choose-card-title">${item.title}</h3> 542 <p class="why-choose-card-desc">${item.desc}</p> 543 </div> 544 `).join(''); 545 } 546 } 547 548 // Update service video/image 549 const serviceVideoSrc = document.getElementById('serviceVideoSrc'); 550 const serviceImageSrc = document.getElementById('serviceImageSrc'); 551 const serviceBannerSlogan = document.getElementById('serviceBannerSlogan'); 552 553 if (serviceVideoSrc && serviceImageSrc) { 554 if (service.video) { 555 // Use video if available 556 const source = serviceVideoSrc.querySelector('source'); 557 if (source) { 558 source.src = service.video; 559 serviceVideoSrc.load(); 560 } 561 serviceVideoSrc.setAttribute('aria-label', service.title); 562 serviceVideoSrc.style.display = 'block'; 563 serviceImageSrc.style.display = 'none'; 564 } else if (service.image) { 565 // Fallback to image if no video 566 serviceImageSrc.src = service.image; 567 serviceImageSrc.alt = service.title; 568 serviceImageSrc.style.display = 'block'; 569 serviceVideoSrc.style.display = 'none'; 570 } 571 } 572 573 // Update banner slogan 574 if (serviceBannerSlogan && service.bannerSlogan) { 575 serviceBannerSlogan.textContent = service.bannerSlogan; 576 serviceBannerSlogan.style.display = 'block'; 577 } else if (serviceBannerSlogan) { 578 serviceBannerSlogan.style.display = 'none'; 579 } 580 581 // Update service description 582 const serviceDetailDescription = document.getElementById('serviceDetailDescription'); 583 if (serviceDetailDescription) { 584 serviceDetailDescription.innerHTML = ` 585 <p>${service.fullDescription}</p> 586 `; 587 } 588 589 // Helper function to check if feature/benefit is object or string 590 const isObject = (item) => typeof item === 'object' && item !== null && !Array.isArray(item) && item.hasOwnProperty('title'); 591 592 // Ensure minimum counts for sections 593 const ensureMinimumItems = (arr, min, type) => { 594 const list = Array.isArray(arr) ? arr.slice() : []; 595 const makeItem = (i) => { 596 if (type === 'feature') { 597 const fallbackFeatures = [ 598 { title: 'Advanced Targeting', description: 'Reach the right audience with precise filters, intent signals, and contextual placements.' }, 599 { title: 'Custom Reporting', description: 'Track KPIs in clear dashboards with weekly/monthly insights your team can act on.' }, 600 { title: 'A/B Testing Framework', description: 'Continuously test creatives, copy, and funnels to improve performance over time.' }, 601 { title: 'Automation Workflows', description: 'Automate routine steps like tagging, routing, and alerts to
601save time.' }, 602 { title: 'Cross-Channel Integration', description: 'Unify data and messaging across web, search, social, and email for consistency.' }, 603 { title: 'Quality Assurance Review', description: 'Pre-launch and ongoing QA to maintain accuracy, speed, and reliability.' } 604 ]; 605 return fallbackFeatures[(i - 1) % fallbackFeatures.length]; 606 } 607 if (type === 'benefit') { 608 const fallbackBenefits = [ 609 { title: 'Lower Cost per Result', description: 'Reduce acquisition costs with better targeting, bids, and creative optimization.' }, 610 { title: 'Higher Conversion Rate', description: 'Improve on-site journeys and ad relevance to lift conversions.' }, 611 { title: 'Improved Lead Quality', description: 'Attract decision-makers and high-intent users more likely to buy.' }, 612 { title: 'Faster Time to Value', description: 'Launch quickly with proven playbooks and iterate based on data.' }, 613 { title: 'Scalable Growth', description: 'Build a foundation that supports higher budgets without performance drop.' }, 614 { title: 'Actionable Insights', description: 'Get clear recommendations backed by analytics and real user behavior.' } 615 ]; 616 return fallbackBenefits[(i - 1) % fallbackBenefits.length]; 617 } 618 const fallbackFaqs = [ 619 { question: 'How long until I see meaningful results?', answer: 'Timelines vary by channel. Paid campaigns show movement in weeks; SEO takes 3â6 months for sustained gains.' }, 620 { question: 'What budget should I start with?', answer: 'We propose an INR-based test budget aligned to goals and industry CPC/CPM, then scale with performance.' }, 621 { question: 'Can you work with our in-house team?', answer: 'Yes. We collaborate with internal teams and share clear roadmaps, tasks, and reporting.' }, 622 { question: 'Do you provide detailed reporting?', answer: 'Absolutely. Expect transparent dashboards and executive summaries with next-step actions.' }, 623 { question: 'Will you sign NDAs and follow compliance?', answer: 'Yes. We adhere to brand, data, and legal guidelines and can sign NDAs on request.' }, 624 { question: 'What makes your approach different?', answer: 'Precision targeting, creative excellence, and iterative optimization focused on measurable outcomes.' }, 625 { question: 'Do you handle landing pages and creatives?', answer: 'We can support strategy, copy, design, and development as needed to improve performance.' }, 626 { question: 'How do we get started?', answer: 'We begin with discovery, align on goals, set metrics, and launch a pilot to validate assumptions.' } 627 ]; 628 return fallbackFaqs[(i - 1) % fallbackFaqs.length]; 629 }; 630 for (let i = list.length + 1; i <= min; i++) list.push(makeItem(i)); 631 return list; 632 }; 633 634 // Update features (show all, ensure at least 6) 635 const serviceFeatures = document.getElementById('serviceFeatures'); 636 const normalizedFeatures = ensureMinimumItems(service.features, 6, 'feature'); 637 if (serviceFeatures && normalizedFeatures.length > 0) { 638 const firstFeature = normalizedFeatures[0]; 639 const useGridLayout = isObject(firstFeature); 640 641 const featuresHTML = normalizedFeatures.map((feature, index) => { 642 if (isObject(feature)) { 643 // Shorten description to max 100 characters 644 const shortDesc = feature.description.length > 100 645 ? feature.description.substring(0, 100) + '...' 646 : feature.description; 647 return ` 648 <div class="feature-item card fade-in" style="animation-delay: ${index * 0.1}s"> 649 <div class="feature-header"> 650 <h4 class="feature-title">${feature.title}</h4> 651 </div> 652 <p class="feature-description">${shortDesc}</p> 653 </div> 654 `; 655 } else { 656 return `<li class="fade-in" style="animation-delay: ${index * 0.1}s">${feature}</li>`; 657 } 658 }).join(''); 659 660 serviceFeatures.innerHTML = ` 661 <h3><span class="text-purple">Key</span> Features</h3> 662 ${useGridLayout ? `<div class="features-hscroll hscroll">${featuresHTML}</div>` : `<ul>${featuresHTML}</ul>`} 663 `; 664 665 // Make sure it's visible 666 serviceFeatures.style.display = 'block'; 667 serviceFeatures.style.opacity = '1'; 668 } else if (serviceFeatures) { 669 serviceFeatures.innerHTML = '<p>Features information coming soon.</p>'; 670 } 671 672 // Update benefits (show all, ensure at least 6) 673 const serviceBenefits = document.getElementById('serviceBenefits'); 674 const normalizedBenefits = ensureMinimumItems(service.benefits, 6, 'benefit'); 675 if (serviceBenefits && normalizedBenefits.length > 0) {
676 const firstBenefit = normalizedBenefits[0]; 677 const useGridLayout = isObject(firstBenefit); 678 679 const benefitsHTML = normalizedBenefits.map((benefit, index) => { 680 if (isObject(benefit)) { 681 // Shorten description to max 100 characters 682 const shortDesc = benefit.description.length > 100 683 ? benefit.description.substring(0, 100) + '...' 684 : benefit.description; 685 return ` 686 <div class="benefit-item card fade-in" style="animation-delay: ${index * 0.1}s"> 687 <div class="benefit-header"> 688 <h4 class="benefit-title">${benefit.title}</h4> 689 </div> 690 <p class="benefit-description">${shortDesc}</p> 691 </div> 692 `; 693 } else { 694 return `<li class="fade-in" style="animation-delay: ${index * 0.1}s">${benefit}</li>`; 695 } 696 }).join(''); 697 698 serviceBenefits.innerHTML = ` 699 <h3><span class="text-purple">Key</span> Benefits</h3> 700 ${useGridLayout ? `<div class="benefits-hscroll hscroll">${benefitsHTML}</div>` : `<ul>${benefitsHTML}</ul>`} 701 `; 702 703 // Make sure it's visible 704 serviceBenefits.style.display = 'block'; 705 serviceBenefits.style.opacity = '1'; 706 } else if (serviceBenefits) { 707 serviceBenefits.innerHTML = '<p>Benefits information coming soon.</p>'; 708 } 709 710 // Update FAQ (show all, ensure at least 8) 711 const serviceFAQ = document.getElementById('serviceFAQ'); 712 const normalizedFaqs = ensureMinimumItems(service.faqs, 8, 'faq'); 713 if (serviceFAQ && normalizedFaqs.length > 0) { 714 // Expand short FAQ answers with clearer guidance 715 const expandAnswer = (question, answer, serviceName) => { 716 const base = String(answer || '').trim(); 717 if (base.length >= 220) return base; 718 719 const q = String(question || '').toLowerCase(); 720 const extra = []; 721 722 if (/(cost|price|pricing|budget|charge)/i.test(q)) { 723 extra.push('We provide a phased estimate in INR that separates media spend from our service fees, with options for monthly retainers or project-based engagements.'); 724 } 725 if (/(how long|result|when|timeline|timeframe|roi)/i.test(q)) { 726 extra.push('For paid channels you will typically see directional results within 2â4 weeks; SEO and organic programs usually take 3â6 months to compound and show strong lift.'); 727 } 728 if (/(report|tracking|analytics|measure|kpi|dashboard)/i.test(q)) { 729 extra.push('You receive a simple dashboard plus a monthly summary highlighting KPIs, insights, and recommended next steps, so decisions are always dataâdriven.'); 730 } 731 if (/(industry|domain|sector|niche)/i.test(q)) { 732 extra.push('Our approach is adaptable across industries; we start with discovery, map target personas, benchmark competitors, and tailor creatives and keywords accordingly.'); 733 } 734 if (/(contract|lock|term|commitment|cancellation)/i.test(q)) { 735 extra.push('Engagements are flexible. Most clients start with a 3âmonth plan to validate impact, then extend based on performance and roadmap.'); 736 } 737 if (/(team|inâhouse|collaborate|work with us|handoff)/i.test(q)) { 738 extra.push('We collaborate seamlessly with inâhouse teams, sharing roadmaps, tasks, and clear ownership to avoid duplication and accelerate delivery.'); 739 } 740 if (/(creative|asset|landing|page|copy|design)/i.test(q)) { 741 extra.push('We can support copy, design, and landing pages. Where you have existing assets, we iterate through structured A/B tests to find winners faster.'); 742 } 743 if (/(start|onboard|next step|how do i)/i.test(q)) { 744 extra.push(`Getting started is simple: book a discovery call, align on goals and KPIs for ${serviceName}, approve the plan and INR budget, and we launch a pilot within days.`); 745 } 746 if (extra.length === 0) { 747 extra.push('We follow a clear process: discovery, strategy, execution, and continuous optimization with transparent communication and measurable outcomes.'); 748 } 749 750 const expanded = `${base} ${extra.join(' ')}`.trim(); 751 return expanded.length > 800 ? expanded.slice(0, 780) + '...' : expanded; 752 }; 753
754 const expandedFaqs = normalizedFaqs.map(f => ({ 755 question: f.question, 756 answer: expandAnswer(f.question, f.answer, service.title) 757 })); 758 759 serviceFAQ.innerHTML = ` 760 <h3><span class="text-purple">Frequently Asked</span> Questions</h3> 761 <div class="faq-container"> 762 ${expandedFaqs.map((faq, index) => ` 763 <div class="faq-item fade-in" style="animation-delay: ${index * 0.1}s"> 764 <div class="faq-question"> 765 <h4>${faq.question}</h4> 766 <span class="faq-icon">+</span> 767 </div> 768 <div class="faq-answer"> 769 <p>${faq.answer}</p> 770 </div> 771 </div> 772 `).join('')} 773 </div> 774 `; 775 776 // Make sure it's visible 777 serviceFAQ.style.display = 'block'; 778 serviceFAQ.style.opacity = '1'; 779 780 // Initialize FAQ accordion after a short delay to ensure DOM is ready 781 setTimeout(() => { 782 initializeFAQ(); 783 }, 100); 784 } else if (serviceFAQ) { 785 serviceFAQ.innerHTML = '<p>FAQ information coming soon.</p>'; 786 } 787 788 // Update sidebar services list 789 const sidebarServicesList = document.getElementById('sidebarServicesList'); 790 if (sidebarServicesList) { 791 // Get other services (exclude current) 792 const otherServices = servicesData.filter(s => s.id !== serviceId).slice(0, 5); 793 794 sidebarServicesList.innerHTML = otherServices.map(s => 795 `<li><a href="${typeof serviceDetailHref === 'function' ? serviceDetailHref(s.id) : 'service-detail.html?service=' + encodeURIComponent(s.id)}">${s.title}</a></li>` 796 ).join(''); 797 } 798 799 // Load related services section 800 loadRelatedServices(service); 801 802 // Ensure content sections are visible 803 const contentSections = document.querySelectorAll('.service-features, .service-benefits, .service-faq'); 804 contentSections.forEach(section => { 805 section.style.display = 'block'; 806 section.style.opacity = '1'; 807 section.style.visibility = 'visible'; 808 }); 809 810 // Add fade-in animation with scroll observer 811 const elements = document.querySelectorAll('.service-detail-main, .service-detail-sidebar'); 812 elements.forEach((el, index) => { 813 el.classList.add('fade-in'); 814 el.style.animationDelay = `${index * 0.2}s`; 815 el.style.opacity = '1'; 816 }); 817 818 // Initialize scroll observer for animations (but don't hide content) 819 const observerOptions = { 820 threshold: 0.1, 821 rootMargin: '0px 0px -50px 0px' 822 }; 823 824 const observer = new IntersectionObserver((entries) => { 825 entries.forEach(entry => { 826 if (entry.isIntersecting) { 827 entry.target.classList.add('visible'); 828 entry.target.style.opacity = '1'; 829 observer.unobserve(entry.target); 830 } 831 }); 832 }, observerOptions); 833 834 elements.forEach(el => observer.observe(el)); 835 836 // Add interactive features to features and benefits lists 837 const listItems = document.querySelectorAll('.service-features li, .service-benefits li'); 838 listItems.forEach((item, index) => { 839 item.style.opacity = '0'; 840 item.style.transform = 'translateX(-20px)'; 841 setTimeout(() => { 842 item.style.transition = 'all 0.4s ease'; 843 item.style.opacity = '1'; 844 item.style.transform = 'translateX(0)'; 845 }, index * 50); 846 847 // Add click interaction 848 item.addEventListener('click', function() { 849 this.style.transform = 'translateX(10px) scale(1.05)'; 850 setTimeout(() => { 851 this.style.transform = 'translateX(0) scale(1)'; 852 }, 200); 853 }); 854 }); 855 856 // Add image zoom effect 857 const serviceImage = document.getElementById('serviceImageSrc'); 858 if (serviceImage) { 859 serviceImage.addEventListener('mouseenter', function() { 860 this.style.transform = 'scale(1.1)'; 861 this.style.transition = 'transform 0.5s ease'; 862 }); 863 864 serviceImage.addEventListener('mouseleave', function() { 865 this.style.transform = 'scale(1)'; 866 }); 867 } 868 869 // Add sidebar card animations 870 const sidebarCards = document.querySelectorAll('.service-sidebar-card'); 871 sidebarCards.forEach((card, index) => { 872 card.classList.add('scale-in'); 873 card.style.animationDelay = `${index * 0.2}s`; 874 observer.observe(card); 875 }); 876 877 // Initialize scroll progress 878 const addScrollProgress = () => { 879 const progressBar = document.querySelector('.scroll-progress'); 880 if (!progressBar) return; 881 882 window.addEventListener('scroll', () => { 883 const windowHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight; 884 const scrolled = (window.pageYOffset / windowHeight) * 100; 885 progressBar.style.width = scrolled + '%'; 886 }); 887 }; 888 889 addScrollProgress(); 890}); 891 892// Load Related Services Section 893function loadRelatedServices(currentService) { 894 const relatedServicesSection = document.getElementById('relatedServicesSection'); 895 if (!relatedServicesSection) return; 896 897 // Get other services with videos only (exclude current) and limit to 6 898 const otherServices = servicesData 899 .filter(s => s.id !== currentService.id && s.video) 900 .slice(0, 6); 901 902 if (otherServices.length === 0) { 903 relatedServicesSection.style.display = 'none'; 904 return; 905 } 906 907 relatedServicesSection.innerHTML = ` 908 <h3 class="related-services-title">
909 <span class="text-purple">Explore</span> Other Services 910 </h3> 911 <div class="related-services-grid"> 912 ${otherServices.map((service, index) => ` 913 <a href="${typeof serviceDetailHref === 'function' ? serviceDetailHref(service.id) : 'service-detail.html?service=' + encodeURIComponent(service.id)}" class="related-service-card fade-in" style="animation-delay: ${index * 0.1}s"> 914 <div class="related-service-image"> 915 ${service.video ? ` 916 <video autoplay loop muted playsinline> 917 <source src="${service.video}" type="video/mp4"> 918 </video> 919 ` : service.image ? ` 920 <img src="${service.image}" alt="${service.title}"> 921 ` : ''} 922 </div> 923 <div class="related-service-content"> 924 <h4 class="related-service-name">${service.title}</h4> 925 <p class="related-service-description">${service.shortDescription}</p> 926 <span class="related-service-link">Learn More â</span> 927 </div> 928 </a> 929 `).join('')} 930 </div> 931 <div class="services-cta-actions" style="margin-top: 28px;"> 932 <a href="services.html" class="services-cta-button">Explore more services</a> 933 </div> 934 `; 935 936 // Make sure it's visible 937 relatedServicesSection.style.display = 'block'; 938 relatedServicesSection.style.opacity = '1'; 939} 940 941// FAQ Accordion Functionality 942function initializeFAQ() { 943 const faqItems = document.querySelectorAll('.faq-item'); 944 945 faqItems.forEach(item => { 946 const question = item.querySelector('.faq-question'); 947 const answer = item.querySelector('.faq-answer'); 948 const icon = item.querySelector('.faq-icon'); 949 950 // Set initial state 951 answer.style.maxHeight = '0'; 952 answer.style.opacity = '0'; 953 item.classList.remove('active'); 954 955 question.addEventListener('click', () => { 956 const isActive = item.classList.contains('active'); 957 958 // Close all other FAQs 959 faqItems.forEach(otherItem => { 960 if (otherItem !== item) { 961 otherItem.classList.remove('active'); 962 const otherAnswer = otherItem.querySelector('.faq-answer'); 963 const otherIcon = otherItem.querySelector('.faq-icon'); 964 otherAnswer.style.maxHeight = '0'; 965 otherAnswer.style.opacity = '0'; 966 otherIcon.textContent = '+'; 967 otherIcon.style.transform = 'rotate(0deg)'; 968 } 969 }); 970 971 // Toggle current FAQ 972 if (isActive) { 973 item.classList.remove('active'); 974 answer.style.maxHeight = '0'; 975 answer.style.opacity = '0'; 976 icon.textContent = '+'; 977 icon.style.transform = 'rotate(0deg)'; 978 } else { 979 item.classList.add('active'); 980 answer.style.maxHeight = answer.scrollHeight + 'px'; 981 answer.style.opacity = '1'; 982 icon.textContent = 'â'; 983 icon.style.transform = 'rotate(180deg)'; 984 } 985 }); 986 }); 987}
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.