From f1f66f9c5c446eea8f60cf0531c8e06138232f65 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Thu, 18 Jun 2026 18:51:43 +0300 Subject: [PATCH 01/11] feat(promo-banner): rotating two-slide announcement carousel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the single static promo strip with a crossfading carousel: - Two announcement slides crossfade (CSS opacity) with ‹ › manual controls and a 6s auto-rotate; slides whose target is the current page are filtered out so the banner never self-promotes. - Jump-free layout: both slides share one auto-sized grid cell (grid-area 1/1) with a fixed-width right-aligned badge slot, so the badge and message stay at a fixed x across the crossfade. - Graceful degradation: minmax(0,max-content) track + message ellipsis so a too-long slide shrinks instead of clipping on narrow desktop. - A11y: visually-hidden role="status" aria-live region announces the active slide on manual nav (silent during autoplay to avoid a chatty live region); reduced-motion disables autoplay; ground-truth hover/focus pause state so autoplay can't get stuck off. - Mobile keeps the wrapping, full-width single-slide layout. --- src/components/PromoBanner.astro | 421 +++++++++++++++++++++++++++---- 1 file changed, 368 insertions(+), 53 deletions(-) diff --git a/src/components/PromoBanner.astro b/src/components/PromoBanner.astro index 4ebf82d91..618942364 100644 --- a/src/components/PromoBanner.astro +++ b/src/components/PromoBanner.astro @@ -1,45 +1,200 @@ --- -// Site-wide promo strip for the AI Solution Creator campaign. Shared by marketing -// pages (BaseLayout) and docs (starlight/Header). Hidden on the page it links to. -// Relative URL → stays on the current host; UTM params kept for tracking. -const HREF = '/blog/ai-solution-creator/?utm_source=tb&utm_medium=bnr&utm_campaign=ASC'; +import { Icon } from 'astro-icon/components'; -const TARGET_PATH = '/blog/ai-solution-creator'; -const showBanner = Astro.url.pathname.replace(/\/+$/, '') !== TARGET_PATH; +// Site-wide promo carousel. Two announcement slides that crossfade (one fades out as +// the next fades in over the same spot — all motion is CSS) with ‹ › manual controls +// and a 6s auto-rotate. Shared by marketing (BaseLayout) and docs (starlight/Header). +// A slide whose own target page is the current page is dropped, so the banner never +// self-promotes the page you're already reading. Relative URLs keep the current host. +const SLIDES = [ + { + href: '/blog/thingsboard-cli-for-ai-driven-iot-development/?utm_source=tb&utm_medium=bnr&utm_campaign=cli', + target: '/blog/thingsboard-cli-for-ai-driven-iot-development', + badge: 'NEW', + // Plain text for the link's accessible name. + label: 'ThingsBoard CLI: build your IoT solution with AI Coding agents', + // Display markup (keeps the bold lead-in); rendered with set:html. + html: 'ThingsBoard CLI: build your IoT solution with AI Coding agents', + }, + { + href: '/blog/ai-solution-creator/?utm_source=tb&utm_medium=bnr&utm_campaign=ASC', + target: '/blog/ai-solution-creator', + badge: 'AI FEATURE', + label: 'AI Solution Creator — get a working IoT prototype in 10 minutes', + html: 'AI Solution Creator — get a working IoT prototype in 10 minutes', + }, +]; + +const current = Astro.url.pathname.replace(/\/+$/, ''); +const slides = SLIDES.filter((s) => s.target !== current); +const showBanner = slides.length > 0; +const hasSwitcher = slides.length > 1; --- { showBanner && ( - - - - NEW - - AI Solution Creator — get a working IoT prototype in 10 minutes - +
+ {slides.map((s, i) => ( + + + + + {s.badge} + + + + + + ))} + + {hasSwitcher && ( +
+ + +
+ )} +
+ {hasSwitcher && ( + /* Announces the active slide to screen readers (controls give no other feedback). */ + + )} + ) } { - /* On the banner's own page: zero --promo-h so the offset CSS leaves no gap. */ + /* No slide to show (e.g. all targets matched the current page): zero --promo-h. */ !showBanner && From 356a86de40aeb496de85a3687051be8cc98a2f68 Mon Sep 17 00:00:00 2001 From: Dmytro Khylko <55889080+DmytroKhylko@users.noreply.github.com> Date: Fri, 19 Jun 2026 11:44:47 +0300 Subject: [PATCH 02/11] Update Trendz landing page (#479) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [WIP]: New Trendz landing page * [WIP]: trendz landing page: first screen, contact modal * [WIP]: feat(trendz): add HowIotImprovesBusinessSection + contact form fixes - New accordion section with 6 items: desktop shows sticky right panel with image/text fade transitions; mobile/tablet shows inline panel as a separate rounded #f4f8fe box below the chips box (16px gap between) - Accordion scroll-jump fix: compensate viewport shift when a new item opens and the previously active one collapses above it - ProjectScreenFrame: add adjustable frontInset/middleInset/backInset props; use overflow:hidden + padding-top on screen-wrap to contain decorative border overflow in the inline panel context - Responsive typography: section padding 32px/100px (xs/sm+), title h2→h3 at xs, accordion title h3→h5-medium at xs, body body-s→body-xs at xs; add trendz-h5-medium mixin (20px/500/28px/0.249px) - TrendzContactModal: add missing client_id and fpr hidden inputs so existing JS tracking logic can actually submit them; randomize honeypot field name on every modal open * [WIP]: fix(trendz): accordion scroll behaviour on mobile and desktop - Mobile: on item open, smooth-scroll the item to just below the fixed header; offset reads --header-height CSS custom property (80px) + 8px gap so the header never clips the accordion title - Desktop: activate only, no scroll side-effect — avoids the unwanted page jump when selecting lower accordion items * [WIP]: feat(trendz): add MetricExplorerSection + accordion semantic and style fixes - New MetricExplorerSection: two-column layout (row ≥1280px, column below), YouTube embed via YouTubeVideo component (youtube-nocookie.com) - Accordion h3 semantics: accordion titles promoted from to

wrapping the + \ No newline at end of file + diff --git a/src/components/Trendz/DeploymentOptionsSection.astro b/src/components/Trendz/DeploymentOptionsSection.astro index 05b355163..f1ae74f00 100644 --- a/src/components/Trendz/DeploymentOptionsSection.astro +++ b/src/components/Trendz/DeploymentOptionsSection.astro @@ -1,37 +1,61 @@ --- -const options = [ +import iconPrivateCloud from '~/assets/images/landings/trendz/icon-privat-cloud.svg?raw'; +import iconCloud from '~/assets/images/landings/trendz/icon-cloud.svg?raw'; +import iconTrendz from '~/assets/images/landings/trendz/icon-trendz.svg?raw'; + +const cards = [ { - title: 'Trendz Cloud', - text: 'Upgrade your plan to gain deeper insights into your data', - linkText: 'Upgrade your ThingsBoard Plan', - href: 'https://thingsboard.cloud/billing', + icon: iconPrivateCloud, + title: 'Trendz for Private Cloud', + description: + 'Get full access to Metric Explorer, Anomaly Detection, Predictions, and more – all directly inside your ThingsBoard Private Cloud.', + pricingHref: '/pricing/?section=thingsboard-pe-options&product=thingsboard-private-cloud', + enableHref: '/docs/trendz/activation/private-cloud/', }, { - title: 'Trendz EU Cloud', - text: 'Unlock powerful analytics tools by upgrading your plan', - linkText: 'Upgrade your ThingsBoard EU Plan', - href: 'https://eu.thingsboard.cloud/billing', + icon: iconCloud, + title: 'Trendz for Public Cloud', + description: + 'Seamlessly activate Trendz on your ThingsBoard Cloud and start exploring telemetry, building metrics, and detecting anomalies with no code.', + pricingHref: '/pricing/?section=thingsboard-pe-options&product=thingsboard-cloud', + enableHref: '/docs/trendz/activation/public-cloud/', }, { - title: 'Trendz Self-Hosted', - text: 'Use our step-by-step guide to install Trendz Analytics to your server', - linkText: 'Install Trendz to your server', - href: '/docs/trendz/installation/', + icon: iconTrendz, + title: 'Trendz for Self-Hosted', + description: + 'Integrate the full AI-driven Trendz experience on your server. Activate your add-on and unlock analytics, predictions, anomaly detection, and more.', + pricingHref: '/pricing/?section=thingsboard-pe-options&product=thingsboard-pe', + enableHref: '/docs/trendz/activation/self-managed/', }, ]; --- -
-
-
+
+
+
+

How to Run Trendz for Efficient Data Analytics in IoT

+

+ We provide true deployment freedom designed to match your main platform license. Find the configuration that + corresponds to your current plan below. +

+
+ +
{ - options.map((opt) => ( -
-
{opt.title}
-

{opt.text}

- - {opt.linkText} - + cards.map((card) => ( +
+
+

{card.title}

+

{card.description}

+
)) } @@ -40,142 +64,159 @@ const options = [
diff --git a/src/components/Trendz/FAQSection.astro b/src/components/Trendz/FAQSection.astro new file mode 100644 index 000000000..2fcaf02d3 --- /dev/null +++ b/src/components/Trendz/FAQSection.astro @@ -0,0 +1,401 @@ +--- +const categories = [ + { + id: 'understanding', + label: 'Understanding IoT Analytics & Business Value', + items: [ + { + id: 'q-what-is', + question: 'What is IoT analytics and how does it differ from standard visualization?', + answer: + 'IoT analytics is the process of converting raw sensor data into meaningful business insights. While standard dashboards show what is happening right now, IoT analytics helps you understand why it is happening and predicts what will happen next using statistical functions and calculated fields.', + }, + { + id: 'q-why-need', + question: 'Why do we need IoT analytics solutions if we already have ThingsBoard?', + answer: + 'ThingsBoard is excellent for real-time monitoring and device management. Trendz Analytics complements this by serving as one of the most powerful IoT analytics solutions available, adding model-driven analytics like anomaly detection, health scoring, and complex KPI modeling that basic dashboards cannot perform.', + }, + { + id: 'q-who-offers', + question: 'Who offers real-time IoT data analytics tools?', + answer: + 'While many cloud providers offer generic tools, Trendz Analytics is specifically designed for real-time IoT data analytics within the ThingsBoard ecosystem. It processes incoming telemetry instantly, allowing teams to generate reports and trigger automated workflows without the delay of transferring data to external third-party clouds.', + }, + ], + }, + { + id: 'predictive', + label: 'Predictive Maintenance & Forecasting', + items: [ + { + id: 'q-predictive', + question: 'Can Trendz be used as predictive maintenance software?', + answer: + 'Yes, Trendz is a comprehensive predictive maintenance software tool. It uses historical data to identify early signs of equipment degradation, allowing you to schedule repairs before a failure occurs, which significantly reduces downtime and maintenance costs.', + }, + { + id: 'q-forecasting', + question: 'How does Trendz function as forecasting software?', + answer: + 'Trendz acts as robust forecasting software by using built-in Machine Learning (ML) models to project future trends. You can predict energy consumption, future system loads, or the remaining useful life of an asset based on past telemetry patterns.', + }, + { + id: 'q-accuracy', + question: 'How accurate is data analytics in IoT for forecasting?', + answer: + 'The accuracy of data analytics in IoT depends on the stability of your telemetry and the amount of historical data available to establish baselines. Trendz allows you to validate these models against real-world outcomes to ensure your forecasts are highly reliable for planning.', + }, + ], + }, + { + id: 'integration', + label: 'Integration & Technical Implementation', + items: [ + { + id: 'q-licensing', + question: 'How is Trendz licensed and priced?', + answer: + 'Trendz is a separate add-on product by ThingsBoard and is charged as an add-on in the scope of the main ThingsBoard license. Pricing depends on license type and deployment model — public/private Cloud, self-hosted, or perpetual license.', + }, + { + id: 'q-data', + question: 'What data is required to start with IoT data analytics?', + answer: + 'At a minimum, you need stable telemetry keys and an asset structure in ThingsBoard. To get the most out of IoT data analytics, such as health scoring or predictions, you need enough historical data to establish a baseline for the ML models.', + }, + { + id: 'q-complex', + question: 'How does Trendz simplify IoT analytics for complex systems?', + answer: + 'Trendz automates much of the IoT analytics process through "Topology Discovery," which automatically learns your device and asset relationships from ThingsBoard. This allows you to build complex KPI models and Metric Explorers without manually re-mapping your entire network.', + }, + { + id: 'q-integrate', + question: 'How to integrate Trendz with ThingsBoard and external services?', + answer: + "Trendz is a ThingsBoard add-on and is designed to work with ThingsBoard telemetry and the device/entity model you already have. Optional external context (such as weather or business system inputs) and workflow integrations (ticketing/CMMS/work orders, etc.) are added using ThingsBoard's built-in Integrations and Rule Engine.", + }, + { + id: 'q-sso', + question: 'Do you support SSO, RBAC, and auditing for IoT analytics?', + answer: + 'Yes, Trendz is a native add-on that works within the ThingsBoard identity and access model. Your existing SSO and RBAC settings will apply to your IoT analytics dashboards, ensuring that data remains secure and auditable.', + }, + ], + }, +]; +--- + +
+
+

Frequently asked questions

+ +
+ { + categories.map((cat, ci) => ( +
+ + + +
+ )) + } +
+
+
+ + + + diff --git a/src/components/Trendz/FeatureBlocksSection.astro b/src/components/Trendz/FeatureBlocksSection.astro index 37d986bb1..d108d76c7 100644 --- a/src/components/Trendz/FeatureBlocksSection.astro +++ b/src/components/Trendz/FeatureBlocksSection.astro @@ -1,41 +1,94 @@ --- import { getImage } from 'astro:assets'; -const imgPredictScreen = await getImage({ src: (await import('/src/assets/images/landings/trendz/predict-screen.png')).default, width: 651, quality: 85 }); -const imgPredictScreen440 = await getImage({ src: (await import('/src/assets/images/landings/trendz/predict-screen.png')).default, width: 440, quality: 85 }); -const imgAnomaliesScreen = await getImage({ src: (await import('/src/assets/images/landings/trendz/anomalies-screen.png')).default, width: 651, quality: 85 }); -const imgAnomaliesScreen440 = await getImage({ src: (await import('/src/assets/images/landings/trendz/anomalies-screen.png')).default, width: 440, quality: 85 }); -const imgDashboardScreen = await getImage({ src: (await import('/src/assets/images/landings/trendz/dashboard-screen.png')).default, width: 651, quality: 85 }); -const imgMultipleDonut = await getImage({ src: (await import('/src/assets/images/landings/trendz/multiple-donut.png')).default, quality: 85 }); -const imgLineChart = await getImage({ src: (await import('/src/assets/images/landings/trendz/line-chart.png')).default, quality: 85 }); -const imgPieChart = await getImage({ src: (await import('/src/assets/images/landings/trendz/pie-chart.png')).default, quality: 85 }); -const imgDonutChart = await getImage({ src: (await import('/src/assets/images/landings/trendz/donut-chart.png')).default, quality: 85 }); -const imgSphere = await getImage({ src: (await import('/src/assets/images/landings/trendz/sphere.png')).default, quality: 85 }); -const imgBars = await getImage({ src: (await import('/src/assets/images/landings/trendz/bars.png')).default, quality: 85 }); +const imgPredictScreen = await getImage({ + src: (await import('/src/assets/images/landings/trendz/predict-screen.png')).default, + width: 651, + quality: 85, +}); +const imgPredictScreen440 = await getImage({ + src: (await import('/src/assets/images/landings/trendz/predict-screen.png')).default, + width: 440, + quality: 85, +}); +const imgAnomaliesScreen = await getImage({ + src: (await import('/src/assets/images/landings/trendz/anomalies-screen.png')).default, + width: 651, + quality: 85, +}); +const imgAnomaliesScreen440 = await getImage({ + src: (await import('/src/assets/images/landings/trendz/anomalies-screen.png')).default, + width: 440, + quality: 85, +}); +const imgDashboardScreen = await getImage({ + src: (await import('/src/assets/images/landings/trendz/dashboard-screen.png')).default, + width: 651, + quality: 85, +}); +const imgMultipleDonut = await getImage({ + src: (await import('/src/assets/images/landings/trendz/multiple-donut.png')).default, + quality: 85, +}); +const imgLineChart = await getImage({ + src: (await import('/src/assets/images/landings/trendz/line-chart.png')).default, + quality: 85, +}); +const imgPieChart = await getImage({ + src: (await import('/src/assets/images/landings/trendz/pie-chart.png')).default, + quality: 85, +}); +const imgDonutChart = await getImage({ + src: (await import('/src/assets/images/landings/trendz/donut-chart.png')).default, + quality: 85, +}); +const imgSphere = await getImage({ + src: (await import('/src/assets/images/landings/trendz/sphere.png')).default, + quality: 85, +}); +const imgBars = await getImage({ + src: (await import('/src/assets/images/landings/trendz/bars.png')).default, + quality: 85, +}); ---
-

Predict failures and forecast utilization

- predict screen + predict screen

- For better decision making, resource planning and reducing cost business requires answers - to 3 main questions: What will happen, When, and Why? + For better decision making, resource planning and reducing cost business requires answers to 3 main questions: + What will happen, When, and Why?

Trendz provides an answer

- Start Analysis + Start Analysis
- predict screen + predict screen
@@ -47,16 +100,19 @@ const imgBars = await getImage({ src: (await import('/src/assets/images/landings

Define KPI using calculated fields

- Calculated fields are one of the most powerful features for KPI monitoring and prediction. - Based on the input data, calculated fields allow you to run statistical functions and - create new data items by applying calculations. + Calculated fields are one of the most powerful features for KPI monitoring and prediction. Based on the input + data, calculated fields allow you to run statistical functions and create new data items by applying + calculations.

Learn More about calculated fields
-
+
@@ -71,21 +127,35 @@ const imgBars = await getImage({ src: (await import('/src/assets/images/landings

Detection Anomalies

- anomalies screen + anomalies screen

- Detect anomalies with automated tools based on built-in machine learning algorithms. - Prioritise them and focus on real problems with anomaly scoring. + Detect anomalies with automated tools based on built-in machine learning algorithms. Prioritise them and focus + on real problems with anomaly scoring.

- Start Analysis + Start Analysis
- anomalies screen + anomalies screen
@@ -96,19 +166,20 @@ const imgBars = await getImage({ src: (await import('/src/assets/images/landings

Connect Data

+

Connect Trendz to the ThingsBoard in few clicks with automatic Topology Discovery.

- Connect Trendz to the ThingsBoard in few clicks with automatic Topology Discovery. -

-

- Trendz works with all ThingsBoard products, including Open Source ThingsBoard Community - Edition and ThingsBoard Professional Edition. + Trendz works with all ThingsBoard products, including Open Source ThingsBoard Community Edition and + ThingsBoard Professional Edition.

Learn More about connecting ThingsBoard
-
+
@@ -123,7 +194,14 @@ const imgBars = await getImage({ src: (await import('/src/assets/images/landings

Share securely

- dashboard screen + dashboard screen
Share visualized insights with your users by: @@ -140,7 +218,14 @@ const imgBars = await getImage({ src: (await import('/src/assets/images/landings
- dashboard screen + dashboard screen
@@ -152,15 +237,11 @@ const imgBars = await getImage({ src: (await import('/src/assets/images/landings

Plot and aggregate your data with any granularity

- See your data, like total resource consumption on any levels starting from country level - and deep dive into concrete meter level. Clear dataset in real-time by grouping and - filtering on dimensions that you are interested in. + See your data, like total resource consumption on any levels starting from country level and deep dive into + concrete meter level. Clear dataset in real-time by grouping and filtering on dimensions that you are + interested in.

- Start Analysis + Start Analysis
@@ -727,10 +808,8 @@ const imgBars = await getImage({ src: (await import('/src/assets/images/landings } }); }, - { threshold: 0.25 }, + { threshold: 0.25 } ); - document - .querySelectorAll('.trendz-features .main-bg') - .forEach((block) => observer.observe(block)); + document.querySelectorAll('.trendz-features .main-bg').forEach((block) => observer.observe(block)); diff --git a/src/components/Trendz/HeroSection.astro b/src/components/Trendz/HeroSection.astro index 40157d0c6..24db4133c 100644 --- a/src/components/Trendz/HeroSection.astro +++ b/src/components/Trendz/HeroSection.astro @@ -1,66 +1,76 @@ --- import { getImage } from 'astro:assets'; - -const heroImg = await getImage({ src: (await import('/src/assets/images/landings/trendz/hero-img.png')).default, width: 500, quality: 85 }); -const sphereImg = await getImage({ src: (await import('/src/assets/images/landings/trendz/sphere.png')).default, quality: 85 }); +import ProjectScreenFrame from '../Services/ProjectScreenFrame.astro'; +import TrendzChip from './TrendzChip.astro'; +const sphereImg = await getImage({ + src: (await import('/src/assets/images/landings/trendz/sphere.png')).default, + quality: 85, +}); ---
-

Trendz Analytics Platform

-

Driving more revenue with IoT Data Analytics

-

Turn data into insights and make better decisions

+

+ + The AI-Powered + IoT Data Analytics Workspace +

+

+ Trendz Analytics is an add-on for ThingsBoard that turns telemetry into business KPIs and actionable insights. +

- Get a demoTalk to an Expert
Get started + Activate Trendz in ThingsBoard +
-
- Trendz Analytics dashboard with predictive IoT insights -
+ + +
- -
-
-
-
-
\ No newline at end of file + diff --git a/src/components/Trendz/HowIotImprovesBusinessSection.astro b/src/components/Trendz/HowIotImprovesBusinessSection.astro new file mode 100644 index 000000000..ea8ad9cdb --- /dev/null +++ b/src/components/Trendz/HowIotImprovesBusinessSection.astro @@ -0,0 +1,564 @@ +--- +import ProjectScreenFrame from '../Services/ProjectScreenFrame.astro'; +const kpiImgUrl = '/products/trendz/turning-telemetry-into-clear-kpis.webp'; +const forecastImgUrl = '/products/trendz/forecasting-whats-likely-to-happen-next.webp'; +const anomalyImgUrl = '/products/trendz/anomaly-detection-for-quick-reaction.webp'; +const utilizationImgUrl = '/products/trendz/utilization-and-state-analysis.webp'; +const predictiveImgUrl = '/products/trendz/predictive-maintenance-and-health-scoring.webp'; +const outliersImgUrl = '/products/trendz/find-outliers-across-a-fleet.webp'; + +const items = [ + { + id: 'kpi', + title: 'Turning telemetry into clear KPIs', + description: + 'Turn raw sensor data into clear numbers everyone can use — cost, efficiency, output, quality — the same way across every site and customer.', + examples: ['Energy per unit', 'Cost per hour', 'Downtime minutes', 'Quality %', 'CO₂ estimate'], + imageSrc: kpiImgUrl, + imageAlt: 'KPI dashboard showing fleet energy and cost data across sites', + featureText: + 'Trendz helps you define a few "business metrics" on top of your ThingsBoard data. Once a KPI is defined, you can reuse it everywhere: dashboards, portfolio views, alerts, and reports.', + featureChips: [ + 'Create KPI formulas for device and asset profiles', + 'Compare sites/assets using the same definition', + 'Create Operational reports using KPIs', + ], + }, + { + id: 'forecasting', + title: "Forecasting what's likely to happen next", + description: + 'Forecast the next days/weeks so you can plan work before problems, high-run-outs, threshold breaches, and KPI drift.', + examples: ['Tank empty in ~10 days', 'Temperature likely to go out of range tonight', 'Spend trending over plan'], + imageSrc: forecastImgUrl, + imageAlt: 'Forecast charts showing future sensor data with risk ranges', + featureText: + 'Trendz forecasts your charts into the future and verifies the accuracy of predictions. That makes it practical for operations: you don\'t just see "it will happen", you see when it might happen and how risky it is.', + featureChips: [ + 'Future curve with a risk range', + 'Time-to-threshold alerts', + 'Turn the forecast into an alert/incident', + ], + }, + { + id: 'predictive', + title: 'Predictive maintenance and health scoring', + description: + 'See which assets are getting worse over time, so you can service them at the right moment — before failures and before waste becomes expensive.', + examples: ['Longer cool-down', 'Rising vibration', 'Higher energy for the same output'], + imageSrc: predictiveImgUrl, + imageAlt: 'Predictive maintenance health score list and asset degradation chart', + featureText: + 'Trendz tracks how an asset performs over time and compares it to what "good" looks like for that asset or similar assets. When health declines, you can find when it started, review evidence charts, and trigger a maintenance incident.', + featureChips: [ + 'Simple health score over time', + 'Baseline vs current behavior', + 'Maintenance triggers when thresholds are crossed', + ], + }, + { + id: 'anomaly', + title: 'Anomaly detection for quick reaction', + description: + 'Get a clear signal when something starts behaving unusually, without drowning in noisy alarms, especially where static thresholds miss the real problem.', + examples: [ + 'Energy suddenly jumps', + 'Vibration pattern changes', + 'Temperature becomes unstable', + 'Output drops for the same input', + ], + imageSrc: anomalyImgUrl, + imageAlt: 'Anomaly detection fleet heatmap and time series comparison chart', + featureText: + 'Some issues don\'t have a clean rule like "over 80 = bad". Trendz can flag when behavior changes from normal and mark the moment it changed, so investigation starts from a real timestamp, not guesses.', + featureChips: [ + 'Anomaly timeline with behavior changes', + 'Before vs. after comparison view', + 'Faster triage with less noise', + ], + }, + { + id: 'outliers', + title: 'Find outliers across a fleet', + description: + 'Rank assets and sites that behave differently than their peers, so you can focus on the few that drive most cost and incidents.', + examples: [ + 'One machine uses more energy per unit than others', + 'One building spends more for the same size', + 'One pump is inefficient vs the rest', + ], + imageSrc: outliersImgUrl, + imageAlt: 'Fleet outlier ranking list and peer comparison charts', + featureText: + "Trendz compares similar assets and surfaces the ones that stand out — worst efficiency, highest cost, most downtime, slowest recovery. Start from a ranked list, then drill down to see why it's different using clear visuals.", + featureChips: ['Ranked outlier list by KPI', 'Peer comparison visual proof', 'Drilldown to root patterns'], + }, + { + id: 'utilization', + title: 'Utilization and state analysis', + description: + 'Measure how long assets spend underused, optimal, overloaded, or out-of-control — then use that for capacity planning, SLA reporting, and operational improvements.', + examples: ['Too much idle time', 'Frequent overload periods', 'Temperature out of range during peaks'], + imageSrc: utilizationImgUrl, + imageAlt: 'Utilization dashboard with SLA compliance metrics and weekly heatmap', + featureText: + 'Trendz turns operating states into simple percentages and timelines, so you can spot bottlenecks and recurring waste. Calendar-style views make patterns obvious (after hours, weekends, shift changes) and help teams connect issues to real operations.', + featureChips: ['Time-in-state KPIs', 'Hour-of-week heatmap pattern', 'Capacity and SLA proof'], + }, +]; +--- + +
+

Explore how IoT Analytics can Improve Your Business

+ +
+
+ { + items.map((item, i) => ( +
+

+ +

+ + +
+ )) + } +
+ +
+
+ { + items.map((item, i) => ( +
+ +
+ )) + } +
+
+ { + items.map((item, i) => ( +
+

{item.featureText}

+
+ {item.featureChips.map((chip) => ( +
{chip}
+ ))} +
+
+ )) + } +
+ Talk to an Expert +
+
+
+ + + + diff --git a/src/components/Trendz/MetricExplorerSection.astro b/src/components/Trendz/MetricExplorerSection.astro new file mode 100644 index 000000000..b28426bae --- /dev/null +++ b/src/components/Trendz/MetricExplorerSection.astro @@ -0,0 +1,114 @@ +--- +import YouTubeVideo from '../YouTubeVideo.astro'; +--- + +
+
+
+

Elevate Your IoT Data Analytics with Metric Explorer

+

+ This is your no-code engine for deep data analytics in IoT. Explore telemetry, slice data in seconds, and reveal + hidden patterns using AI-assisted tools. Build complex business logic and metrics instantly — without writing a + single line of code. +

+ More about Metric Explorer +
+ +
+ +
+
+
+ + diff --git a/src/components/Trendz/TopFeaturesSection.astro b/src/components/Trendz/TopFeaturesSection.astro index 2a092324a..740273b3c 100644 --- a/src/components/Trendz/TopFeaturesSection.astro +++ b/src/components/Trendz/TopFeaturesSection.astro @@ -1,32 +1,160 @@ --- -const features = [ +import iconCalculation from '~/assets/images/landings/trendz/icon-calculation.svg?raw'; +import iconAnomaly from '~/assets/images/landings/trendz/icon-anomaly.svg?raw'; +import iconPrediction from '~/assets/images/landings/trendz/icon-prediction.svg?raw'; +import iconAi from '~/assets/images/landings/trendz/icon-ai.svg?raw'; +import iconMetricExplorer from '~/assets/images/landings/trendz/icon-metric-explorer.svg?raw'; +import iconCpu from '~/assets/images/landings/trendz/icon-cpu.svg?raw'; +import iconChartBar from '~/assets/images/landings/trendz/icon-chart-bar.svg?raw'; +import iconTreeStructure from '~/assets/images/landings/trendz/icon-tree-structure.svg?raw'; +import iconWebhooks from '~/assets/images/landings/trendz/icon-webhooks.svg?raw'; + +const cards = [ + { + icon: iconCalculation, + title: 'Calculated Fields', + subtitle: 'Business Logic & KPI Builder', + items: [ + 'Create KPIs, derived metrics, conditional formulas, and logic blocks', + 'Centralize logic and reuse calculations across views and dashboards', + 'Validate results instantly on sample data', + 'Save any calculation to ThingsBoard telemetry for automation', + ], + href: '/docs/trendz/calculations/overview/', + }, + { + icon: iconAnomaly, + title: 'Anomaly Detection', + subtitle: 'Automated Monitoring & Deviations Tracking', + items: [ + 'Identify unusual behavior, performance drops, drifts, and spikes', + 'Use ready-made algorithms or customize thresholds and conditions', + 'Visualize anomalies inside Trendz or save them to ThingsBoard', + 'Trigger ThingsBoard alarms for real-time reactions', + ], + href: '/docs/trendz/anomaly/overview/', + }, + { + icon: iconPrediction, + title: 'IoT Predictive Analytics', + subtitle: 'Forecasting & Future Behavior Insights', + items: [ + 'Predict failures, loads, consumption, or performance KPIs', + 'Validate accuracy with real vs predicted comparisons', + 'View long- and short-term forecasts instantly', + 'Save predictions to ThingsBoard to drive preventive maintenance dashboards', + ], + href: '/docs/trendz/prediction/', + }, + { + icon: iconAi, + title: 'AI Analytics', + subtitle: 'Natural Language Analytics & Auto-Generation', + items: [ + 'Ask questions in plain language and get instant analytical answers', + 'Generate formulas, KPIs, and metrics by description', + 'Modify existing logic with AI suggestions', + 'Ideal for rapid prototyping and quick investigations', + ], + href: '/docs/trendz/ai-assistance-overview/', + }, + { + icon: iconMetricExplorer, + title: 'Data Aggregation', + subtitle: 'Scalable Aggregates & Time-Based Summaries', + items: [ + 'Convert millions of telemetry points into clear summaries', + 'Aggregate hourly, daily, weekly, or with custom intervals', + 'Power reports, performance KPIs, and trend dashboards', + 'Use aggregated data directly in Trendz visualizations, dashboards, and logic', + ], + href: '/docs/trendz/telemetry-aggregation/', + }, { - title: 'Anomaly detection', - text: 'Find and address issues that require immediate attention before they become a problem.', + icon: iconCpu, + title: 'Device States', + subtitle: 'Context-Aware Device Behavior Classification', + items: [ + 'Define operating modes, quality levels, statuses, or health states', + 'Transform raw telemetry into clear, human-readable state labels', + 'Use states to enrich Trendz analytics, comparisons, KPIs, and dashboards', + 'Visualize state transitions in Trendz Views and combine them with other metrics', + ], + href: '/docs/trendz/states/', }, { - title: 'Forecasting', - text: 'Plan and optimize operations with insights into future events and system behavior.', + icon: iconChartBar, + title: 'IoT Data Visualization', + subtitle: 'Interactive Data Investigation Tools', + items: [ + 'Instantly explore telemetry with zoom, filters, breakdowns, and overlays', + 'Compare multiple metrics, assets, or devices side-by-side', + 'Highlight patterns, correlations, and anomalies visually', + 'Use visual tools as a starting point before building KPIs or models', + ], + href: '/docs/trendz/visualizations-overview/', }, { - title: 'Predictive maintenance', - text: 'Identify when a machine is likely to fail, and take preventive measures to avoid downtime', + icon: iconTreeStructure, + title: 'What-If Simulations', + subtitle: 'Scenario Testing with Calculated Fields', + items: [ + 'Change input parameters to see how KPIs or metrics would react', + 'Test best-case, worst-case, or custom operational scenarios', + 'Validate business assumptions without affecting real data', + 'Use simulations to prepare decisions, budgets, or maintenance strategies', + ], + href: null, }, { - title: 'AI Assistant', - text: 'Chat with your data to get instant, AI-driven insights.', + icon: iconWebhooks, + title: 'Optimization Engine', + subtitle: 'Smart Formula-Based Optimization', + items: [ + 'Optimize KPIs such as efficiency, cost, consumption, or performance', + 'Automatically compute the best parameter combination', + 'Use constraints and conditions to keep scenarios realistic', + 'Ideal for process tuning, energy optimization, and resource planning', + ], + href: null, }, ]; ---
-
-
+
+
+

Comprehensive IoT Analytics Solutions for Your Business

+

+ A complete ecosystem for IoT data analytics. Leverage automated insights and custom reporting to stay ahead in a + connected world +

+
+ +
{ - features.map((f) => ( -
-

{f.title}

-

{f.text}

+ cards.map((card) => ( +
+
+ +

{card.title}

+
+
+

{card.subtitle}

+
    + {card.items.map((item) => ( +
  • {item}
  • + ))} +
+ {card.href ? ( + + Read more about {card.title} + + ) : ( + Coming Soon + )} +
)) } @@ -34,96 +162,248 @@ const features = [
+ + diff --git a/src/components/Trendz/TrendzChip.astro b/src/components/Trendz/TrendzChip.astro new file mode 100644 index 000000000..3be594a0d --- /dev/null +++ b/src/components/Trendz/TrendzChip.astro @@ -0,0 +1,33 @@ +--- +interface Props { + label: string; + color?: string; + bg?: string; + tag?: 'h1' | 'h2' | 'h3' | 'p' | 'span'; +} + +const { label, color = 'var(--color-trendz-accent)', bg = 'transparent', tag: Tag = 'span' } = Astro.props; +--- + + + + {label} + + + diff --git a/src/components/Trendz/TrendzContactModal.astro b/src/components/Trendz/TrendzContactModal.astro new file mode 100644 index 000000000..6b86b9b79 --- /dev/null +++ b/src/components/Trendz/TrendzContactModal.astro @@ -0,0 +1,442 @@ +--- + +--- + + + + + + diff --git a/src/pages/products/trendz/index.astro b/src/pages/products/trendz/index.astro index 24d64b174..2a5163bd1 100644 --- a/src/pages/products/trendz/index.astro +++ b/src/pages/products/trendz/index.astro @@ -1,10 +1,13 @@ --- import BaseLayout from '../../../layouts/BaseLayout.astro'; import HeroSection from '../../../components/Trendz/HeroSection.astro'; +import TrendzContactModal from '../../../components/Trendz/TrendzContactModal.astro'; +import HowIotImprovesBusinessSection from '../../../components/Trendz/HowIotImprovesBusinessSection.astro'; +import MetricExplorerSection from '../../../components/Trendz/MetricExplorerSection.astro'; import TopFeaturesSection from '../../../components/Trendz/TopFeaturesSection.astro'; -import FeatureBlocksSection from '../../../components/Trendz/FeatureBlocksSection.astro'; import DeploymentOptionsSection from '../../../components/Trendz/DeploymentOptionsSection.astro'; import BottomCTASection from '../../../components/Trendz/BottomCTASection.astro'; +import FAQSection from '../../../components/Trendz/FAQSection.astro'; --- - - + + + - \ No newline at end of file + + + diff --git a/src/pages/services/development-services/index.astro b/src/pages/services/development-services/index.astro index de2f7d863..7262c57d4 100644 --- a/src/pages/services/development-services/index.astro +++ b/src/pages/services/development-services/index.astro @@ -2,6 +2,7 @@ import BaseLayout from '../../../layouts/BaseLayout.astro'; import LogoCarousel from '../../../components/Services/LogoCarousel.astro'; import ServicesBanner from '../../../components/Services/ServicesBanner.astro'; +import ProjectScreenFrame from '../../../components/Services/ProjectScreenFrame.astro'; import FeedbackCard from '../../../components/Feedback/FeedbackCard.astro'; import { devServicesFeedback } from '@data/clients-feedback'; @@ -24,1023 +25,1911 @@ const customerLogos = [ pageId="development-services" >
- -
- - -
-
-
-
-

IoT Development Services

-

3X faster delivery, 2X lower cost of ownership: accelerate your IoT solution development

+ +
+ + +
+
+
+
+

IoT Development Services

+

+ 3X faster delivery, 2X lower cost of ownership: accelerate your IoT solution development +

+
+
+ +
-
- +
+ ThingsBoard IoT dashboard + ThingsBoard widgets + ThingsBoard chart + ThingsBoard map widget
-
- ThingsBoard IoT dashboard - ThingsBoard widgets - ThingsBoard chart - ThingsBoard map widget -
-
-
-
-

1

-

years in IoT domain

-
-
-

1

-

countries

-
-
-

1+

-

delivered projects

-
-
-

1%

-

success rate

-
-
-

1%

-

clients engage us again

+
+
+

1

+

years in IoT domain

+
+
+

1

+

countries

+
+
+

1+

+

delivered projects

+
+
+

1%

+

success rate

+
+
+

1%

+

clients engage us again

+
-
-
- - -
-
-
-
-

Custom IoT solutions: concepts made real

-
-
- {[ - { - title: 'Fleet tracking', - defaultOpen: true, - image: '/images/development-services/site-fleet-tracking-1.webp', - demoLink: 'https://thingsboard.cloud/dashboard/3b0ab5a0-f838-11f0-a24d-13b2783631c6?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', - tags: ['Logistics', 'Automotive', 'Delivery', 'Connected vehicle'], - projects: '47+', - text: 'Fleet tracking addresses the core challenge of managing vehicles effectively. Real-time visibility in a combination with geofence rules brings clarity to asset locations and ensures route efficiency, whether we are tracking e-bikes or heavy-duty trucks. By adding driver accountability and reporting, we transform complex operational data into a clear path for improved service and real cost savings.', - }, - { - title: 'Energy monitoring', - image: '/images/development-services/smart-energy-1.webp', - demoLink: 'https://demo.thingsboard.io/dashboard/e8e409c0-f2b5-11e6-a6ee-bb0136cc33d0?publicId=963ab470-34c9-11e7-a7ce-bb0136cc33d0', - tags: ['Manufacturing', 'Retail', 'Utilities', 'Industry'], - projects: '48+', - text: 'Energy monitoring system provides clarity on your real-time energy usage, enabling smart energy management by highlighting hidden inefficiencies and anomalies. Tailored dashboards, alerts, and analytics help businesses reduce costs, improve transparency, and meet energy efficiency goals — from industrial operations to commercial buildings.', - }, - { - title: 'Asset tracking', - image: '/images/development-services/waste-1.webp', - demoLink: 'https://thingsboard.cloud/dashboard/7814f8a0-8fa9-11ef-baa8-4521077809fd?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', - tags: ['Manufacturing', 'Logistics', 'Construction', 'Agriculture', 'Retail'], - projects: '44+', - text: 'A custom IoT asset tracking system enables real-time monitoring of tools, equipment, or goods across multiple locations. With location data, usage history, and alerts available in one asset tracking platform, businesses can improve visibility, reduce losses, and automate asset tracking and management processes — whether in warehouses, factories, or on remote sites.', - }, - { - title: 'SCADA', - image: '/images/development-services/hp-swiming-pool-system-state.webp', - demoLink: 'https://thingsboard.cloud/dashboard/231a5800-ce96-11ef-852e-bd51c2b30fde?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', - tags: ['Manufacturing', 'Utilities', 'Oil & Gas', 'Water Management', 'Energy'], - projects: '38+', - text: 'SCADA IoT solutions provide real-time visibility into industrial operations, seamlessly integrating existing equipment through IT/OT integration. Typically configured with digital twin capabilities, they detect issues early, automate alerts, and simplify remote control. This proactive approach helps teams quickly respond and minimize operational disruptions.', - }, - { - title: 'Smart Metering', - image: '/images/development-services/smart-metering-1.webp', - demoLink: 'https://demo.thingsboard.io/dashboard/3a1026e0-83f6-11e7-b56d-c7f326cba909?publicId=322a2330-7c36-11e7-835d-c7f326cba909', - tags: ['Manufacturing', 'Real Estate', 'Utilities', 'Smart Cities', 'Energy'], - projects: '33+', - text: 'Smart metering transforms utility management by automating the collection of electricity, water, and gas consumption data, converting it into actionable, real-time insights. It automates invoicing workflows and delivers precise usage metrics for transparent, reliable billing. With anomaly detection for leaks or unusual usage patterns, facility managers can effectively minimize losses and significantly enhance sustainability efforts.', - }, - { - title: 'Tank level', - image: '/images/development-services/tank-level-monitoring-1.webp', - demoLink: 'https://thingsboard.cloud/dashboard/e1ff5690-5e0c-11ee-aeee-d16039673934?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', - tags: ['Oil & Gas', 'Agriculture', 'Manufacturing', 'Utilities', 'Water Management'], - projects: '31+', - text: 'An IoT tank level monitoring system enables accurate, real-time tracking of liquid levels in fuel, water, or chemical tanks. Remote access, automated alerts, and refill optimization reduce manual checks, prevent overflows, and help detect leaks early.', - }, +
+ + +
+
+
+
+

Custom IoT solutions: concepts made real

+
+
{ - title: 'Cold chain', - image: '/images/development-services/smart-retail-3.webp', - demoLink: 'https://thingsboard.cloud/dashboard/551d4ca0-8b54-11ec-98f9-ff45c37940c6?publicId=4978baf0-8a92-11ec-98f9-ff45c37940c6', - tags: ['Manufacturing', 'Logistics', 'Retail'], - projects: '45+', - text: 'Cold chain monitoring systems deliver real-time visibility of temperature-sensitive products by tracking environmental conditions from storage through shipment, ensuring quality and compliance. They automate logging of critical parameters into live dashboards and audit-ready historical reports. With proactive alerts, time-to-threshold forecasts, and automated compliance reports, managers can intervene early to prevent spoilage.', - }, - ].map((panel) => ( -
-
-

{panel.title}

-
-
-
- {panel.tags.map((tag) =>
{tag}
)} + [ + { + title: 'Fleet tracking', + defaultOpen: true, + image: '/images/development-services/site-fleet-tracking-1.webp', + demoLink: + 'https://thingsboard.cloud/dashboard/3b0ab5a0-f838-11f0-a24d-13b2783631c6?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', + tags: ['Logistics', 'Automotive', 'Delivery', 'Connected vehicle'], + projects: '47+', + text: 'Fleet tracking addresses the core challenge of managing vehicles effectively. Real-time visibility in a combination with geofence rules brings clarity to asset locations and ensures route efficiency, whether we are tracking e-bikes or heavy-duty trucks. By adding driver accountability and reporting, we transform complex operational data into a clear path for improved service and real cost savings.', + }, + { + title: 'Energy monitoring', + image: '/images/development-services/smart-energy-1.webp', + demoLink: + 'https://demo.thingsboard.io/dashboard/e8e409c0-f2b5-11e6-a6ee-bb0136cc33d0?publicId=963ab470-34c9-11e7-a7ce-bb0136cc33d0', + tags: ['Manufacturing', 'Retail', 'Utilities', 'Industry'], + projects: '48+', + text: 'Energy monitoring system provides clarity on your real-time energy usage, enabling smart energy management by highlighting hidden inefficiencies and anomalies. Tailored dashboards, alerts, and analytics help businesses reduce costs, improve transparency, and meet energy efficiency goals — from industrial operations to commercial buildings.', + }, + { + title: 'Asset tracking', + image: '/images/development-services/waste-1.webp', + demoLink: + 'https://thingsboard.cloud/dashboard/7814f8a0-8fa9-11ef-baa8-4521077809fd?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', + tags: ['Manufacturing', 'Logistics', 'Construction', 'Agriculture', 'Retail'], + projects: '44+', + text: 'A custom IoT asset tracking system enables real-time monitoring of tools, equipment, or goods across multiple locations. With location data, usage history, and alerts available in one asset tracking platform, businesses can improve visibility, reduce losses, and automate asset tracking and management processes — whether in warehouses, factories, or on remote sites.', + }, + { + title: 'SCADA', + image: '/images/development-services/hp-swiming-pool-system-state.webp', + demoLink: + 'https://thingsboard.cloud/dashboard/231a5800-ce96-11ef-852e-bd51c2b30fde?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', + tags: ['Manufacturing', 'Utilities', 'Oil & Gas', 'Water Management', 'Energy'], + projects: '38+', + text: 'SCADA IoT solutions provide real-time visibility into industrial operations, seamlessly integrating existing equipment through IT/OT integration. Typically configured with digital twin capabilities, they detect issues early, automate alerts, and simplify remote control. This proactive approach helps teams quickly respond and minimize operational disruptions.', + }, + { + title: 'Smart Metering', + image: '/images/development-services/smart-metering-1.webp', + demoLink: + 'https://demo.thingsboard.io/dashboard/3a1026e0-83f6-11e7-b56d-c7f326cba909?publicId=322a2330-7c36-11e7-835d-c7f326cba909', + tags: ['Manufacturing', 'Real Estate', 'Utilities', 'Smart Cities', 'Energy'], + projects: '33+', + text: 'Smart metering transforms utility management by automating the collection of electricity, water, and gas consumption data, converting it into actionable, real-time insights. It automates invoicing workflows and delivers precise usage metrics for transparent, reliable billing. With anomaly detection for leaks or unusual usage patterns, facility managers can effectively minimize losses and significantly enhance sustainability efforts.', + }, + { + title: 'Tank level', + image: '/images/development-services/tank-level-monitoring-1.webp', + demoLink: + 'https://thingsboard.cloud/dashboard/e1ff5690-5e0c-11ee-aeee-d16039673934?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', + tags: ['Oil & Gas', 'Agriculture', 'Manufacturing', 'Utilities', 'Water Management'], + projects: '31+', + text: 'An IoT tank level monitoring system enables accurate, real-time tracking of liquid levels in fuel, water, or chemical tanks. Remote access, automated alerts, and refill optimization reduce manual checks, prevent overflows, and help detect leaks early.', + }, + { + title: 'Cold chain', + image: '/images/development-services/smart-retail-3.webp', + demoLink: + 'https://thingsboard.cloud/dashboard/551d4ca0-8b54-11ec-98f9-ff45c37940c6?publicId=4978baf0-8a92-11ec-98f9-ff45c37940c6', + tags: ['Manufacturing', 'Logistics', 'Retail'], + projects: '45+', + text: 'Cold chain monitoring systems deliver real-time visibility of temperature-sensitive products by tracking environmental conditions from storage through shipment, ensuring quality and compliance. They automate logging of critical parameters into live dashboards and audit-ready historical reports. With proactive alerts, time-to-threshold forecasts, and automated compliance reports, managers can intervene early to prevent spoilage.', + }, + ].map((panel) => ( +
+
+

{panel.title}

+
+
+
+ {panel.tags.map((tag) => ( +
{tag}
+ ))} +
+
+ {panel.projects} successful projects + {panel.text} +
+
+
-
- {panel.projects} successful projects - {panel.text} + )) + } +
+
+
+ +
+ + View live demo +
+ +
+
+
+
+ Eric Bourbeau +
+

+ "We were looking for a robust and scalable IoT platform to help us deploy leading edge + LoRaWAN™-based IoT projects. We landed a contract to deploy a city-wide network of + solar/wireless variable message "No Parking" signs to manage on-street parking for + snow removal operations. The dead... read more about smart city solutions +

+
+
Eric Bourbeau, Founder and CEO at X-TELIA
-
- ))} +
+
+
+
+ + + + + +
+
+
+
+
+ Photo of Artur Ishkhanishvili, VP Business Development ThingsBoard + Photo of Artur Ishkhanishvili, VP Business Development ThingsBoard +
+
Artur Ishkhanishvili
+
VP Business Development
+
+
+
+
+

+ In IoT, data and dashboards mean nothing if they don't create real business value. At ThingsBoard, + our Development Unit makes sure your solution does exactly that. +

+

+ We don't just build features — we help you turn ideas into results. With our platform and experts, + your technical goals are covered, so you can stay focused on your business impact. From optimizing + supply chains to launching smart services, we ensure the tech drives results that matter — to your + customers and your bottom line. +

+
+
+
+
-
-
-
-
-
-
-
+
+
+ + +
+

From concept to success: IoT development case studies

+
+
+ - - -
-
-
-
- Eric Bourbeau -
-

"We were looking for a robust and scalable IoT platform to help us deploy leading edge LoRaWAN™-based IoT projects. We landed a contract to deploy a city-wide network of solar/wireless variable message "No Parking" signs to manage on-street parking for snow removal operations. The dead... read more about smart city solutions

+ -
+
-
-
-
- - - - - -
-
-
-
-
- Photo of Artur Ishkhanishvili, VP Business Development ThingsBoard - Photo of Artur Ishkhanishvili, VP Business Development ThingsBoard -
-
Artur Ishkhanishvili
-
VP Business Development
-
+
+ -
-
-

In IoT, data and dashboards mean nothing if they don't create real business value. At ThingsBoard, our Development Unit makes sure your solution does exactly that.

-

We don't just build features — we help you turn ideas into results. With our platform and experts, your technical goals are covered, so you can stay focused on your business impact. From optimizing supply chains to launching smart services, we ensure the tech drives results that matter — to your customers and your bottom line.

-
+
+ - -
-
- - -
-

From concept to success: IoT development case studies

-
+ + +
+
+

Custom IoT development services

+
+ These are custom development services delivered directly by the in-house ThingsBoard team. No third + parties — just our engineers and proven processes +
+
+
+
+
+ IoT Consulting & Solution Architecture icon

IoT Consulting & Solution Architecture

+
+
+
+
    +
  • Analyze business processes to define effective IoT strategy
  • + Design system architecture and identify areas for improvement +
  • Develop detailed roadmap for successful IoT solution implementation
  • +
-
-
-
- -
- Manufacturing - +
+
    +
  • Quickly validate ideas through Proof of Concept (PoC) creation
  • + Development of Minimum Viable Product (MVPs) for accelerated market entry +
  • Test use cases directly on real devices in real-world conditions
  • +
-
-
-
- -
- Industry 4.0 - +
+
    +
  • Implement reliable data synchronization across multiple applications
  • + Integrate third-party apps (on-premise, cloud-based, SaaS) to automate workflows +
  • Connect IoT solutions with existing enterprise systems
  • +
-
-
-
- -
- Energy and utilities - +
+
    +
  • Enable on-site data processing and dashboards in offline mode
  • + Centralized deployment of workflows and applications to edge devices +
  • Hybrid IoT deployment via edge gateways and cloud
  • +
-
-
-
- -
- Equipment tracking - +
+
    +
  • Custom web and mobile IoT apps for specific industry needs
  • + Build secure, scalable IoT applications ensuring optimal performance +
  • Create intuitive UI/UX for actionable data insights
  • +
-
-
-
- -
- Logistic & supply-chain - +
+
    +
  • Development of native mobile applications for easy remote access
  • + Setup push notifications, remote control and monitoring on mobile +
  • Integrate mobile device sensors (camera, GPS, scanners) for intuitive IoT control
  • +
+
+
+
+
+
+ IoT Data Visualization icon

IoT Data Visualization

+
+
+
+
    +
  • Design intuitive dashboards to present complex IoT data with clarity
  • + Develop custom charts, widgets & reports for in-depth trend analysis +
  • Build interactive drill-down dashboards for detailed data exploration
  • +
+
+
+
+
+
+ IoT analytics icon

IoT analytics

+
+
+
+
    +
  • Enable KPI tracking, trend and anomaly detection including root cause analysis
  • + Build predictive forecasting and 'what-if' simulations within digital twins +
  • Visualize insights on drill-down dashboards with layered aggregated metrics
  • +
+
+
+
+
+
+ Remote Monitoring & Control Apps icon

Remote Monitoring & Control Apps

+
+
+
+
    +
  • Enable real-time tracking of your remote assets and device status
  • + Implement secured methods for OTA configuration update and send commands +
  • Automate device actions & workflows based on IoT triggers
  • +
+
+
+
+
+
+ Device Integration icon

Device integration

+
+
+
+
    +
  • + Establish bidirectional connectivity for device-to-application data flow and remote control +
  • Custom integration with legacy systems for unified data processing
  • + Device onboarding, lifecycle management, and secured OTA updates +
  • +
+
+
+
+
+
+ Predictive Maintenance icon

Predictive Maintenance

+
+
+
+
    +
  • Deliver actionable alerts & insights to prevent downtime and optimize assets
  • + Predict equipment failures with ML models trained on live data from sensors +
  • Enable proactive maintenance scheduling & work order management
  • +
+
+
+
+
+
+ Digital Twin icon

Digital Twin

+
+
+
+
    +
  • Build digital twins unifying diverse IoT and integrated system data
  • + Analyze model behavior, metrics and simulate various 'what-if' scenarios +
  • Predict performance and use twin simulations for operational optimization
  • +
+
+
+
+
+
+ IoT Compliance management icon

IoT Compliance management

+
+
+
+
    +
  • Automate audit trails & reports in specific regulatory formats
  • + Configure system for GDPR, HACCP, 21 CFR Part 11, ISO 50001 & similar regulations +
  • Apply our IoT expertise to sector-specific compliance needs
  • +
+
+
+
+
+
+ Migration Services icon

Migration Services

+
+
+
+
    +
  • Evaluate current IoT system & plan managed migration to ThingsBoard
  • + Migrate devices, data & logic to ThingsBoard for scale & lower TCO +
  • Deploy reliable ThingsBoard solution, ready for future feature growth
  • +
+
+
+
+
+
+ Device management icon

Device management

+
+
+
+
    +
  • Interfaces for full device lifecycle management, from provisioning to replacement
  • + Enable bulk device operations and secured OTA for firmware/configurations +
  • Automate device management via conditional rules & workflows
  • +
+
+
+
+
+
+ AI Agents & Copilots icon

AI Agents & Copilots

+
+
+
+
    +
  • Deploy AI copilots for guided troubleshooting and operational efficiency
  • + Enable natural language queries and control via integrated LLM services +
  • GenAI recommendations based on expert knowledge and live data
  • +
-
-
-
- - -
-
-

Custom IoT development services

-
These are custom development services delivered directly by the in-house ThingsBoard team. No third parties — just our engineers and proven processes
-
-
-
IoT Consulting & Solution Architecture icon

IoT Consulting & Solution Architecture

-
  • Analyze business processes to define effective IoT strategy
  • Design system architecture and identify areas for improvement
  • Develop detailed roadmap for successful IoT solution implementation
-
-
-
Prototyping (PoC, MVP) icon

Prototyping (PoC, MVP)

-
  • Quickly validate ideas through Proof of Concept (PoC) creation
  • Development of Minimum Viable Product (MVPs) for accelerated market entry
  • Test use cases directly on real devices in real-world conditions
-
-
-
IoT Integration services icon

IoT integration services

-
  • Implement reliable data synchronization across multiple applications
  • Integrate third-party apps (on-premise, cloud-based, SaaS) to automate workflows
  • Connect IoT solutions with existing enterprise systems
-
-
-
Edge Computing Solutions icon

Edge Computing Solutions

-
  • Enable on-site data processing and dashboards in offline mode
  • Centralized deployment of workflows and applications to edge devices
  • Hybrid IoT deployment via edge gateways and cloud
-
-
-
IoT Application Development icon

IoT Application Development

-
  • Custom web and mobile IoT apps for specific industry needs
  • Build secure, scalable IoT applications ensuring optimal performance
  • Create intuitive UI/UX for actionable data insights
-
-
-
IoT Mobile App icon

IoT Mobile App

-
  • Development of native mobile applications for easy remote access
  • Setup push notifications, remote control and monitoring on mobile
  • Integrate mobile device sensors (camera, GPS, scanners) for intuitive IoT control
-
-
-
IoT Data Visualization icon

IoT Data Visualization

-
  • Design intuitive dashboards to present complex IoT data with clarity
  • Develop custom charts, widgets & reports for in-depth trend analysis
  • Build interactive drill-down dashboards for detailed data exploration
-
-
-
IoT analytics icon

IoT analytics

-
  • Enable KPI tracking, trend and anomaly detection including root cause analysis
  • Build predictive forecasting and 'what-if' simulations within digital twins
  • Visualize insights on drill-down dashboards with layered aggregated metrics
+
+
+

Discuss your IoT project with us

+
-
-
Remote Monitoring & Control Apps icon

Remote Monitoring & Control Apps

-
  • Enable real-time tracking of your remote assets and device status
  • Implement secured methods for OTA configuration update and send commands
  • Automate device actions & workflows based on IoT triggers
+
+
+ + +
+
+

Industries we empower with IoT development

+
+ Our experience covers more than 10 industries — from smart meters and fleet telematics to predictive + maintenance on factory floors. Our deep domain expertise means faster development, fewer risks, and + software that performs exactly as you expect
-
-
Device Integration icon

Device integration

-
  • Establish bidirectional connectivity for device-to-application data flow and remote control
  • Custom integration with legacy systems for unified data processing
  • Device onboarding, lifecycle management, and secured OTA updates
+
+ +
-
-
Predictive Maintenance icon

Predictive Maintenance

-
  • Deliver actionable alerts & insights to prevent downtime and optimize assets
  • Predict equipment failures with ML models trained on live data from sensors
  • Enable proactive maintenance scheduling & work order management
+
+
+ + +
+

Your trusted IoT development partner

+
+
+
+
Fixed cost
+
Fast delivery
+
Proved results
+
+
+

65% of our clients build 2+ solution with us

+
-
-
Digital Twin icon

Digital Twin

-
  • Build digital twins unifying diverse IoT and integrated system data
  • Analyze model behavior, metrics and simulate various 'what-if' scenarios
  • Predict performance and use twin simulations for operational optimization
+ -
-
IoT Compliance management icon

IoT Compliance management

-
  • Automate audit trails & reports in specific regulatory formats
  • Configure system for GDPR, HACCP, 21 CFR Part 11, ISO 50001 & similar regulations
  • Apply our IoT expertise to sector-specific compliance needs
+
+
+ + +
+

+ Fast delivery it's not about time management, it's about expertise, knowledge, and a ready-to-develop core + platform +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Why it mattersWhat it gives
ThingsBoard at the CoreWe build on ThingsBoard's micro-service stack and re-using components instead of wiring them from + scratch8× faster process: regular 8-month MVP delivered in just 1 month
Low-code acceleratorsDashboards, workflows, and rules are configured, not codedAbout 70 % of UI built via drag-and-drop
Vertical starter kitsReusable blueprints for 10+ industries cut uncertainty and tighten estimates.40 – 50 % of configuration is reused across engagements
Architecture-as-a-ServiceScaling, HA, observability, and DevOps patterns come pre-hardened and cloud-agnosticScalable production-ready setup for 50k msg/s deployed in 5–8 days
Fixed-price transparencyBudget is locked on day one; no surprises down the lineProjects delivered on agreed cost and timeline
+
+
+
+

Why it matters

+

What it gives

-
-
Migration Services icon

Migration Services

-
  • Evaluate current IoT system & plan managed migration to ThingsBoard
  • Migrate devices, data & logic to ThingsBoard for scale & lower TCO
  • Deploy reliable ThingsBoard solution, ready for future feature growth
+

ThingsBoard at the Core

+
+

+ We build on ThingsBoard's micro-service stack and re-using components instead of wiring them from + scratch +

+

8x faster process: regular 8-month MVP delivered in just 1 month

-
-
Device management icon

Device management

-
  • Interfaces for full device lifecycle management, from provisioning to replacement
  • Enable bulk device operations and secured OTA for firmware/configurations
  • Automate device management via conditional rules & workflows
+

Low-code accelerators

+
+

Dashboards, workflows, and rules are configured, not coded

+

About 70 % of UI built via drag-and-drop

-
-
AI Agents & Copilots icon

AI Agents & Copilots

-
  • Deploy AI copilots for guided troubleshooting and operational efficiency
  • Enable natural language queries and control via integrated LLM services
  • GenAI recommendations based on expert knowledge and live data
+

Vertical starter kits

+
+

Reusable blueprints for 10+ industries cut uncertainty and tighten estimates.

+

40 – 50 % of configuration is reused across engagements

-
-
Security icon

Security

-
  • Secure device links and implement reliable authentication and encryption
  • Ensure data security via granular role based access controls
  • Configure audit logs, SSO/MFA & other essential application security best practices
+

Architecture-as-a-Service

+
+

+ Scaling, HA, observability, and DevOps patterns come pre-hardened and cloud-agnostic +

+

Scalable production-ready setup for 50k msg/s deployed in 5–8 days

-
-
IoT DevOps services icon

IoT DevOps services

-
  • Application deployment as a scalable microservices ensuring uptime, health and performance
  • Setup monitoring stack for platform and application level metrics
  • Provide ongoing operational support and proactive system maintenance
+

Fixed-price transparency

+
+

Budget is locked on day one; no surprises down the line

+

Projects delivered on agreed cost and timeline

-
-
-
-

Discuss your IoT project with us

- -
-
- - -
-
-

Industries we empower with IoT development

-
Our experience covers more than 10 industries — from smart meters and fleet telematics to predictive maintenance on factory floors. Our deep domain expertise means faster development, fewer risks, and software that performs exactly as you expect
-
- -
+ + +
+ Quote mark +
+

+ "We operate in highly competitive markets; from housing management to utilities and manufacturing sectors. + Technology innovation is at the heart of our product strategy and service delivery approach. As we grow + and extend our field service management solution, we recognised that we needed a flexible IoT platform + that enables our delivery needs with lower complexity and co... read more about smart energy solutions +

+

Mark Hunt, CTO at Oneserve

-
-
- - -
-

Your trusted IoT development partner

-
-
-
-
Fixed cost
-
Fast delivery
-
Proved results
+
+ + +
+

A few more features that our clients value

+
+
+

Pre-built stack, custom focus

+
+ 70% of the stack comes from ThingsBoard + low-code, so engineers focus only on the remaining 30% of + business logic +
-
-

65% of our clients build 2+ solution with us

+
+

Scalable by design

+
+ Microservices, DevOps templates, and the migration tool-chain are productized, so going from 100 devices + to 1M is a repeatable playbook +
-
-
- - -
-

Fast delivery it's not about time management, it's about expertise, knowledge, and a ready-to-develop core platform

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Why it mattersWhat it gives
ThingsBoard at the CoreWe build on ThingsBoard's micro-service stack and re-using components instead of wiring them from scratch8× faster process: regular 8-month MVP delivered in just 1 month
Low-code acceleratorsDashboards, workflows, and rules are configured, not codedAbout 70 % of UI built via drag-and-drop
Vertical starter kitsReusable blueprints for 10+ industries cut uncertainty and tighten estimates.40 – 50 % of configuration is reused across engagements
Architecture-as-a-ServiceScaling, HA, observability, and DevOps patterns come pre-hardened and cloud-agnosticScalable production-ready setup for 50k msg/s deployed in 5–8 days
Fixed-price transparencyBudget is locked on day one; no surprises down the lineProjects delivered on agreed cost and timeline
-
-
-
-

Why it matters

-

What it gives

-
-

ThingsBoard at the Core

-
-

We build on ThingsBoard's micro-service stack and re-using components instead of wiring them from scratch

-

8x faster process: regular 8-month MVP delivered in just 1 month

-
-

Low-code accelerators

-
-

Dashboards, workflows, and rules are configured, not coded

-

About 70 % of UI built via drag-and-drop

-
-

Vertical starter kits

-
-

Reusable blueprints for 10+ industries cut uncertainty and tighten estimates.

-

40 – 50 % of configuration is reused across engagements

-
-

Architecture-as-a-Service

-
-

Scaling, HA, observability, and DevOps patterns come pre-hardened and cloud-agnostic

-

Scalable production-ready setup for 50k msg/s deployed in 5–8 days

-
-

Fixed-price transparency

-
-

Budget is locked on day one; no surprises down the line

-

Projects delivered on agreed cost and timeline

-
-
-
- - -
- Quote mark -
-

"We operate in highly competitive markets; from housing management to utilities and manufacturing sectors. Technology innovation is at the heart of our product strategy and service delivery approach. As we grow and extend our field service management solution, we recognised that we needed a flexible IoT platform that enables our delivery needs with lower complexity and co... read more about smart energy solutions

-

Mark Hunt, CTO at Oneserve

-
-
- - -
-

A few more features that our clients value

-
-
-

Pre-built stack, custom focus

-
70% of the stack comes from ThingsBoard + low-code, so engineers focus only on the remaining 30% of business logic
-
-
-

Scalable by design

-
Microservices, DevOps templates, and the migration tool-chain are productized, so going from 100 devices to 1M is a repeatable playbook
-
-
-

Ownership of custom solution

-
IP transfer - you own the solution, including data models, all configurations, and rules
-
-
-

Enterprise support 24/7

-
Our support services are available to clients who choose them, providing assistance after development
-
-
- -
- - -
-

Project implementation timeline

-

This timeline shows the key milestones in our development process, from the initial technical discussion to production deployment and maintenance. It is a structured framework that we adapt to the specific needs of client project

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StepsWeek 1Week 2Week 3Week 4Week 5Week 6Week 7Week 8
01. Technical Workshop

1-3 sessions

A working session with our solution architects and your team. We map your business objectives to concrete technical requirements and define the functional scope of the solution.

02. Scope & Proposal

5 days

Based on the workshop, we prepare a technical proposal. It includes the detailed system architecture, project scope, a fixed-cost breakdown, and an implementation plan with clear deliverables for each phase.

03. Project Kick-off

2 days

Once the proposal is approved, we sign the contract and provision the dedicated project environment (development, staging, production). The assigned engineering team begins work.

04. Iterative Development

Scope-dependent (from 1 week)

The solution is built in agile sprints (typically 2 weeks). Each sprint concludes with a demo of the new functionality for your team to review and provide direct feedback, ensuring the project stays aligned with the goals.

05. Iterative Testing & Validation

Scope-dependent (from 2 weeks)

The solution undergoes a complete testing cycle, including functional, integration, and performance testing. We then proceed to User Acceptance Testing (UAT) with your team to formally validate that all requirements have been met.

06. Deployment

2 days

Following successful validation, we deploy the solution to the production environment. The go-live process follows a pre-agreed plan designed to ensure a smooth cutover.

07. Support & Maintenance

Ongoing

Post-launch, we offer optional Service-Level Agreements (SLAs) for ongoing system maintenance, technical support, and planning for future feature development.

-
-
-
-
Week 1
-
Week 2
-
Week 3
-
Week 4
-
Week 5
-
Week 6
-
Week 7
-
Week 8
-
-
-
-

Technical Workshop

-

1-3 sessions

-

A working session with our solution architects and your team. We map your business objectives to concrete technical requirements and define the functional scope of the solution.

-
-
-

Scope & Proposal

-

5 days

-

Based on the workshop, we prepare a technical proposal. It includes the detailed system architecture, project scope, a fixed-cost breakdown, and an implementation plan with clear deliverables for each phase.

-
-
-

Project Kick-off

-

2 days

-

Once the proposal is approved, we sign the contract and provision the dedicated project environment (development, staging, production). The assigned engineering team begins work.

-
-
-

Iterative Development

-

Scope-dependent (from 1 week)

-

The solution is built in agile sprints (typically 2 weeks). Each sprint concludes with a demo of the new functionality for your team to review and provide direct feedback, ensuring the project stays aligned with the goals.

-
-
-

Iterative Testing & Validation

-

Scope-dependent (typically 1-2 weeks)

-

The solution undergoes a complete testing cycle, including functional, integration, and performance testing. We then proceed to User Acceptance Testing (UAT) with your team to formally validate that all requirements have been met.

-
-
-

Deployment

-

2 days

-

Following successful validation, we deploy the solution to the production environment. The go-live process follows a pre-agreed plan designed to ensure a smooth cutover.

+ +
+ + +
+

Project implementation timeline

+

+ This timeline shows the key milestones in our development process, from the initial technical discussion to + production deployment and maintenance. It is a structured framework that we adapt to the specific needs of + client project +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StepsWeek 1Week 2Week 3Week 4Week 5Week 6Week 7Week 8
01. Technical Workshop
+

1-3 sessions

+ A working session with our solution architects and your team. We map your business objectives to + concrete technical requirements and define the functional scope of the solution. +

+
02. Scope & Proposal
+

5 days

+ Based on the workshop, we prepare a technical proposal. It includes the detailed system + architecture, project scope, a fixed-cost breakdown, and an implementation plan with clear + deliverables for each phase. +

+
03. Project Kick-off
+

2 days

+ Once the proposal is approved, we sign the contract and provision the dedicated project + environment (development, staging, production). The assigned engineering team begins work. +

+
04. Iterative Development
+

Scope-dependent (from 1 week)

+ The solution is built in agile sprints (typically 2 weeks). Each sprint concludes with a demo of + the new functionality for your team to review and provide direct feedback, ensuring the project + stays aligned with the goals. +

+
05. Iterative Testing & Validation
+

Scope-dependent (from 2 weeks)

+ The solution undergoes a complete testing cycle, including functional, integration, and + performance testing. We then proceed to User Acceptance Testing (UAT) with your team to formally + validate that all requirements have been met. +

+
06. Deployment
+

2 days

+ Following successful validation, we deploy the solution to the production environment. The + go-live process follows a pre-agreed plan designed to ensure a smooth cutover. +

+
07. Support & Maintenance
+

Ongoing

+ Post-launch, we offer optional Service-Level Agreements (SLAs) for ongoing system maintenance, + technical support, and planning for future feature development. +

+
-
-

Support & Maintenance

-

Ongoing

-

Post-launch, we offer optional Service-Level Agreements (SLAs) for ongoing system maintenance, technical support, and planning for future feature development.

+
+
+
Week 1
+
Week 2
+
Week 3
+
Week 4
+
Week 5
+
Week 6
+
Week 7
+
Week 8
+
+
+
+

Technical Workshop

+

1-3 sessions

+

+ A working session with our solution architects and your team. We map your business objectives to + concrete technical requirements and define the functional scope of the solution. +

+
+
+

Scope & Proposal

+

5 days

+

+ Based on the workshop, we prepare a technical proposal. It includes the detailed system architecture, + project scope, a fixed-cost breakdown, and an implementation plan with clear deliverables for each + phase. +

+
+
+

Project Kick-off

+

2 days

+

+ Once the proposal is approved, we sign the contract and provision the dedicated project environment + (development, staging, production). The assigned engineering team begins work. +

+
+
+

Iterative Development

+

Scope-dependent (from 1 week)

+

+ The solution is built in agile sprints (typically 2 weeks). Each sprint concludes with a demo of the + new functionality for your team to review and provide direct feedback, ensuring the project stays + aligned with the goals. +

+
+
+

Iterative Testing & Validation

+

Scope-dependent (typically 1-2 weeks)

+

+ The solution undergoes a complete testing cycle, including functional, integration, and performance + testing. We then proceed to User Acceptance Testing (UAT) with your team to formally validate that all + requirements have been met. +

+
+
+

Deployment

+

2 days

+

+ Following successful validation, we deploy the solution to the production environment. The go-live + process follows a pre-agreed plan designed to ensure a smooth cutover. +

+
+
+

Support & Maintenance

+

Ongoing

+

+ Post-launch, we offer optional Service-Level Agreements (SLAs) for ongoing system maintenance, + technical support, and planning for future feature development. +

+
+
-
-
-
+
- - +
- -
- -
+ +
+ +
- -
-

Clients reviews

-
- {devServicesFeedback.map((entry) => ( - - ))} -
-
+ +
+

Clients reviews

+
+ {devServicesFeedback.map((entry) => )} +
+
- -
-

Frequently asked questions about IoT Development

-
-
-
Understanding IoT Development
-
Building and Managing IoT Solutions
-
Cost and Security
-
-
-
-
-

What is IoT development?

-
-
-

IoT development services cover the design, development, deployment, and maintenance of IoT solutions. They include the creation of software ecosystems that allow you to manage communication between devices, collect data, map ingested data to digital twin, visualise it, and work as one integrated system. Think of smart electricity, water, heat meters, wearable health monitors, or asset tracking devices that provide critical information about asset health, allow decision makers to effectively strategies and improve the efficiency of key operational aspects. IoT development services bring these innovations to life.

- Key IoT development services: -
    -
  1. Device Management and Connectivity*: Securely connects, provisions, and monitors IoT devices and assets
  2. -
  3. Data Ingestion and Processing*: Collects real-time telemetry and processes it for storage, analytics, and triggering events.
  4. -
  5. Digital Twin and Modeling*: Represents physical assets and their relationships through a scalable, structured data model.
  6. -
  7. Analytics and KPIs*: Calculates key metrics such as energy usage, costs, or emissions across different system levels.
  8. -
  9. Dashboards and Visualization*: Provides real-time dashboards and drill-down interfaces for monitoring and control.
  10. -
  11. Alerts and Notifications*: Automatically triggers alerts based on predefined conditions and notifies users via multiple channels.
  12. -
  13. User Roles and Access Control*: Manages user permissions to ensure secure, role-based access to data and actions.
  14. -
  15. Security and Scalability*: Ensures encrypted data transfer, secure authentication, and high availability across large-scale deployments.
  16. -
-
+ +
+

Frequently asked questions about IoT Development

+
+
+
+ Understanding IoT Development
-
-
-

What industries can benefit from IoT application development services?

-
-
-

Almost every industry can benefit from the IoT, including manufacturing, healthcare, retail, logistics, agriculture, energy, automotive, smart cities, education, and construction. IoT helps to improve efficiency, safety, productivity and provides companies with critical data tailored to their unique needs of each sector.

-
+
+ Building and Managing IoT Solutions
-
-
-

What are some common IoT development challenges?

-
-
-

The main challenges of the IoT include ensuring seamless connectivity of all devices, data security and privacy, managing large amounts of information, visualising and analysing the data, ensuring that different devices work together and meeting the high requirements of industry standards.

-
+
+ Cost and Security
-
-

Do I need specialized hardware for IoT development?

-
-
-

No, you don't need to have hardware to start developing, you can add it in the next phases of the development process, and use simulated data to start with. But for a full product, IoT solutions usually require specialised hardware, such as sensors and gateways for data collection and transmission. The specific hardware depends on the goals of your project, such as temperature monitoring, location tracking, or remote equipment management.

+
+
+
+

What is IoT development?

+
+
+

+ IoT development services cover the design, development, deployment, and maintenance of IoT + solutions. They include the creation of software ecosystems that allow you to manage + communication between devices, collect data, map ingested data to digital twin, visualise it, + and work as one integrated system. Think of smart electricity, water, heat meters, wearable + health monitors, or asset tracking devices that provide critical information about asset health, + allow decision makers to effectively strategies and improve the efficiency of key operational + aspects. IoT development services bring these innovations to life. +

+ Key IoT development services: +
    +
  1. + Device Management and Connectivity*: Securely connects, provisions, and monitors IoT devices + and assets +
  2. +
  3. + Data Ingestion and Processing*: Collects real-time telemetry and processes it for storage, + analytics, and triggering events. +
  4. +
  5. + Digital Twin and Modeling*: Represents physical assets and their relationships through a + scalable, structured data model. +
  6. +
  7. + Analytics and KPIs*: Calculates key metrics such as energy usage, costs, or emissions across + different system levels. +
  8. +
  9. + Dashboards and Visualization*: Provides real-time dashboards and drill-down interfaces for + monitoring and control. +
  10. +
  11. + Alerts and Notifications*: Automatically triggers alerts based on predefined conditions and + notifies users via multiple channels. +
  12. +
  13. + User Roles and Access Control*: Manages user permissions to ensure secure, role-based access + to data and actions. +
  14. +
  15. + Security and Scalability*: Ensures encrypted data transfer, secure authentication, and high + availability across large-scale deployments. +
  16. +
+
+
-
-
-
-
-
-

What is an IoT platform, and do I need one?

-
-
-

An IoT platform is software that helps you easily manage connected devices, collect data, and visualise it in a clear and easy way. If you plan to effectively manage multiple devices and data streams, you'll definitely need an IoT platform, and we recommend using an IoT platform like ThingsBoard.

+
+

What industries can benefit from IoT application development services?

+
+
+

+ Almost every industry can benefit from the IoT, including manufacturing, healthcare, retail, + logistics, agriculture, energy, automotive, smart cities, education, and construction. IoT helps + to improve efficiency, safety, productivity and provides companies with critical data tailored + to their unique needs of each sector. +

+
+
-
-
-
-

How long does it take to develop an IoT solution?

-
-
-

Development time is highly dependent on many factors, such as your specific needs, hardware availability, required integrations; simple projects can take weeks, while more complex ones can take several months.

+
+

What are some common IoT development challenges?

+
+
+

+ The main challenges of the IoT include ensuring seamless connectivity of all devices, data + security and privacy, managing large amounts of information, visualising and analysing the data, + ensuring that different devices work together and meeting the high requirements of industry + standards. +

+
+
+
+
+

Do I need specialized hardware for IoT development?

+
+
+

+ No, you don't need to have hardware to start developing, you can add it in the next phases of + the development process, and use simulated data to start with. But for a full product, IoT + solutions usually require specialised hardware, such as sensors and gateways for data collection + and transmission. The specific hardware depends on the goals of your project, such as + temperature monitoring, location tracking, or remote equipment management. +

+
+
-
-
-

Does your IoT development company provide ongoing support and maintenance?

-
-
-

Yes, we offer ongoing support, including problem analysis, problem resolution, upgrades, scaling services, and continuous enhancements to ensure your IoT system is running smoothly and meeting your ever-changing needs.

+
+
+

What is an IoT platform, and do I need one?

+
+
+

+ An IoT platform is software that helps you easily manage connected devices, collect data, and + visualise it in a clear and easy way. If you plan to effectively manage multiple devices and + data streams, you'll definitely need an IoT platform, and we recommend using an IoT platform + like ThingsBoard. +

+
+
+
+
+

How long does it take to develop an IoT solution?

+
+
+

+ Development time is highly dependent on many factors, such as your specific needs, hardware + availability, required integrations; simple projects can take weeks, while more complex ones can + take several months. +

+
+
+
+
+

Does your IoT development company provide ongoing support and maintenance?

+
+
+

+ Yes, we offer ongoing support, including problem analysis, problem resolution, upgrades, scaling + services, and continuous enhancements to ensure your IoT system is running smoothly and meeting + your ever-changing needs. +

+
+
-
-
-
-

Can existing IoT solutions be integrated with the ThingsBoard platform?

-
-
-

Yes, existing IoT solutions can be easily integrated with ThingsBoard. We help with seamless integration, ensuring that your current setup receives enhanced functionality and improved management capabilities.

+
+

Can existing IoT solutions be integrated with the ThingsBoard platform?

+
+
+

+ Yes, existing IoT solutions can be easily integrated with ThingsBoard. We help with seamless + integration, ensuring that your current setup receives enhanced functionality and improved + management capabilities. +

+
+
-
-
-
-
-

What factors affect the cost of IoT development?

-
-
-

Costs depend on the complexity of the project, hardware requirements, custom software development needs, integration with existing systems, and ongoing support needs. Each of these elements can have a significant impact on the total investment in your IoT project.

+
+
+

What factors affect the cost of IoT development?

+
+
+

+ Costs depend on the complexity of the project, hardware requirements, custom software + development needs, integration with existing systems, and ongoing support needs. Each of these + elements can have a significant impact on the total investment in your IoT project. +

+
+
-
-
-
-

IoT Security

-
-
-

Taking into account industry standards and regulations (HIPAA, GDPR, etc.). Regular audit of infrastructure and application security. Development of a comprehensive security strategy (encryption, multi-level authentication, access control).

+
+

IoT Security

+
+
+

+ Taking into account industry standards and regulations (HIPAA, GDPR, etc.). Regular audit of + infrastructure and application security. Development of a comprehensive security strategy + (encryption, multi-level authentication, access control). +

+
+
-
-
-
-

How is IoT security ensured in your solutions?

-
-
-

We keep the IoT secure with strong encryption, multiple levels of authentication, and strict access controls. We also regularly audit our systems and comply with regulations such as GDPR and HIPAA to ensure your data is fully protected.

+
+

How is IoT security ensured in your solutions?

+
+
+

+ We keep the IoT secure with strong encryption, multiple levels of authentication, and strict + access controls. We also regularly audit our systems and comply with regulations such as GDPR + and HIPAA to ensure your data is fully protected. +

+
+
-
-
-
+
- -
-
-
-
- pattern -
-

Let's talk about your project

- Fill out the form — we'll get back to you shortly to clarify the details and prepare a tailored estimate -
-
-
- Photo of Artur Ishkhanishvili, VP Business Development ThingsBoard -
-
-
Artur Ishkhanishvili
-
VP Business Development
-
-
-
-
-
-
-
- -
-
- + +
+
+
+
+ pattern +
+

Let's talk about your project

+ Fill out the form — we'll get back to you shortly to clarify the details and prepare a tailored + estimate
- - - - - - - - -
- - -
- -
- +
+ +
+
+ +
+
+ +
+ +
+ + + + + + + +
+ + +
+ +
+ +
+
- +
-
+
-
- - @@ -1050,48 +1939,74 @@ const customerLogos = [

Let's talk about your project

- Close + Close
-
+ class="gtm_form developmentServicesContactUsForm" + >
- - - - - - - + + + + + + +
- +
- +
- +
@@ -1105,80 +2020,94 @@ const customerLogos = [ hasImage: true, image: '/images/development-services/Eric-Bourbeau.webp', imageAlt: 'Eric Bourbeau', - feedback: '"We were looking for a robust and scalable IoT platform to help us deploy leading edge LoRaWAN™-based IoT projects. We landed a contract to deploy a city-wide network of solar/wireless variable message “No Parking” signs to manage on-street parking for snow removal operations. The dead...', + feedback: + '"We were looking for a robust and scalable IoT platform to help us deploy leading edge LoRaWAN™-based IoT projects. We landed a contract to deploy a city-wide network of solar/wireless variable message “No Parking” signs to manage on-street parking for snow removal operations. The dead...', readMoreLink: '/clients-feedback/?category=smart-city', readMoreLabel: 'about smart city solutions', name: 'Eric Bourbeau, Founder and CEO at X-TELIA', nameNoMargin: false, - demoLink: 'https://thingsboard.cloud/dashboard/3b0ab5a0-f838-11f0-a24d-13b2783631c6?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', + demoLink: + 'https://thingsboard.cloud/dashboard/3b0ab5a0-f838-11f0-a24d-13b2783631c6?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', }, { hasImage: false, - feedback: '"Our company operates with the Smart Building Technology sector and were looking for a solution that was adaptable, programmable and easy to use for providing complete solutions to our existing customers with good clear visualisations of their data. We had researched and tried other solutions but...', + feedback: + '"Our company operates with the Smart Building Technology sector and were looking for a solution that was adaptable, programmable and easy to use for providing complete solutions to our existing customers with good clear visualisations of their data. We had researched and tried other solutions but...', readMoreLink: '/clients-feedback/?category=smart-energy', readMoreLabel: 'about smart energy solutions', name: 'Nairn Harrison, Director at Environmental Energy Controls', nameNoMargin: true, - demoLink: 'https://thingsboard.cloud/dashboard/3b0ab5a0-f838-11f0-a24d-13b2783631c6?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', + demoLink: + 'https://thingsboard.cloud/dashboard/3b0ab5a0-f838-11f0-a24d-13b2783631c6?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', }, { hasImage: true, image: '/images/development-services/Jeppe-Walther.webp', imageAlt: 'Jeppe Walther', - feedback: '"ThingsBoard (TB) turned out to be a great match to build our Agricultural IoT platform. First and foremost because of the extremely skilled and service minded architects behind it. Together with the TB developers several new features were added to the platform for our needs, among these the Asset system...', + feedback: + '"ThingsBoard (TB) turned out to be a great match to build our Agricultural IoT platform. First and foremost because of the extremely skilled and service minded architects behind it. Together with the TB developers several new features were added to the platform for our needs, among these the Asset system...', readMoreLink: '/industries/agriculture/', readMoreLabel: 'about agriculture IoT solutions', name: 'Jeppe Walther, CTO at Supertech Agroline', nameNoMargin: false, - demoLink: 'https://demo.thingsboard.io/dashboard/e8e409c0-f2b5-11e6-a6ee-bb0136cc33d0?publicId=963ab470-34c9-11e7-a7ce-bb0136cc33d0', + demoLink: + 'https://demo.thingsboard.io/dashboard/e8e409c0-f2b5-11e6-a6ee-bb0136cc33d0?publicId=963ab470-34c9-11e7-a7ce-bb0136cc33d0', }, { hasImage: true, image: '/images/development-services/Mamadou-Ly.webp', imageAlt: 'Mamadou Ly', - feedback: '"With ThingsBoard we found the platform to modernize our factories and especially improve our performance processes. Following a benchmarking of solutions on the market, we came across Thingsboard. It was a surprising discovery, but above all a turning point for Farinia group. Now we have a real-ti...', + feedback: + '"With ThingsBoard we found the platform to modernize our factories and especially improve our performance processes. Following a benchmarking of solutions on the market, we came across Thingsboard. It was a surprising discovery, but above all a turning point for Farinia group. Now we have a real-ti...', readMoreLink: '/industries/industry40/', readMoreLabel: 'about Industry 4.0 IoT solutions', name: 'Mamadou Ly, Project Manager at Farinia Group', nameNoMargin: false, - demoLink: 'https://thingsboard.cloud/dashboard/7814f8a0-8fa9-11ef-baa8-4521077809fd?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', + demoLink: + 'https://thingsboard.cloud/dashboard/7814f8a0-8fa9-11ef-baa8-4521077809fd?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', }, { hasImage: true, image: '/images/development-services/peter-backes.webp', imageAlt: 'Peter Backes', - feedback: '"We\'re a meter operator and as such a service provider for energy distribution network carriers (electricity, gas, water and heat) and other meter operators. We provide SaaS-Solutions for the remote reading of meters, field force management (for meter fitters) and the administration of smart meter gateways. Addition...', + feedback: + '"We\'re a meter operator and as such a service provider for energy distribution network carriers (electricity, gas, water and heat) and other meter operators. We provide SaaS-Solutions for the remote reading of meters, field force management (for meter fitters) and the administration of smart meter gateways. Addition...', readMoreLink: '/clients-feedback/?category=smart-energy', readMoreLabel: 'about smart energy solutions', name: 'Peter Backes, CEO at co.met GmbH', nameNoMargin: false, - demoLink: 'https://thingsboard.cloud/dashboard/231a5800-ce96-11ef-852e-bd51c2b30fde?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', + demoLink: + 'https://thingsboard.cloud/dashboard/231a5800-ce96-11ef-852e-bd51c2b30fde?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', }, { hasImage: true, image: '/images/development-services/Patricia-Crispim.webp', imageAlt: 'Patricia Crispim', - feedback: '"ThingsBoard delivered an exceptional beer tank tracking solution, on-time and within budget. The platform provided us visibility into our assets, real-time tracking, and actionable insights that significantly improved our operational efficiency...', + feedback: + '"ThingsBoard delivered an exceptional beer tank tracking solution, on-time and within budget. The platform provided us visibility into our assets, real-time tracking, and actionable insights that significantly improved our operational efficiency...', readMoreLink: '/case-studies/super-bock/', readMoreLabel: 'about the Super Bock case study', name: 'Patricia Crispim, Super Bock Group', nameNoMargin: false, - demoLink: 'https://demo.thingsboard.io/dashboard/3a1026e0-83f6-11e7-b56d-c7f326cba909?publicId=322a2330-7c36-11e7-835d-c7f326cba909', + demoLink: + 'https://demo.thingsboard.io/dashboard/3a1026e0-83f6-11e7-b56d-c7f326cba909?publicId=322a2330-7c36-11e7-835d-c7f326cba909', }, { hasImage: true, image: '/images/development-services/Steven-Kruse.webp', imageAlt: 'Steven Kruse', - feedback: '"With ThingsBoard, we can offer our customers a customised IoT platform that has been specially developed for monitoring temperature and storage conditions in food logistics. One of the platform\'s greatest strengths is its low-code approach, which allows us to implement complex solutions with minima...', + feedback: + '"With ThingsBoard, we can offer our customers a customised IoT platform that has been specially developed for monitoring temperature and storage conditions in food logistics. One of the platform\'s greatest strengths is its low-code approach, which allows us to implement complex solutions with minima...', readMoreLink: '/industries/warehouse-monitoring/', readMoreLabel: 'about warehouse monitoring solutions', name: 'Steven Kruse, CEO at SenseING GmbH', nameNoMargin: false, - demoLink: 'https://thingsboard.cloud/dashboard/551d4ca0-8b54-11ec-98f9-ff45c37940c6?publicId=4978baf0-8a92-11ec-98f9-ff45c37940c6', + demoLink: + 'https://thingsboard.cloud/dashboard/551d4ca0-8b54-11ec-98f9-ff45c37940c6?publicId=4978baf0-8a92-11ec-98f9-ff45c37940c6', }, ]; - function buildClientHtml(c: typeof clientData[0]) { + function buildClientHtml(c: (typeof clientData)[0]) { const avatarHtml = c.hasImage ? `
${c.imageAlt}
` : ''; @@ -1282,7 +2211,7 @@ const customerLogos = [ } }); }, - { threshold: 0.5 }, + { threshold: 0.5 } ); elements.forEach((el) => { @@ -1303,11 +2232,15 @@ const customerLogos = [ // Scroll fade-in animation let lastScrollY = window.scrollY; let isScrollingDown = true; - window.addEventListener('scroll', () => { - const currentScrollY = window.scrollY; - isScrollingDown = currentScrollY > lastScrollY; - lastScrollY = currentScrollY <= 0 ? 0 : currentScrollY; - }, { passive: true }); + window.addEventListener( + 'scroll', + () => { + const currentScrollY = window.scrollY; + isScrollingDown = currentScrollY > lastScrollY; + lastScrollY = currentScrollY <= 0 ? 0 : currentScrollY; + }, + { passive: true } + ); const animatedSections = document.querySelectorAll( '.get-in-touch-section, .vision-section, .trusted-partner, .more-feature, .engagement-models' @@ -1318,14 +2251,17 @@ const customerLogos = [ } }); - const scrollObserver = new IntersectionObserver((entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - entry.target.classList.add(isScrollingDown ? 'animation-trigger' : 'visible-no-anim'); - scrollObserver.unobserve(entry.target); - } - }); - }, { threshold: 0.1 }); + const scrollObserver = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + entry.target.classList.add(isScrollingDown ? 'animation-trigger' : 'visible-no-anim'); + scrollObserver.unobserve(entry.target); + } + }); + }, + { threshold: 0.1 } + ); animatedSections.forEach((el) => scrollObserver.observe(el)); @@ -1414,9 +2350,11 @@ const customerLogos = [ // FAQ — tab switching const currentFaqContainer = 'iot-development'; - (window as any).switchFaqSection = function(sectionId: string, el: HTMLElement | null) { + (window as any).switchFaqSection = function (sectionId: string, el: HTMLElement | null) { if (el?.classList.contains('active')) return; - document.querySelectorAll(`#faq-${currentFaqContainer} .faq-section-option`).forEach((e) => e.classList.remove('active')); + document + .querySelectorAll(`#faq-${currentFaqContainer} .faq-section-option`) + .forEach((e) => e.classList.remove('active')); document.querySelectorAll(`#faq-${currentFaqContainer} .pi-accordion`).forEach((e) => e.classList.remove('active')); document.getElementById(`faq-${currentFaqContainer}-${sectionId}`)?.classList.add('active'); if (el) { @@ -1442,10 +2380,13 @@ const customerLogos = [ }); const closeBtn = devModal.querySelector('.dev-modal-close-button'); - if (closeBtn) closeBtn.addEventListener('click', () => { devModal.style.display = 'none'; }); + if (closeBtn) + closeBtn.addEventListener('click', () => { + devModal.style.display = 'none'; + }); } - (window as any).onContactUsClick = function() { + (window as any).onContactUsClick = function () { if (!devModal) return; const timeInput = devModal.querySelector('.form-rendered-at'); if (timeInput) timeInput.value = String(Math.floor(Date.now() / 1000)); @@ -1454,45 +2395,45 @@ const customerLogos = [ // ── UTM + input--empty + honeypot init ─────────────────────────────────── // (runs inside shared DOMContentLoaded) - const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; - const params = new URLSearchParams(window.location.search); - - document.querySelectorAll('.developmentServicesContactUsForm').forEach((form) => { - // UTM hidden fields - utmKeys.forEach((key) => { - const el = form.querySelector(`[name="${key}"]`); - if (el) el.value = params.get(key) || ''; - }); - - // Timestamp - const timeInput = form.querySelector('.form-rendered-at'); - if (timeInput) timeInput.value = String(Math.floor(Date.now() / 1000)); + const utmKeys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; + const params = new URLSearchParams(window.location.search); + + document.querySelectorAll('.developmentServicesContactUsForm').forEach((form) => { + // UTM hidden fields + utmKeys.forEach((key) => { + const el = form.querySelector(`[name="${key}"]`); + if (el) el.value = params.get(key) || ''; + }); - // Randomize honeypot name - const hpInput = form.querySelector('.cus-hp-container input'); - const hpLabel = form.querySelector('.cus-hp-container label'); - if (hpInput && hpLabel) { - const newName = 'hp_' + Math.random().toString(36).substring(2, 10); - hpInput.name = newName; - hpInput.id = newName; - hpLabel.htmlFor = newName; - } + // Timestamp + const timeInput = form.querySelector('.form-rendered-at'); + if (timeInput) timeInput.value = String(Math.floor(Date.now() / 1000)); - // input--empty class for floating labels - form.querySelectorAll('.form-control').forEach((el) => { - el.addEventListener('input', () => { - el.classList.toggle('input--empty', !el.value); - }); + // Randomize honeypot name + const hpInput = form.querySelector('.cus-hp-container input'); + const hpLabel = form.querySelector('.cus-hp-container label'); + if (hpInput && hpLabel) { + const newName = 'hp_' + Math.random().toString(36).substring(2, 10); + hpInput.name = newName; + hpInput.id = newName; + hpLabel.htmlFor = newName; + } + + // input--empty class for floating labels + form.querySelectorAll('.form-control').forEach((el) => { + el.addEventListener('input', () => { + el.classList.toggle('input--empty', !el.value); }); + }); - // Form validation on submit - form.addEventListener('submit', (e) => { - (window as any).validateContactUsForm(form, e); - }); + // Form validation on submit + form.addEventListener('submit', (e) => { + (window as any).validateContactUsForm(form, e); }); + }); // ── Form validation ─────────────────────────────────────────────────────── - (window as any).validateContactUsForm = function(form: HTMLFormElement, e?: Event): void { + (window as any).validateContactUsForm = function (form: HTMLFormElement, e?: Event): void { const fields = [ { name: 'name', label: 'Name', type: 'text' }, { name: 'email', label: 'Email Address', type: 'email' }, @@ -1514,7 +2455,8 @@ const customerLogos = [ const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$/; // Reject common XSS payloads client-side so users get an inline // error instead of Cloudflare's "you have been blocked" page. - const xssPattern = /<\s*\/?\s*(?:script|iframe|object|embed)\b|javascript\s*:|on(?:click|error|load|focus|blur|mouseover|mouseout|change|submit|input|toggle|animationend)\s*=/i; + const xssPattern = + /<\s*\/?\s*(?:script|iframe|object|embed)\b|javascript\s*:|on(?:click|error|load|focus|blur|mouseover|mouseout|change|submit|input|toggle|animationend)\s*=/i; fields.forEach(({ name, label, type }) => { const el = form.elements.namedItem(name) as HTMLInputElement | null; @@ -1549,7 +2491,7 @@ const customerLogos = [ const hpInput = form.querySelector('.cus-hp-container input'); const timeInput = form.querySelector('.form-rendered-at'); if (hpInput && timeInput) { - const tooFast = (Math.floor(Date.now() / 1000) - parseInt(timeInput.value, 10)) < 3; + const tooFast = Math.floor(Date.now() / 1000) - parseInt(timeInput.value, 10) < 3; if (hpInput.value.trim() !== '' || tooFast) { e?.preventDefault(); form.innerHTML = '

Thank you! Your message has been received.

'; @@ -1570,7 +2512,9 @@ const customerLogos = [ :global(.animation-trigger) { opacity: 1; transform: translateY(0); - transition: opacity 1s ease, transform 1s ease; + transition: + opacity 1s ease, + transform 1s ease; } :global(.visible-no-anim) { @@ -1653,7 +2597,9 @@ const customerLogos = [ text-align: center; text-decoration: none; cursor: pointer; - transition: background-color 0.15s, color 0.15s; + transition: + background-color 0.15s, + color 0.15s; &:hover { background-color: #fff; @@ -1681,7 +2627,9 @@ const customerLogos = [ cursor: pointer; transition: background-color 0.15s; - &:hover { background-color: #1557bb; } + &:hover { + background-color: #1557bb; + } } .hero-images { @@ -1712,7 +2660,9 @@ const customerLogos = [ max-width: 407px; animation-delay: 600ms; - @media (max-width: 1700px) { max-width: 306px; } + @media (max-width: 1700px) { + max-width: 306px; + } } .right { @@ -1721,7 +2671,9 @@ const customerLogos = [ max-width: 434px; animation-delay: 800ms; - @media (max-width: 1700px) { max-width: 399px; } + @media (max-width: 1700px) { + max-width: 399px; + } } .bottom { @@ -1730,7 +2682,9 @@ const customerLogos = [ max-width: 477px; animation-delay: 900ms; - @media (max-width: 1700px) { max-width: 387px; } + @media (max-width: 1700px) { + max-width: 387px; + } } } @@ -1917,62 +2871,9 @@ const customerLogos = [ } .project-screen-container { - min-height: 370px; - padding: 5px; - display: flex; - flex-direction: column; - align-items: center; - border-radius: 12px; margin-bottom: 50px; } - .project-screen { - position: relative; - width: 100%; - isolation: isolate; - - img { - height: auto; - width: 100%; - border-radius: 5px; - transition: opacity 0.3s ease; - } - - .bg-1 { - position: absolute; - width: 100%; - height: 100%; - z-index: -1; - border-radius: 24px; - right: -81px; - top: 46px; - border: 1.5px solid #3e9af8; - } - - .bg-2 { - position: absolute; - width: 100%; - height: 100%; - z-index: -2; - border-radius: 24px; - left: -61px; - top: -33px; - border: 1.5px solid #d1e9ff; - } - - .bg-3 { - position: absolute; - width: 100%; - height: 100%; - z-index: -3; - border-radius: 24px; - right: -57px; - top: -65px; - background: #f4f8fe; - border: none; - } - } - // :global() needed — buttons are injected via buildClientHtml() without Astro scoped attributes :global(.buttons-block) { display: flex; @@ -1991,7 +2892,9 @@ const customerLogos = [ text-decoration: none; transition: opacity 0.15s; } - :global(.buttons-block .button:hover) { opacity: 0.8; } + :global(.buttons-block .button:hover) { + opacity: 0.8; + } :global(.buttons-block .view-live-demo) { background-color: unset; color: #1e67d4; @@ -2088,9 +2991,18 @@ const customerLogos = [ padding: 0 100px; } - .cdu-title { font-size: 36px; line-height: 48px; font-weight: 500; } - .cdu-sub-title { font-size: 18px; line-height: 30px; } - .development-services-container { padding: 0 100px; } + .cdu-title { + font-size: 36px; + line-height: 48px; + font-weight: 500; + } + .cdu-sub-title { + font-size: 18px; + line-height: 30px; + } + .development-services-container { + padding: 0 100px; + } } // ≤1279px — tablet: column layout, hide right panel, show inside expanded panel @@ -2104,23 +3016,43 @@ const customerLogos = [ width: unset; padding-top: 50px; - .request-consultation-container { text-align: center; } + .request-consultation-container { + text-align: center; + } } - .hero-images { margin-top: 0; } + .hero-images { + margin-top: 0; + } } - .statistics { gap: 70px; padding: 20px; z-index: 3; } + .statistics { + gap: 70px; + padding: 20px; + z-index: 3; + } - #first-screen { min-height: unset; margin-bottom: 60px; } + #first-screen { + min-height: unset; + margin-bottom: 60px; + } - .development-services-container { padding: 32px; } + .development-services-container { + padding: 32px; + } - .custom-solution-container { flex-direction: column; gap: 20px; } + .custom-solution-container { + flex-direction: column; + gap: 20px; + } - .custom-solution-container > .cards { width: 100%; } + .custom-solution-container > .cards { + width: 100%; + } - .expansion-panel { width: 100%; } + .expansion-panel { + width: 100%; + } .expansion-panel.expanded { background: none; @@ -2132,7 +3064,10 @@ const customerLogos = [ border-radius: 15px; margin-bottom: 16px; - &::after { top: 35px; right: 23px; } + &::after { + top: 35px; + right: 23px; + } } .expansion-content { @@ -2147,38 +3082,73 @@ const customerLogos = [ display: none; width: 100%; - :global(.client-feedback-cards) { width: 100%; } - :global(.project-screen-container) { display: none; min-height: unset; } - :global(.feedback-heading) { display: none; } - :global(.buttons-block) { margin-bottom: 0; padding-top: 22px; } + :global(.client-feedback-cards) { + width: 100%; + } + :global(.project-screen-container) { + display: none; + } + :global(.feedback-heading) { + display: none; + } + :global(.buttons-block) { + margin-bottom: 0; + padding-top: 22px; + } } - .expansion-panel.expanded .expansion-content .panel-images { display: block; } + .expansion-panel.expanded .expansion-content .panel-images { + display: block; + } - .solutions-images { display: none; } + .solutions-images { + display: none; + } } // ≤959px @media (max-width: 959px) { - .page-wrap { overflow: hidden; } + .page-wrap { + overflow: hidden; + } - .development-services-container { padding: 0 32px; } - .custom-solutions { padding: 10px; margin-bottom: 50px; } - .solutions-images { width: 100%; } + .development-services-container { + padding: 0 32px; + } + .custom-solutions { + padding: 10px; + margin-bottom: 50px; + } + .solutions-images { + width: 100%; + } .hero-images { margin-right: 12%; - .top { max-width: 32vw; } - .right { max-width: 40vw; } - .bottom { max-width: 42vw; } + .top { + max-width: 32vw; + } + .right { + max-width: 40vw; + } + .bottom { + max-width: 42vw; + } } .statistics { gap: 16px; - .stat-num { font-size: 36px; line-height: 48px; margin-bottom: 16px; } - .stat-label { font-size: 14px; line-height: 24px; } + .stat-num { + font-size: 36px; + line-height: 48px; + margin-bottom: 16px; + } + .stat-label { + font-size: 14px; + line-height: 24px; + } } } @@ -2187,9 +3157,18 @@ const customerLogos = [ .hero-images { margin-right: 9%; - .top { top: 41px; left: 26px; } - .right { right: -114px; top: 78px; } - .bottom { bottom: 41px; left: -12px; } + .top { + top: 41px; + left: 26px; + } + .right { + right: -114px; + top: 78px; + } + .bottom { + bottom: 41px; + left: -12px; + } } } @@ -2203,18 +3182,30 @@ const customerLogos = [ padding: 0 16px; text-align: center; - .text { padding-bottom: 50px; margin: 0; } + .text { + padding-bottom: 50px; + margin: 0; + } } - .cdu-title { font-size: 28px; line-height: 44px; } - .cdu-sub-title { width: 100%; } + .cdu-title { + font-size: 28px; + line-height: 44px; + } + .cdu-sub-title { + width: 100%; + } // At this width the secondary screenshots break out of the laptop's // frame — `.right` sits at right:-114px off-screen and `.bottom` // drops below the main image instead of overlapping it. Hide them // so the hero shows just the laptop, cleanly centered. .hero-images { - .top, .right, .bottom { display: none; } + .top, + .right, + .bottom { + display: none; + } } #first-screen { @@ -2238,13 +3229,26 @@ const customerLogos = [ text-align: center; } - .stat-num { font-size: 36px; line-height: 48px; margin-bottom: 16px; } - .stat-label { font-size: 14px; line-height: 24px; width: 80px; } + .stat-num { + font-size: 36px; + line-height: 48px; + margin-bottom: 16px; + } + .stat-label { + font-size: 14px; + line-height: 24px; + width: 80px; + } } - .development-services-container { padding: 0 16px; } + .development-services-container { + padding: 0 16px; + } - .custom-solutions { padding: 40px 0; margin-bottom: 0; } + .custom-solutions { + padding: 40px 0; + margin-bottom: 0; + } .custom-solutions-wrapper h2 { font-size: 28px; @@ -2252,23 +3256,28 @@ const customerLogos = [ margin-bottom: 24px; } - .expansion-title { font-size: 22px; } + .expansion-title { + font-size: 22px; + } - .expansion-content { padding: 0; } + .expansion-content { + padding: 0; + } :global(.buttons-block) { flex-direction: column; width: 100%; } - :global(.buttons-block .button) { width: 100%; } + :global(.buttons-block .button) { + width: 100%; + } .panel-images { :global(.project-screen-container) { - display: block; + display: flex; width: 100%; padding: 56px 0 32px; margin-bottom: 0; - min-height: unset; } :global(.feedback-heading) { @@ -2278,25 +3287,32 @@ const customerLogos = [ margin-bottom: 12px; } - :global(.buttons-block) { margin-bottom: 22px; } + :global(.buttons-block) { + margin-bottom: 22px; + } - :global(.client-info) { padding: 0; } + :global(.client-info) { + padding: 0; + } - :global(.client-avatar-container) { flex-direction: column; } + :global(.client-avatar-container) { + flex-direction: column; + } :global(.client-avatar-img) { width: 75px; height: 75px; } - :global(.client-avatar-img img) { width: 75px; height: 75px; } + :global(.client-avatar-img img) { + width: 75px; + height: 75px; + } - :global(.client-info > div:last-child) { margin-left: 0; } + :global(.client-info > div:last-child) { + margin-left: 0; + } } - - :global(.project-screen .bg-1) { right: -13px; top: 10px; } - :global(.project-screen .bg-2) { left: -10px; top: -31px; } - :global(.project-screen .bg-3) { right: -14px; top: -19px; } } // ≤380px @@ -2304,9 +3320,21 @@ const customerLogos = [ .hero-images { margin-right: 0; - .top { top: 19px; left: 26px; max-width: 38vw; } - .right { right: -44px; top: 48px; max-width: 46vw; } - .bottom { bottom: 33px; left: 3px; max-width: 49vw; } + .top { + top: 19px; + left: 26px; + max-width: 38vw; + } + .right { + right: -44px; + top: 48px; + max-width: 46vw; + } + .bottom { + bottom: 33px; + left: 3px; + max-width: 49vw; + } } } @@ -2317,11 +3345,11 @@ const customerLogos = [ background-color: transparent; &::before { - content: ""; + content: ''; position: absolute; width: 100vw; height: 100%; - background-color: #F4F8FE; + background-color: #f4f8fe; z-index: -1; left: 49.4%; transform: translateX(-50%); @@ -2338,7 +3366,7 @@ const customerLogos = [ background-color: var(--color-bg); padding: 46px; border-radius: 24px; - border: 1px solid #2A7DEC; + border: 1px solid #2a7dec; box-shadow: 0 26px 40px 0 rgba(42, 125, 236, 0.08); } @@ -2386,7 +3414,7 @@ const customerLogos = [ .text-wrap { height: fit-content; padding-left: 17px; - border-left: 3px solid #2A7DEC; + border-left: 3px solid #2a7dec; margin-bottom: 16px; p { @@ -2395,7 +3423,9 @@ const customerLogos = [ font-weight: 400; line-height: 28px; - &:first-child { margin-bottom: 12px; } + &:first-child { + margin-bottom: 12px; + } } } } @@ -2404,7 +3434,7 @@ const customerLogos = [ display: flex; justify-content: space-between; align-items: center; - border-top: 1px solid #E5EFFC; + border-top: 1px solid #e5effc; padding-top: 32px; .vision-footer-text { @@ -2434,7 +3464,9 @@ const customerLogos = [ justify-content: start; width: 70%; - .vision-img { max-width: 250px; } + .vision-img { + max-width: 250px; + } } } } @@ -2442,9 +3474,13 @@ const customerLogos = [ // ≤959px — vision @media (max-width: 959px) { .vision-section { - .vision-wrapper { padding: 32px; } + .vision-wrapper { + padding: 32px; + } - .vision-info { gap: 28px; } + .vision-info { + gap: 28px; + } .vision-header { width: 100%; @@ -2462,7 +3498,9 @@ const customerLogos = [ align-items: flex-start; gap: 28px; - .vision-footer-text { text-align: left; } + .vision-footer-text { + text-align: left; + } } } } @@ -2472,25 +3510,43 @@ const customerLogos = [ .vision-section { padding: 40px 0; - .vision-wrapper { padding: 46px 24px; } + .vision-wrapper { + padding: 46px 24px; + } .vision-title { display: flex; gap: 16px; margin: 0; - .vision-img { width: 100%; display: none; } - .vision-img-mobile { display: block; } + .vision-img { + width: 100%; + display: none; + } + .vision-img-mobile { + display: block; + } - .name { font-size: 18px; } - .vision-title-text { font-size: 16px; } + .name { + font-size: 18px; + } + .vision-title-text { + font-size: 16px; + } } - .vision-descr .text-wrap p { font-size: 14px; } + .vision-descr .text-wrap p { + font-size: 14px; + } .vision-footer { - .vision-footer-text { font-size: 18px; line-height: 30px; } - .cdu-button { width: 100%; } + .vision-footer-text { + font-size: 18px; + line-height: 30px; + } + .cdu-button { + width: 100%; + } } } } @@ -2533,7 +3589,7 @@ const customerLogos = [ background-size: cover; &::after { - content: ""; + content: ''; position: absolute; top: 0; right: 0; @@ -2546,14 +3602,20 @@ const customerLogos = [ } &:hover { - &::after { transform: scale(1.2); } + &::after { + transform: scale(1.2); + } .content .footer { padding-bottom: 45px; .stats p { - .short { opacity: 0; } - .long { opacity: 1; } + .short { + opacity: 0; + } + .long { + opacity: 1; + } } } } @@ -2576,8 +3638,8 @@ const customerLogos = [ width: 100%; .glass-tag { - color: #1C1C1B; - background: rgba(255, 255, 255, 0.60); + color: #1c1c1b; + background: rgba(255, 255, 255, 0.6); font-size: 14px; font-weight: 500; line-height: 24px; @@ -2610,7 +3672,10 @@ const customerLogos = [ } } - .logo { height: 36px; width: auto; } + .logo { + height: 36px; + width: auto; + } } .footer { @@ -2624,7 +3689,7 @@ const customerLogos = [ transition: all 0.5s; padding-bottom: 12px; margin-bottom: 12px; - border-bottom: 1px solid #B9C0C5; + border-bottom: 1px solid #b9c0c5; } .stats { @@ -2641,7 +3706,9 @@ const customerLogos = [ flex-shrink: 0; position: relative; - &:last-child { width: auto; } + &:last-child { + width: auto; + } .num { font-size: 24px; @@ -2649,13 +3716,16 @@ const customerLogos = [ line-height: 36px; } - .short, .long { + .short, + .long { position: absolute; transition: opacity 0.5s linear; white-space: nowrap; } - .long { opacity: 0; } + .long { + opacity: 0; + } } } } @@ -2665,12 +3735,16 @@ const customerLogos = [ // ≤1350px — case studies @media (max-width: 1350px) { - #case-studies-clients .wrap .client-card { width: calc((100% - 32px) / 2); } + #case-studies-clients .wrap .client-card { + width: calc((100% - 32px) / 2); + } } // ≤959px — case studies @media (max-width: 959px) { - #case-studies-clients .wrap .client-card { width: 100%; } + #case-studies-clients .wrap .client-card { + width: 100%; + } } // ≤599px — case studies @@ -2678,7 +3752,10 @@ const customerLogos = [ #case-studies-clients { padding: 40px 0; - h2 { font-size: 28px; line-height: 44px; } + h2 { + font-size: 28px; + line-height: 44px; + } .wrap .client-card { width: 100%; @@ -2686,7 +3763,9 @@ const customerLogos = [ .bg-wrap .content .footer .stats { justify-content: space-around; - p { width: 109px; } + p { + width: 109px; + } } } } @@ -2699,11 +3778,11 @@ const customerLogos = [ background-color: transparent; &::before { - content: ""; + content: ''; position: absolute; width: 100vw; height: 100%; - background-color: #F4F8FE; + background-color: #f4f8fe; z-index: -1; left: 49.4%; transform: translateX(-50%); @@ -2763,8 +3842,8 @@ const customerLogos = [ display: block; width: 8px; height: 8px; - border-right: 2px solid #6B7178; - border-bottom: 2px solid #6B7178; + border-right: 2px solid #6b7178; + border-bottom: 2px solid #6b7178; transform: rotate(45deg); transition: transform 0.6s; flex-shrink: 0; @@ -2798,9 +3877,11 @@ const customerLogos = [ max-height: 370px; .expansion-header { - border-bottom: 1px solid #BDBDBD; + border-bottom: 1px solid #bdbdbd; - &::after { transform: rotate(-135deg); } + &::after { + transform: rotate(-135deg); + } } .expansion-content { @@ -2816,7 +3897,10 @@ const customerLogos = [ overflow: hidden; text-align: left; opacity: 0; - transition: opacity 0.4s ease-in-out, max-height 0.4s ease-in-out, padding 0.4s ease-in-out; + transition: + opacity 0.4s ease-in-out, + max-height 0.4s ease-in-out, + padding 0.4s ease-in-out; ul { display: flex; @@ -2831,7 +3915,9 @@ const customerLogos = [ line-height: 24px; color: #424242; - &::marker { color: #2A7DEC; } + &::marker { + color: #2a7dec; + } } } } @@ -2872,13 +3958,17 @@ const customerLogos = [ // ≤1100px — services @media (max-width: 1100px) { .services { - .cards .expansion-card { width: calc(50% - 8px); } + .cards .expansion-card { + width: calc(50% - 8px); + } } } // ≤750px — services 1 col @media (max-width: 750px) { - .services .cards .expansion-card { width: 100%; } + .services .cards .expansion-card { + width: 100%; + } } // ≤599px — services @@ -2886,8 +3976,14 @@ const customerLogos = [ .services { padding: 40px 0; - .services-title { font-size: 28px; line-height: 44px; } - .services-sub-title { font-size: 16px; line-height: 28px; } + .services-title { + font-size: 28px; + line-height: 44px; + } + .services-sub-title { + font-size: 16px; + line-height: 28px; + } .cards .expansion-card { width: 100%; @@ -2958,7 +4054,7 @@ const customerLogos = [ max-width: 50%; width: 50%; scrollbar-width: thin; - scrollbar-color: #ADB5BD transparent; + scrollbar-color: #adb5bd transparent; padding-right: 16px; .menu-item { @@ -2968,13 +4064,17 @@ const customerLogos = [ padding: 20px 32px; cursor: pointer; - &:hover .menu-item-header h3 { color: #000; } + &:hover .menu-item-header h3 { + color: #000; + } &.active { border-radius: 24px; - background: #F4F8FE; + background: #f4f8fe; - .menu-item-header h3 { color: #000; } + .menu-item-header h3 { + color: #000; + } } .menu-item-header { @@ -2989,7 +4089,7 @@ const customerLogos = [ font-size: 24px; font-weight: 400; line-height: 36px; - color: #3D3D3D; + color: #3d3d3d; } } } @@ -3004,7 +4104,9 @@ const customerLogos = [ gap: 32px; } - :global(.industries-card.inline) { display: none; } + :global(.industries-card.inline) { + display: none; + } } // Industries card inner content — fully global (injected via innerHTML) @@ -3023,7 +4125,9 @@ const customerLogos = [ color: #212121; } - :global(.industries-card .card-descr) { margin-bottom: 32px; } + :global(.industries-card .card-descr) { + margin-bottom: 32px; + } :global(.industries-card ul) { display: flex; @@ -3034,18 +4138,22 @@ const customerLogos = [ :global(.industries-card ul li) { list-style-type: disc; - color: #3D3D3D; + color: #3d3d3d; font-size: 16px; font-weight: 400; line-height: 28px; } - :global(.industries-card ul li::marker) { color: #2A7DEC; } + :global(.industries-card ul li::marker) { + color: #2a7dec; + } // ≤1280px — industries (mobile: inline card) @media (max-width: 1280px) { .industries { - .industries-title { text-align: center; } + .industries-title { + text-align: center; + } .content-container { width: 100%; @@ -3064,13 +4172,19 @@ const customerLogos = [ flex-direction: column; padding: 16px 0; - &.active .menu-item-header { padding-bottom: 0; } + &.active .menu-item-header { + padding-bottom: 0; + } - .menu-item-header { padding: 16px 32px; } + .menu-item-header { + padding: 16px 32px; + } } } - :global(.industries-card.global) { display: none; } + :global(.industries-card.global) { + display: none; + } :global(.industries-card.inline) { display: flex; @@ -3078,8 +4192,14 @@ const customerLogos = [ max-width: 95%; } - :global(.industries-card.inline .card-descr) { width: 60%; } - :global(.industries-card.inline .card-img) { max-width: 300px; bottom: 20px; right: 20px; } + :global(.industries-card.inline .card-descr) { + width: 60%; + } + :global(.industries-card.inline .card-img) { + max-width: 300px; + bottom: 20px; + right: 20px; + } } } @@ -3088,9 +4208,13 @@ const customerLogos = [ .industries { padding: 40px 0; - .industries-container { padding: 10px; } + .industries-container { + padding: 10px; + } - .menu .menu-item { padding: 12px 0; } + .menu .menu-item { + padding: 12px 0; + } } :global(.industries-card.inline) { @@ -3099,8 +4223,12 @@ const customerLogos = [ line-height: 21px; } - :global(.industries-card.inline .card-img) { display: none; } - :global(.industries-card.inline .card-descr) { width: 100%; } + :global(.industries-card.inline .card-img) { + display: none; + } + :global(.industries-card.inline .card-descr) { + width: 100%; + } } // ── Trusted Partner Section ────────────────────────────────────────────────── @@ -3110,11 +4238,11 @@ const customerLogos = [ position: relative; &::before { - content: ""; + content: ''; position: absolute; width: 100vw; height: 100%; - background-color: #F4F8FE; + background-color: #f4f8fe; z-index: -1; left: 49.4%; transform: translateX(-50%); @@ -3161,8 +4289,8 @@ const customerLogos = [ &::before { content: '✓'; - color: #FAFBFC; - background-color: #2A7DEC; + color: #fafbfc; + background-color: #2a7dec; border-radius: 50%; font-size: 25px; font-weight: 600; @@ -3197,7 +4325,7 @@ const customerLogos = [ display: flex; flex-direction: column; gap: 12px; - border-left: 3px solid #2A7DEC; + border-left: 3px solid #2a7dec; padding-left: 17px; margin-bottom: 32px; @@ -3216,8 +4344,13 @@ const customerLogos = [ align-items: center; gap: 16px; - .avatar { max-width: 220px; height: auto; } - .avatar-mobile { display: none; } + .avatar { + max-width: 220px; + height: auto; + } + .avatar-mobile { + display: none; + } .trusted-partner-text { .name { @@ -3237,13 +4370,19 @@ const customerLogos = [ // ≤1279px — trusted partner @media (max-width: 1279px) { - .trusted-partner .trusted-partner-container { padding: 40px; } - .trusted-partner .trusted-partner-avatar .avatar { max-width: 245px; } + .trusted-partner .trusted-partner-container { + padding: 40px; + } + .trusted-partner .trusted-partner-avatar .avatar { + max-width: 245px; + } } // ≤959px — trusted partner @media (max-width: 959px) { - .trusted-partner .trusted-partner-container { padding: 20px; } + .trusted-partner .trusted-partner-container { + padding: 20px; + } .trusted-partner .trusted-partner-footer { flex-direction: column-reverse; gap: 20px; @@ -3252,8 +4391,12 @@ const customerLogos = [ .trusted-partner-avatar { width: 100%; - .avatar { margin: 0 auto; } - .trusted-partner-text { text-align: left; } + .avatar { + margin: 0 auto; + } + .trusted-partner-text { + text-align: left; + } } } } @@ -3263,8 +4406,13 @@ const customerLogos = [ .trusted-partner { padding: 40px 0; - .trusted-partner-title { font-size: 28px; line-height: 44px; } - .trusted-partner-container { padding: 20px 0; } + .trusted-partner-title { + font-size: 28px; + line-height: 44px; + } + .trusted-partner-container { + padding: 20px 0; + } .trusted-tips { gap: 45px; @@ -3274,19 +4422,35 @@ const customerLogos = [ font-weight: 400; line-height: 32px; - &::before { width: 32px; height: 32px; font-size: 14px; } + &::before { + width: 32px; + height: 32px; + font-size: 14px; + } } } - .trusted-partner-header-descr p { font-size: 16px; font-weight: 400; line-height: 30px; } + .trusted-partner-header-descr p { + font-size: 16px; + font-weight: 400; + line-height: 30px; + } - .trusted-partner-descr p { font-size: 14px; font-weight: 400; } + .trusted-partner-descr p { + font-size: 14px; + font-weight: 400; + } .trusted-partner-avatar { flex-direction: row; - .avatar { width: 100%; display: none; } - .avatar-mobile { display: block; } + .avatar { + width: 100%; + display: none; + } + .avatar-mobile { + display: block; + } } } } @@ -3299,11 +4463,11 @@ const customerLogos = [ background-color: transparent; &::before { - content: ""; + content: ''; position: absolute; width: 100vw; height: 100%; - background-color: #F4F8FE; + background-color: #f4f8fe; z-index: -1; left: 49.4%; transform: translateX(-50%); @@ -3319,13 +4483,16 @@ const customerLogos = [ color: #212121; } - .mobile-container { display: none; } + .mobile-container { + display: none; + } table { width: 100%; border-collapse: collapse; - th, td { + th, + td { padding: 10px 20px; text-align: center; font-size: 16px; @@ -3334,7 +4501,7 @@ const customerLogos = [ border: 4px solid #f4f7fa; border-radius: 7px; background: #fff; - color: #3D3D3D; + color: #3d3d3d; height: 75px; } @@ -3350,30 +4517,38 @@ const customerLogos = [ thead th:first-child { width: 30%; - background-color: #F4F8FE; + background-color: #f4f8fe; border-radius: 0; } - thead th:not(:first-child) { width: 35%; } + thead th:not(:first-child) { + width: 35%; + } tbody td:first-child { font-weight: 400; color: #212529; width: 30%; - background-color: #F4F8FE; + background-color: #f4f8fe; border-radius: 0; text-align: left; } - tbody td:not(:first-child) { width: 35%; } + tbody td:not(:first-child) { + width: 35%; + } - tr:last-child td { border-bottom: none; } + tr:last-child td { + border-bottom: none; + } } } // ≤1279px — fast delivery @media (max-width: 1279px) { - .fast-delivery table td { padding: 20px; } + .fast-delivery table td { + padding: 20px; + } } // ≤959px — fast delivery @@ -3381,7 +4556,9 @@ const customerLogos = [ .fast-delivery { padding: 100px 10px; - .table-container { display: none; } + .table-container { + display: none; + } .mobile-container { display: flex; @@ -3403,7 +4580,7 @@ const customerLogos = [ font-size: 14px; line-height: 24px; font-weight: 400; - color: #3D3D3D; + color: #3d3d3d; text-align: left; box-shadow: 0 26px 40px 0 rgba(42, 125, 236, 0.08); } @@ -3422,7 +4599,7 @@ const customerLogos = [ font-size: 16px; font-weight: 500; line-height: 28px; - color: #1F2021; + color: #1f2021; } } } @@ -3434,8 +4611,14 @@ const customerLogos = [ padding: 40px 0; padding-top: 0; - .fast-delivery-title { padding: 0; font-size: 24px; line-height: 36px; } - .table-container { overflow-x: scroll; } + .fast-delivery-title { + padding: 0; + font-size: 24px; + line-height: 36px; + } + .table-container { + overflow-x: scroll; + } } } @@ -3446,11 +4629,13 @@ const customerLogos = [ gap: 64px; align-items: flex-start; - img { flex-shrink: 0; } + img { + flex-shrink: 0; + } .quote-text { p { - color: #3A3B3D; + color: #3a3b3d; font-style: italic; font-size: 18px; font-weight: 400; @@ -3459,7 +4644,7 @@ const customerLogos = [ margin-bottom: 32px; a.read-more-link { - color: #3D3D3D; + color: #3d3d3d; font-style: normal; text-decoration: underline; } @@ -3482,7 +4667,9 @@ const customerLogos = [ flex-direction: column; padding: 40px 0; - img { display: none; } + img { + display: none; + } } } @@ -3492,11 +4679,11 @@ const customerLogos = [ position: relative; &::before { - content: ""; + content: ''; position: absolute; width: 100vw; height: 100%; - background-color: #F4F8FE; + background-color: #f4f8fe; z-index: -1; left: 49.4%; transform: translateX(-50%); @@ -3542,13 +4729,16 @@ const customerLogos = [ line-height: 28px; } } - } // ≤1279px — more feature @media (max-width: 1279px) { - .more-feature .cards .card { padding: 32px; } - .more-feature :global(.banner-img) { display: none; } + .more-feature .cards .card { + padding: 32px; + } + .more-feature :global(.banner-img) { + display: none; + } } // ≤959px — more feature @@ -3558,7 +4748,11 @@ const customerLogos = [ margin-bottom: 80px; width: 100%; - .card { margin-bottom: 0; width: 48%; flex: unset; } + .card { + margin-bottom: 0; + width: 48%; + flex: unset; + } } } @@ -3567,16 +4761,26 @@ const customerLogos = [ .more-feature { padding: 40px 0; - .more-feature-title { font-size: 24px; line-height: 36px; } + .more-feature-title { + font-size: 24px; + line-height: 36px; + } .cards { flex-direction: column; margin-bottom: 32px; - .card { width: 100%; margin-bottom: 0; padding: 32px; } - .card-title { font-size: 24px; line-height: 36px; margin-bottom: 0; } + .card { + width: 100%; + margin-bottom: 0; + padding: 32px; + } + .card-title { + font-size: 24px; + line-height: 36px; + margin-bottom: 0; + } } - } } @@ -3619,7 +4823,7 @@ const customerLogos = [ font-weight: 500; line-height: 30px; text-align: center; - border-bottom: 1px solid #9E9E9E; + border-bottom: 1px solid #9e9e9e; &:first-child { text-align: left; @@ -3629,7 +4833,7 @@ const customerLogos = [ th:not(:last-child), td:not(:last-child) { - border-right: 1px dashed #9E9E9E; + border-right: 1px dashed #9e9e9e; } th:first-child, @@ -3643,9 +4847,15 @@ const customerLogos = [ tbody { tr { - &:nth-child(4).highlight-row { background-color: #F2F7FE; } - &:hover { background-color: #F2F7FE; } - &:hover td:first-child { font-weight: 500; } + &:nth-child(4).highlight-row { + background-color: #f2f7fe; + } + &:hover { + background-color: #f2f7fe; + } + &:hover td:first-child { + font-weight: 500; + } } td { @@ -3670,7 +4880,11 @@ const customerLogos = [ overflow: hidden; position: relative; color: rgb(33, 37, 41); - transition: height 0.3s ease-in-out, width 0.3s ease-in-out, transform 0.3s ease-in-out, text-align 0.3s; + transition: + height 0.3s ease-in-out, + width 0.3s ease-in-out, + transform 0.3s ease-in-out, + text-align 0.3s; cursor: default; p { @@ -3684,12 +4898,14 @@ const customerLogos = [ margin-bottom: 8px; } - &:last-child { opacity: 0; } + &:last-child { + opacity: 0; + } } &.first { - border: 1px solid #B5C0CE; - background: linear-gradient(90deg, #FFF 0%, #B5C0CE 100%); + border: 1px solid #b5c0ce; + background: linear-gradient(90deg, #fff 0%, #b5c0ce 100%); width: 150%; &:hover { @@ -3699,13 +4915,15 @@ const customerLogos = [ text-align: left; height: 136px; - p:last-child { opacity: 1; } + p:last-child { + opacity: 1; + } } } &.second { - border: 1px solid rgba(42, 125, 236, 0.40); - background: #D9EBFF; + border: 1px solid rgba(42, 125, 236, 0.4); + background: #d9ebff; width: 100%; margin-left: 50%; @@ -3715,13 +4933,15 @@ const customerLogos = [ text-align: left; height: 136px; - p:last-child { opacity: 1; } + p:last-child { + opacity: 1; + } } } &.third { - border: 1px solid rgba(42, 125, 236, 0.60); - background: #BBD5F9; + border: 1px solid rgba(42, 125, 236, 0.6); + background: #bbd5f9; width: 50%; margin-left: 50%; padding: 6px 2px; @@ -3732,12 +4952,14 @@ const customerLogos = [ text-align: left; height: 136px; - p:last-child { opacity: 1; } + p:last-child { + opacity: 1; + } } } &.fourth { - border: 1px solid #2670D4; + border: 1px solid #2670d4; background: #1e67d4; width: 100%; color: white; @@ -3745,7 +4967,9 @@ const customerLogos = [ padding: 4px 1px; text-align: center; - p { color: white; } + p { + color: white; + } &:hover { padding-left: 8px; @@ -3754,13 +4978,15 @@ const customerLogos = [ text-align: left; height: 136px; - p:last-child { opacity: 1; } + p:last-child { + opacity: 1; + } } } &.fifth { - border: 1px solid rgba(42, 125, 236, 0.60); - background: #BBD5F9; + border: 1px solid rgba(42, 125, 236, 0.6); + background: #bbd5f9; width: 200%; height: 54px; @@ -3770,13 +4996,15 @@ const customerLogos = [ text-align: left; height: 136px; - p:last-child { opacity: 1; } + p:last-child { + opacity: 1; + } } } &.sixth { - border: 1px solid #2670D4; - background: #D9EBFF; + border: 1px solid #2670d4; + background: #d9ebff; width: 50%; padding: 6px 2px; @@ -3787,13 +5015,15 @@ const customerLogos = [ height: 136px; transform: translateX(-92px); - p:last-child { opacity: 1; } + p:last-child { + opacity: 1; + } } } &.seventh { - border: 1px solid #B5C0CE; - background: linear-gradient(90deg, #B5C0CE 0%, #FFF 100%); + border: 1px solid #b5c0ce; + background: linear-gradient(90deg, #b5c0ce 0%, #fff 100%); width: 150%; margin-left: 50%; @@ -3804,7 +5034,9 @@ const customerLogos = [ height: 136px; transform: translateX(-147px); - p:last-child { opacity: 1; } + p:last-child { + opacity: 1; + } } } } @@ -3820,7 +5052,9 @@ const customerLogos = [ // ≤1279px — project-timeline → mobile layout @media (max-width: 1279px) { .project-timeline { - .table-container { display: none; } + .table-container { + display: none; + } .mobile-timeline { display: flex; @@ -3837,10 +5071,12 @@ const customerLogos = [ font-weight: 400; line-height: 30px; letter-spacing: 0.15px; - color: #3D3D3D; + color: #3d3d3d; border-bottom: 1px dashed #757575; - &:last-child { border-bottom: none; } + &:last-child { + border-bottom: none; + } } } @@ -3868,13 +5104,16 @@ const customerLogos = [ font-weight: 400; line-height: 30px; letter-spacing: 0.15px; - color: #3D3D3D; + color: #3d3d3d; } p:last-child { max-height: 0; overflow: hidden; - transition: max-height 0.5s ease-in-out, margin-top 0.5s ease-in-out, opacity 0.4s ease-in-out; + transition: + max-height 0.5s ease-in-out, + margin-top 0.5s ease-in-out, + opacity 0.4s ease-in-out; margin-top: 0; opacity: 0; } @@ -3899,19 +5138,19 @@ const customerLogos = [ // even with a 1500px cap. &:nth-child(1) { padding: 51.5px 16px; - background: linear-gradient(180deg, #FFF 0%, #B5C0CE 100%); + background: linear-gradient(180deg, #fff 0%, #b5c0ce 100%); min-height: 167px; } &:nth-child(2) { padding: 34px 16px; - background: #D4E5FB; + background: #d4e5fb; min-height: 132px; } &:nth-child(3) { padding: 4px 16px; - background: #BBD5F9; + background: #bbd5f9; min-height: 72px; } @@ -3920,24 +5159,27 @@ const customerLogos = [ background: #1e67d4; min-height: 132px; - p, h3 { color: white; } + p, + h3 { + color: white; + } } &:nth-child(5) { padding: 100px 16px; - background: #BBD5F9; + background: #bbd5f9; min-height: 264px; } &:nth-child(6) { padding: 4px 16px; - background: #D4E5FB; + background: #d4e5fb; min-height: 72px; } &:nth-child(7) { padding: 51.5px 16px; - background: linear-gradient(180deg, #B5C0CE 0%, #FFF 100%); + background: linear-gradient(180deg, #b5c0ce 0%, #fff 100%); min-height: 167px; } } @@ -3952,810 +5194,922 @@ const customerLogos = [ padding: 40px 0; .mobile-timeline { - .mt-left div { padding-left: 0; } + .mt-left div { + padding-left: 0; + } .mt-right > div { - h3 { font-size: 18px; line-height: 30px; } - p { font-size: 16px; line-height: 28px; } + h3 { + font-size: 18px; + line-height: 30px; + } + p { + font-size: 16px; + line-height: 28px; + } } - .mt-right > div:nth-child(4) { padding-top: 9%; } - .mt-right > div:nth-child(5) { padding-top: 28%; } + .mt-right > div:nth-child(4) { + padding-top: 9%; + } + .mt-right > div:nth-child(5) { + padding-top: 28%; + } } } } -// ─── ENGAGEMENT MODELS ────────────────────────────────────────────────────── + // ─── ENGAGEMENT MODELS ────────────────────────────────────────────────────── -.engagement-models { - padding: 100px 0; - position: relative; + .engagement-models { + padding: 100px 0; + position: relative; - &::before { - content: ''; - position: absolute; - top: 0; - left: 49.4%; - transform: translateX(-50%); - width: 100vw; - height: 100%; - background-color: #F4F8FE; - z-index: -1; - } + &::before { + content: ''; + position: absolute; + top: 0; + left: 49.4%; + transform: translateX(-50%); + width: 100vw; + height: 100%; + background-color: #f4f8fe; + z-index: -1; + } - .engagement-model-container { - display: flex; - gap: 20px; - flex-direction: column; - align-items: center; - justify-content: center; - margin-bottom: 40px; - } + .engagement-model-container { + display: flex; + gap: 20px; + flex-direction: column; + align-items: center; + justify-content: center; + margin-bottom: 40px; + } - .engagement-model-title { - font-size: 36px; - font-weight: 500; - line-height: 48px; - color: #212121; - margin-bottom: 16px; - text-align: center; + .engagement-model-title { + font-size: 36px; + font-weight: 500; + line-height: 48px; + color: #212121; + margin-bottom: 16px; + text-align: center; + } + + .engagement-model-descr { + text-align: center; + max-width: 824px; + font-size: 18px; + font-weight: 400; + color: #424242; + margin-bottom: 40px; + line-height: 30px; + } + + .em-container { + display: flex; + gap: 32px; + width: 100%; + } + + .em-card { + flex: 1; + padding: 46px; + display: flex; + flex-direction: column; + border: 1px solid #ddeafc; + border-radius: 24px; + box-shadow: 0 26px 40px 0 rgba(0, 0, 0, 0.08); + background-color: #fff; + + & > img:first-child { + margin: 0 auto 16px; + } + + h3 { + font-size: 28px; + font-weight: 500; + line-height: 44px; + text-align: center; + margin-bottom: 8px; + color: #212121; + } + + .em-subtitle { + font-size: 16px; + font-weight: 400; + line-height: 28px; + color: #3d3d3d; + text-align: center; + margin-bottom: 40px; + white-space: break-spaces; + } + + .em-btn { + font-size: 16px; + margin-bottom: 40px; + align-self: center; + } + + h4 { + font-size: 18px; + font-weight: 500; + line-height: 30px; + color: #212121; + margin-bottom: 16px; + } + + ul:first-of-type { + margin-bottom: 40px; + } + + li { + display: flex; + margin-bottom: 12px; + + img { + margin-right: 12px; + } + + p { + font-size: 14px; + font-weight: 400; + line-height: 24px; + color: #212121; + } + } + } } - .engagement-model-descr { - text-align: center; - max-width: 824px; - font-size: 18px; - font-weight: 400; - color: #424242; - margin-bottom: 40px; - line-height: 30px; + // ≤1279px — engagement models + @media (max-width: 1279px) { + .engagement-models .em-container { + flex-direction: column; + max-width: unset; + + .em-card:first-child h3 { + width: unset; + margin-left: auto; + margin-right: auto; + } + } } - .em-container { - display: flex; - gap: 32px; - width: 100%; + // ≤959px — engagement models + @media (max-width: 959px) { + .engagement-models { + padding: 40px 0; + + .engagement-model-title { + font-size: 24px; + line-height: 36px; + } + .engagement-model-descr { + font-size: 16px; + line-height: 28px; + } + + .em-card { + padding: 32px; + + h3 { + font-size: 24px; + line-height: 36px; + } + + ul:first-of-type li img { + margin-top: 3px; + } + li { + align-items: flex-start; + } + } + } } - .em-card { - flex: 1; - padding: 46px; - display: flex; - flex-direction: column; - border: 1px solid #DDEAFC; - border-radius: 24px; - box-shadow: 0 26px 40px 0 rgba(0, 0, 0, 0.08); - background-color: #FFF; + // ─── REVIEWS ──────────────────────────────────────────────────────────────── - & > img:first-child { - margin: 0 auto 16px; - } + .reviews { + padding: 40px 0 0; + background: transparent; - h3 { - font-size: 28px; + .reviews-title { + font-size: 36px; font-weight: 500; - line-height: 44px; + line-height: 48px; text-align: center; - margin-bottom: 8px; color: #212121; - } - - .em-subtitle { - font-size: 16px; - font-weight: 400; - line-height: 28px; - color: #3D3D3D; - text-align: center; margin-bottom: 40px; - white-space: break-spaces; } - .em-btn { - font-size: 16px; + .reviews-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 24px; margin-bottom: 40px; - align-self: center; } + } - h4 { - font-size: 18px; - font-weight: 500; - line-height: 30px; - color: #212121; - margin-bottom: 16px; + @media (max-width: 959px) { + .reviews .reviews-grid { + grid-template-columns: 1fr; + margin-bottom: 0; } + } - ul:first-of-type { margin-bottom: 40px; } - - li { - display: flex; - margin-bottom: 12px; + // ─── CONTACT BANNER ───────────────────────────────────────────────────────── - img { margin-right: 12px; } + .contact { + padding: 100px 0; + background: transparent; + } - p { - font-size: 14px; - font-weight: 400; - line-height: 24px; - color: #212121; - } + @media (max-width: 959px) { + .contact { + padding: 40px 0; } } -} -// ≤1279px — engagement models -@media (max-width: 1279px) { - .engagement-models .em-container { + // ─── FAQ ───────────────────────────────────────────────────────────────────── + + .faq-iot-development { + display: flex; flex-direction: column; - max-width: unset; + padding: 100px 0; + z-index: 10; - .em-card:first-child h3 { - width: unset; - margin-left: auto; - margin-right: auto; + .faq-section-title { + font-size: 36px; + font-weight: 500; + line-height: 48px; + margin-bottom: 56px; + text-align: center; + color: #212529; + white-space: normal; + padding: 0; } - } -} -// ≤959px — engagement models -@media (max-width: 959px) { - .engagement-models { - padding: 40px 0; + .faq-section-content { + display: flex; + gap: 20px; + } - .engagement-model-title { font-size: 24px; line-height: 36px; } - .engagement-model-descr { font-size: 16px; line-height: 28px; } + .faq-section-selector { + display: flex; + flex-direction: column; + gap: 16px; + align-items: flex-start; + padding: 8px; + width: fit-content; + color: rgba(0, 0, 0, 0.38); - .em-card { - padding: 32px; + .faq-section-option { + width: 100%; + font-size: 24px; + font-weight: 500; + line-height: 36px; + padding: 16px 24px; + border: 1.5px solid transparent; + border-radius: 16px; + cursor: pointer; + color: #757575; + white-space: nowrap; - h3 { font-size: 24px; line-height: 36px; } + &:hover { + color: #2a2e33; + } - ul:first-of-type li img { margin-top: 3px; } - li { align-items: flex-start; } + &.active { + color: #202021; + background: #f4f8fe; + } + } } - } -} -// ─── REVIEWS ──────────────────────────────────────────────────────────────── + .answers { + flex: 1.5; -.reviews { - padding: 40px 0 0; - background: transparent; + .pi-accordion { + display: none; - .reviews-title { - font-size: 36px; - font-weight: 500; - line-height: 48px; - text-align: center; - color: #212121; - margin-bottom: 40px; - } + &.active { + display: block; + } + } - .reviews-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 24px; - margin-bottom: 40px; - } -} + .item { + border-bottom: 1.5px solid #dee2e6; + overflow: visible; + position: relative; -@media (max-width: 959px) { - .reviews .reviews-grid { - grid-template-columns: 1fr; - margin-bottom: 0; - } -} + &:not(:last-of-type) { + margin-bottom: 7px; + } -// ─── CONTACT BANNER ───────────────────────────────────────────────────────── + h3.title { + font-size: 18px; + font-weight: 500; + line-height: 30px; + color: #212529; + padding: 22px 37px 22px 20px; + margin: 0; + cursor: pointer; + position: relative; + white-space: normal; + + &:hover { + color: rgba(33, 33, 33, 0.78); + } -.contact { - padding: 100px 0; - background: transparent; -} + // CSS chevron + &::after { + content: ''; + display: block; + position: absolute; + right: 12px; + top: 50%; + width: 8px; + height: 8px; + border-right: 2px solid rgba(0, 0, 0, 0.38); + border-bottom: 2px solid rgba(0, 0, 0, 0.38); + transform: translateY(-70%) rotate(45deg); + transition: transform 0.3s; + } + } -@media (max-width: 959px) { - .contact { padding: 40px 0; } -} + .content { + max-height: 0; + overflow: hidden; + transition: max-height 0.35s ease; + border: none; + box-shadow: none; + border-radius: 4px; + padding: 0 50px 0 10px; + margin: 0 10px; -// ─── FAQ ───────────────────────────────────────────────────────────────────── + .container { + max-width: unset; + padding-bottom: 16px; -.faq-iot-development { - display: flex; - flex-direction: column; - padding: 100px 0; - z-index: 10; + > *:not(:last-child) { + padding-bottom: 20px; + } + } - .faq-section-title { - font-size: 36px; - font-weight: 500; - line-height: 48px; - margin-bottom: 56px; - text-align: center; - color: #212529; - white-space: normal; - padding: 0; - } + ol { + list-style-type: decimal; + padding-left: 20px; - .faq-section-content { - display: flex; - gap: 20px; - } + li { + list-style: decimal; + margin-bottom: 16px; + } + } - .faq-section-selector { - display: flex; - flex-direction: column; - gap: 16px; - align-items: flex-start; - padding: 8px; - width: fit-content; - color: rgba(0, 0, 0, 0.38); + p, + li { + font-size: 14px; + font-weight: 400; + color: #3d3d3d; + line-height: 24px; + } - .faq-section-option { - width: 100%; - font-size: 24px; - font-weight: 500; - line-height: 36px; - padding: 16px 24px; - border: 1.5px solid transparent; - border-radius: 16px; - cursor: pointer; - color: #757575; - white-space: nowrap; + span { + display: inline-block; + font-size: 16px; + font-weight: 500; + color: #3d3d3d; + line-height: 24px; + padding-bottom: 16px; + } + } - &:hover { color: #2A2E33; } + &.on { + h3.title::after { + transform: translateY(-30%) rotate(225deg); + } - &.active { - color: #202021; - background: #F4F8FE; + .content { + max-height: 2000px; + } + } } } } - .answers { - flex: 1.5; - - .pi-accordion { - display: none; - - &.active { display: block; } + // ≤1200px — FAQ + @media (max-width: 1200px) { + .faq-iot-development .faq-section-content { + flex-direction: column; } + } - .item { - border-bottom: 1.5px solid #DEE2E6; - overflow: visible; - position: relative; - - &:not(:last-of-type) { margin-bottom: 7px; } - - h3.title { + // ≤1150px — FAQ + @media (max-width: 1150px) { + .faq-iot-development { + .faq-section-title { + font-size: 24px; + } + .faq-section-selector .faq-section-option { font-size: 18px; - font-weight: 500; - line-height: 30px; - color: #212529; - padding: 22px 37px 22px 20px; - margin: 0; - cursor: pointer; - position: relative; - white-space: normal; + } + } + } - &:hover { color: rgba(33, 33, 33, 0.78); } + // ≤959px — FAQ + @media (max-width: 959px) { + .faq-iot-development { + padding: 40px 0; - // CSS chevron - &::after { - content: ''; - display: block; - position: absolute; - right: 12px; - top: 50%; - width: 8px; - height: 8px; - border-right: 2px solid rgba(0, 0, 0, 0.38); - border-bottom: 2px solid rgba(0, 0, 0, 0.38); - transform: translateY(-70%) rotate(45deg); - transition: transform 0.3s; - } + .faq-section-selector { + width: 100%; } - .content { - max-height: 0; - overflow: hidden; - transition: max-height 0.35s ease; - border: none; - box-shadow: none; - border-radius: 4px; - padding: 0 50px 0 10px; - margin: 0 10px; - - .container { - max-width: unset; - padding-bottom: 16px; - - > *:not(:last-child) { padding-bottom: 20px; } + .answers .item { + h3.title { + font-size: 16px; } - ol { - list-style-type: decimal; - padding-left: 20px; - + .content { + p, li { - list-style: decimal; - margin-bottom: 16px; + font-size: 14px; + line-height: 20px; + } + span { + font-size: 15px; + line-height: 22px; } } + } + } + } - p, li { - font-size: 14px; - font-weight: 400; - color: #3D3D3D; - line-height: 24px; + // ≤690px — FAQ selector full width + @media (max-width: 690px) { + .faq-iot-development .faq-section-selector { + width: 100%; + } + } + + // ─── SHARED FORM STYLES (contact form + modal) ─────────────────────────────── + + .contact-us-form, + .dev-modal-sub-content { + .form-section { + width: 100%; + display: flex; + flex-wrap: wrap; + gap: 16px; + + .form-element { + display: inline-block; + position: relative; + width: calc(50% - 8px); + margin-bottom: 8px; + + &.next, + &:last-of-type { + width: 100%; } - span { - display: inline-block; + .form-control { + width: 100%; + margin: 24px 0 0 0; + line-height: 30px; font-size: 16px; - font-weight: 500; - color: #3D3D3D; - line-height: 24px; - padding-bottom: 16px; - } - } + vertical-align: middle; + border: 1px solid #e0e1e2; + background-color: transparent; + border-radius: 6px; + color: #212529; + box-shadow: none; + + &::placeholder { + color: #9e9e9e; + } + &.invalid-input { + border: 1px solid #d9534f; + } + &.invalid-input:focus { + border-color: #d9534f; + box-shadow: 0 0 0 0.2rem rgba(217, 83, 79, 0.25); + } - &.on { - h3.title::after { - transform: translateY(-30%) rotate(225deg); + // Focus uses a box-shadow ring instead of growing the border — + // border width changes shift the input's content box and cause + // a 1px caret/placeholder jump on focus. box-shadow paints + // outside the layout box, so dimensions stay stable. + &:focus { + outline: none; + border-color: #2a7dec; + box-shadow: 0 0 0 1px #2a7dec; + color: #212529; + &::placeholder { + opacity: 0.2; + } + } } - .content { max-height: 2000px; } - } - } - } -} + input.form-control { + height: 44px; + padding: 0 16px; + } -// ≤1200px — FAQ -@media (max-width: 1200px) { - .faq-iot-development .faq-section-content { - flex-direction: column; - } -} + textarea.form-control { + height: 170px; + resize: vertical; + padding: 8px 16px; + margin-bottom: 16px; + &:focus { + cursor: initial; + } + } -// ≤1150px — FAQ -@media (max-width: 1150px) { - .faq-iot-development { - .faq-section-title { font-size: 24px; } - .faq-section-selector .faq-section-option { font-size: 18px; } - } -} + label { + width: 100%; + line-height: 100%; + font-size: 14px; + margin-bottom: 0; + + p { + cursor: text; + position: absolute; + left: unset; + top: unset; + margin: 0 0 0 10px; + padding: 11px 0; + font-size: 14px; + font-weight: 500; + color: #3d3d3d; + transition: 150ms; + transform: scale(1) translate(-10px, -86px); + pointer-events: none; -// ≤959px — FAQ -@media (max-width: 959px) { - .faq-iot-development { - padding: 40px 0; + &.text-area-label { + position: absolute; + top: 68px; + } + } + } - .faq-section-selector { width: 100%; } + .form-control:focus + p, + .form-control:not(.input--empty) + p { + color: inherit; + } - .answers .item { - h3.title { font-size: 16px; } + // :global() because the hint

is created dynamically in JS, so + // it never gets the scoping attribute that surrounding scoped + // styles rely on. The parent (`.cdu-form` / contact-us modal) + // keeps its scope, so the rule only applies inside this form. + :global(.error-message-hint) { + color: #d9534f; + font-size: 14px; + font-weight: 400; + margin-bottom: 0; + width: 100%; + display: block; + box-sizing: border-box; + } + } - .content { - p, li { font-size: 14px; line-height: 20px; } - span { font-size: 15px; line-height: 22px; } + &.mb30 { + margin-bottom: 30px; } } } -} - -// ≤690px — FAQ selector full width -@media (max-width: 690px) { - .faq-iot-development .faq-section-selector { width: 100%; } -} -// ─── SHARED FORM STYLES (contact form + modal) ─────────────────────────────── + // ─── CONTACT US SECTION ─────────────────────────────────────────────────────── -.contact-us-form, -.dev-modal-sub-content { - .form-section { - width: 100%; - display: flex; - flex-wrap: wrap; - gap: 16px; + .contact-us-section { + padding: 100px 0; + position: relative; + background-color: transparent; - .form-element { - display: inline-block; - position: relative; - width: calc(50% - 8px); - margin-bottom: 8px; + &::before { + content: ''; + position: absolute; + width: 100vw; + height: 100%; + background-color: #f4f8fe; + z-index: -1; + left: 49.4%; + transform: translateX(-50%); + top: 0; + } - &.next, &:last-of-type { width: 100%; } + .contact-us-section-content { + max-width: 100%; + margin: 0; + padding: 0 20px; - .form-control { - width: 100%; - margin: 24px 0 0 0; - line-height: 30px; - font-size: 16px; - vertical-align: middle; - border: 1px solid #E0E1E2; - background-color: transparent; - border-radius: 6px; - color: #212529; - box-shadow: none; - - &::placeholder { color: #9E9E9E; } - &.invalid-input { border: 1px solid #D9534F; } - &.invalid-input:focus { border-color: #D9534F; box-shadow: 0 0 0 0.2rem rgba(217, 83, 79, 0.25); } - - // Focus uses a box-shadow ring instead of growing the border — - // border width changes shift the input's content box and cause - // a 1px caret/placeholder jump on focus. box-shadow paints - // outside the layout box, so dimensions stay stable. - &:focus { - outline: none; - border-color: #2a7dec; - box-shadow: 0 0 0 1px #2a7dec; - color: #212529; - &::placeholder { opacity: 0.2; } - } + .contact-us-container { + position: relative; + background: white; + border-radius: 24px; + display: flex; + padding: 8px; + gap: 8px; + box-shadow: + -4px 15px 50px -20px rgba(0, 0, 0, 0.15), + 0 0 8px 0 rgba(0, 0, 0, 0.08); } + } - input.form-control { - height: 44px; - padding: 0 16px; + .contact-us-descr { + & > img:first-child { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + z-index: 1; } - textarea.form-control { - height: 170px; - resize: vertical; - padding: 8px 16px; - margin-bottom: 16px; - &:focus { cursor: initial; } - } + width: 42%; + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 60px 38px; + background: #2a7dec; + border-radius: 16px; + position: relative; - label { - width: 100%; - line-height: 100%; - font-size: 14px; - margin-bottom: 0; + .contact-us-descr-container { + display: flex; + flex-direction: column; + gap: 16px; + z-index: 2; - p { - cursor: text; - position: absolute; - left: unset; - top: unset; - margin: 0 0 0 10px; - padding: 11px 0; - font-size: 14px; + h2 { + font-size: 48px; font-weight: 500; - color: #3D3D3D; - transition: 150ms; - transform: scale(1) translate(-10px, -86px); - pointer-events: none; - - &.text-area-label { position: absolute; top: 68px; } + line-height: 130%; + color: white; + white-space: normal; + padding: 0; } - } - - .form-control:focus + p, - .form-control:not(.input--empty) + p { color: inherit; } - // :global() because the hint

is created dynamically in JS, so - // it never gets the scoping attribute that surrounding scoped - // styles rely on. The parent (`.cdu-form` / contact-us modal) - // keeps its scope, so the rule only applies inside this form. - :global(.error-message-hint) { - color: #D9534F; - font-size: 14px; - font-weight: 400; - margin-bottom: 0; - width: 100%; - display: block; - box-sizing: border-box; + span { + color: white; + font-size: 24px; + font-weight: 500; + line-height: 36px; + margin-bottom: 72px; + } } - } - - &.mb30 { margin-bottom: 30px; } - } -} + .client-avatar-container { + display: flex; + justify-content: flex-start; + gap: 16px; + z-index: 2; -// ─── CONTACT US SECTION ─────────────────────────────────────────────────────── - -.contact-us-section { - padding: 100px 0; - position: relative; - background-color: transparent; + .client-avatar-img img { + max-width: 64px; + height: auto; + } - &::before { - content: ""; - position: absolute; - width: 100vw; - height: 100%; - background-color: #F4F8FE; - z-index: -1; - left: 49.4%; - transform: translateX(-50%); - top: 0; - } + .client-descr { + display: flex; + flex-direction: column; + justify-content: flex-end; + text-align: start; - .contact-us-section-content { - max-width: 100%; - margin: 0; - padding: 0 20px; + .client-name { + font-size: 18px; + font-weight: 500; + line-height: 30px; + color: white; + } - .contact-us-container { - position: relative; - background: white; - border-radius: 24px; - display: flex; - padding: 8px; - gap: 8px; - box-shadow: -4px 15px 50px -20px rgba(0, 0, 0, 0.15), 0 0 8px 0 rgba(0, 0, 0, 0.08); + .client-title { + font-size: 16px; + font-weight: 400; + line-height: 28px; + color: white; + } + } + } } - } - .contact-us-descr { - & > img:first-child { - position: absolute; - bottom: 0; - left: 0; - width: 100%; + .contact-us-form { + width: 58%; z-index: 1; - } + padding: 60px; + border-radius: 24px; + max-height: 817px; + overflow: auto; - width: 42%; - display: flex; - flex-direction: column; - justify-content: space-between; - padding: 60px 38px; - background: #2A7DEC; - border-radius: 16px; - position: relative; + .developmentServicesContactUsForm { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + } - .contact-us-descr-container { - display: flex; - flex-direction: column; - gap: 16px; - z-index: 2; + .cus-hp-container { + position: absolute; + left: -9999px; + } - h2 { - font-size: 48px; - font-weight: 500; - line-height: 130%; - color: white; - white-space: normal; - padding: 0; + .submit-button-container { + display: flex; + justify-content: flex-end; } - span { - color: white; - font-size: 24px; - font-weight: 500; - line-height: 36px; - margin-bottom: 72px; + .cus-submit-btn { + width: 255px; + height: 56px; + font-size: 20px; + text-align: center; + line-height: 1; + padding: 0; } } + } - .client-avatar-container { - display: flex; - justify-content: flex-start; - gap: 16px; - z-index: 2; - - .client-avatar-img img { - max-width: 64px; - height: auto; + @media (max-width: 1279px) { + .contact-us-section { + .contact-us-section-content { + margin-bottom: 0; } - .client-descr { - display: flex; + .contact-us-container { flex-direction: column; - justify-content: flex-end; - text-align: start; + } - .client-name { - font-size: 18px; - font-weight: 500; - line-height: 30px; - color: white; + .contact-us-descr { + width: 100%; + gap: 25px; + padding: 40px; + + & > img:first-child { + display: none; } - .client-title { - font-size: 16px; - font-weight: 400; - line-height: 28px; - color: white; + .client-avatar-container { + flex-direction: row-reverse; } } + + .contact-us-form { + width: 100%; + } } } - .contact-us-form { - width: 58%; - z-index: 1; - padding: 60px; - border-radius: 24px; - max-height: 817px; - overflow: auto; + @media (max-width: 959px) { + .contact-us-section { + padding: 40px 0; - .developmentServicesContactUsForm { - height: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; - } + .contact-us-descr { + padding: 32px; - .cus-hp-container { - position: absolute; - left: -9999px; - } + .contact-us-descr-container { + h2 { + font-size: 24px; + line-height: 36px; + } + span { + font-size: 16px; + line-height: 28px; + } + } - .submit-button-container { - display: flex; - justify-content: flex-end; - } + .client-avatar-container { + flex-direction: column; + } + } - .cus-submit-btn { - width: 255px; - height: 56px; - font-size: 20px; - text-align: center; - line-height: 1; - padding: 0; + .contact-us-form { + padding: 32px; + } } } -} - -@media (max-width: 1279px) { - .contact-us-section { - .contact-us-section-content { margin-bottom: 0; } - .contact-us-container { - flex-direction: column; - } - - .contact-us-descr { - width: 100%; - gap: 25px; - padding: 40px; + // ─── MODAL ─────────────────────────────────────────────────────────────────── - & > img:first-child { display: none; } + .dev-modal { + display: none; + position: fixed; + align-items: center; + justify-content: center; + z-index: 13000; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.4); - .client-avatar-container { flex-direction: row-reverse; } - } + .dev-modal-content { + width: 861px; + max-width: 90%; + max-height: 90%; + display: flex; + flex-direction: column; + animation: animatetop 0.4s; + background-color: #fefefe; + border: 1px solid #888; + border-radius: 24px; + overflow: hidden; + padding: 30px; - .contact-us-form { width: 100%; } - } -} + .dev-modal-title-container { + position: sticky; + top: 0; + background: #fefefe; + z-index: 1; + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; -@media (max-width: 959px) { - .contact-us-section { - padding: 40px 0; + h2 { + font-size: 24px; + font-weight: 500; + white-space: normal; + padding: 0; + } - .contact-us-descr { - padding: 32px; + .dev-modal-close-button { + cursor: pointer; + padding: 4px; - .contact-us-descr-container { - h2 { font-size: 24px; line-height: 36px; } - span { font-size: 16px; line-height: 28px; } + img { + width: 28px; + height: 28px; + display: block; + } + } } - .client-avatar-container { flex-direction: column; } - } - - .contact-us-form { padding: 32px; } - } -} - -// ─── MODAL ─────────────────────────────────────────────────────────────────── - -.dev-modal { - display: none; - position: fixed; - align-items: center; - justify-content: center; - z-index: 13000; - left: 0; - top: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.4); - - .dev-modal-content { - width: 861px; - max-width: 90%; - max-height: 90%; - display: flex; - flex-direction: column; - animation: animatetop 0.4s; - background-color: #fefefe; - border: 1px solid #888; - border-radius: 24px; - overflow: hidden; - padding: 30px; + form { + height: 100%; + display: flex; + flex-direction: column; + flex: 1; + overflow: auto; + } - .dev-modal-title-container { - position: sticky; - top: 0; - background: #fefefe; - z-index: 1; - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 8px; + .cus-hp-container { + position: absolute; + left: -9999px; + } - h2 { - font-size: 24px; - font-weight: 500; - white-space: normal; - padding: 0; + .dev-modal-sub-content { + flex: 1; + overflow-y: auto; + min-height: 0; + padding: 20px 0; } - .dev-modal-close-button { - cursor: pointer; - padding: 4px; + .dev-modal-submit-container { + position: sticky; + bottom: 0; + background: #fefefe; + z-index: 1; + margin-top: auto; + padding-top: 20px; - img { - width: 28px; - height: 28px; - display: block; + .cus-submit-btn { + width: 100%; + height: 56px; + font-size: 20px; + text-align: center; + line-height: 1; + padding: 0; } } } + } - form { - height: 100%; - display: flex; - flex-direction: column; - flex: 1; - overflow: auto; - } - - .cus-hp-container { - position: absolute; - left: -9999px; + @keyframes animatetop { + from { + top: -300px; + opacity: 0; } - - .dev-modal-sub-content { - flex: 1; - overflow-y: auto; - min-height: 0; - padding: 20px 0; + to { + top: 0; + opacity: 1; } + } - .dev-modal-submit-container { - position: sticky; - bottom: 0; - background: #fefefe; - z-index: 1; - margin-top: auto; - padding-top: 20px; + @media (max-width: 959px) { + .dev-modal .dev-modal-content { + .dev-modal-title-container h2 { + font-size: 18px; + } - .cus-submit-btn { + .dev-modal-sub-content .form-section .form-element { width: 100%; - height: 56px; - font-size: 20px; - text-align: center; - line-height: 1; - padding: 0; } } - } -} - -@keyframes animatetop { - from { top: -300px; opacity: 0; } - to { top: 0; opacity: 1; } -} - -@media (max-width: 959px) { - .dev-modal .dev-modal-content { - .dev-modal-title-container h2 { font-size: 18px; } - .dev-modal-sub-content .form-section .form-element { width: 100%; } + // Stack Name + Email at the same breakpoint the modal does. At 50% width + // on a 375px viewport the email column collapses to ~150px, which both + // crams "john@example.com" placeholder and forces the "Email Address" + // floating label to wrap onto two lines and overlap the input. + .contact-us-form .form-section .form-element { + width: 100%; + } } - - // Stack Name + Email at the same breakpoint the modal does. At 50% width - // on a 375px viewport the email column collapses to ~150px, which both - // crams "john@example.com" placeholder and forces the "Email Address" - // floating label to wrap onto two lines and overlap the input. - .contact-us-form .form-section .form-element { width: 100%; } -} - diff --git a/src/styles/_trendz.scss b/src/styles/_trendz.scss new file mode 100644 index 000000000..5f5f6fba9 --- /dev/null +++ b/src/styles/_trendz.scss @@ -0,0 +1,200 @@ +// ============================================ +// TRENDZ LANDING — Design Tokens & Mixins +// ============================================ +// Imported once via global.scss — emits html#trendz CSS vars globally. +// Components @use this file for mixins only (the html#trendz block gets +// Astro-scoped in component output and is silently ignored there). +// ============================================ +@use 'variables' as *; + +// -------------------------------------------- +// CSS Custom Properties — scoped to Trendz page +// -------------------------------------------- + +html#trendz { + --color-trendz-accent: #{$color-primary}; + --color-trendz-accent-hover: #{$color-primary-hover}; + --color-trendz-text-primary: #212121; + --color-trendz-text-secondary: #3d3d3d; +} + +// -------------------------------------------- +// Breakpoints +// 0–599 xs mobile +// 600–959 sm large mobile / small tablet +// 960–1279 md tablet / small desktop +// 1280–1919 lg desktop +// 1920+ xl wide +// -------------------------------------------- + +$trendz-bp-sm: 600px; +$trendz-bp-md: 960px; +$trendz-bp-lg: 1280px; +$trendz-bp-xl: 1920px; + +@mixin trendz-up($bp) { + @if $bp == sm { + @media (min-width: #{$trendz-bp-sm}) { + @content; + } + } @else if $bp == md { + @media (min-width: #{$trendz-bp-md}) { + @content; + } + } @else if $bp == lg { + @media (min-width: #{$trendz-bp-lg}) { + @content; + } + } @else if $bp == xl { + @media (min-width: #{$trendz-bp-xl}) { + @content; + } + } +} + +@mixin trendz-down($bp) { + @if $bp == xs { + @media (max-width: #{$trendz-bp-sm - 1px}) { + @content; + } + } @else if $bp == sm { + @media (max-width: #{$trendz-bp-md - 1px}) { + @content; + } + } @else if $bp == md { + @media (max-width: #{$trendz-bp-lg - 1px}) { + @content; + } + } @else if $bp == lg { + @media (max-width: #{$trendz-bp-xl - 1px}) { + @content; + } + } +} + +// -------------------------------------------- +// Typography — base styles (no color, no font-family) +// -------------------------------------------- + +@mixin trendz-h1 { + font-size: 56px; + font-weight: 600; + line-height: 72px; + letter-spacing: 0.14px; +} + +@mixin trendz-h2 { + font-size: 36px; + font-weight: 500; + line-height: 48px; + letter-spacing: 0.09px; +} + +@mixin trendz-h3 { + font-size: 28px; + font-weight: 500; + line-height: 44px; + letter-spacing: 0.249px; +} + +@mixin trendz-h3-regular { + font-size: 28px; + font-weight: 400; + line-height: 44px; + letter-spacing: 0.249px; +} + +@mixin trendz-h4 { + font-size: 24px; + font-weight: 500; + line-height: 36px; + letter-spacing: 0.15px; +} + +@mixin trendz-h5 { + font-size: 20px; + font-weight: 400; + line-height: 32px; + letter-spacing: 0.15px; +} + +@mixin trendz-h5-medium { + font-size: 20px; + font-weight: 500; + line-height: 28px; + letter-spacing: 0.249px; +} + +@mixin trendz-h5-semibold { + font-size: 20px; + font-weight: 600; + line-height: 32px; + letter-spacing: 0.15px; +} + +@mixin trendz-body-m { + font-size: 18px; + font-weight: 400; + line-height: 30px; + letter-spacing: 0.15px; +} + +@mixin trendz-body-m-medium { + font-size: 18px; + font-weight: 500; + line-height: 30px; + letter-spacing: 0.15px; +} + +@mixin trendz-body-s { + font-size: 16px; + font-weight: 400; + line-height: 28px; + letter-spacing: 0.15px; +} + +@mixin trendz-body-xs { + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.15px; +} + +@mixin trendz-body-xs-medium { + font-size: 14px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.15px; +} + +// -------------------------------------------- +// Responsive typography — Figma breakpoint rules +// -------------------------------------------- + +@mixin trendz-h1-responsive { + @include trendz-h1; + @include trendz-down(xs) { + @include trendz-h4; + } +} + +@mixin trendz-h2-responsive { + @include trendz-h2; + @include trendz-down(xs) { + @include trendz-h4; + } +} + +@mixin trendz-h5-responsive { + @include trendz-h5; + @include trendz-down(xs) { + @include trendz-body-m; + } +} + +@mixin trendz-h5-semibold-responsive { + @include trendz-h5-semibold; + @include trendz-down(xs) { + @include trendz-body-m-medium; + } +} diff --git a/src/styles/global.scss b/src/styles/global.scss index 8e14d19b6..c68648b78 100644 --- a/src/styles/global.scss +++ b/src/styles/global.scss @@ -8,3 +8,4 @@ @use 'base'; @use 'utilities'; @use 'layout'; +@use 'trendz'; From 132b51e70ce861541cd4effbbd24da0f25a2aa40 Mon Sep 17 00:00:00 2001 From: Ruslan Vasylkiv <87172504+rusikv@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:04:19 +0000 Subject: [PATCH 03/11] Carousel unification: slot-only shared component, use-case dashboards, a11y fixes + site-wide astro:page-load cleanup (#484) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(use-cases): restore dashboard carousels lost in migration The old Jekyll site showed an image carousel on 13 use-case pages; only 8 were migrated. Restore the missing 5 — smart-metering, water-metering, smart-retail, air-quality-monitoring, and scada-energy-management — by copying the original webp screenshots and adding the overview carousel block to each data file. Alt/title texts, image order, and dimensions match the legacy carousel data verbatim, except scada-energy-management slide 3, whose declared 1286x660 box was 1.59% off the real asset's aspect ratio (2604x1358) and is corrected to the aspect-exact 1302x679. The smart-retail and air-quality screenshots were exported near-lossless on the legacy site; they are re-encoded at webp quality 80 (matching their siblings), cutting those 10 files from 2.4 MB to 1.0 MB. The remaining 13 were already optimally encoded. * feat(carousel): redesign nav chrome with brand indigo accents Replace the legacy owl-carousel-era chrome (thin hand-drawn SVG chevrons, 72x4 dash pagination) on the shared Landing carousel: - Arrows: 44px circular buttons with astro-icon tabler chevrons; lavender-tinted disc at rest, solid accent with contrast icon on hover, focus-visible ring. - Dots: 8px round dots; the active one morphs into a 24px pill. Uniform 28x24px touch targets replace the mobile-only override. - Colors ride on --carousel-accent: brand indigo in light theme, lavender in dark, via var(--color-brand-indigo, var(--color-product-cloud)) so it picks up the brand token once the brand unification lands while rendering identically today. - New .carousel-stage wrapper anchors the arrow overlay to the slide area (excluding dots, and the caption in the simple variant) so buttons center on the image instead of sitting low. - Home-page usecase variant: side padding 50px -> 64px to clear the round buttons. * fix(blog): replace raw YouTube iframes broken by referrer policy The site serves referrer-policy: same-origin (Cloudflare managed transform), so browsers send no Referer to YouTube's embed player, which now requires one — raw iframes fail with player error 153. Swap the two raw + ## High-performance entity data query service (EDQS) diff --git a/src/content/blog/thingsboard-calculated-fields-an-easy-way-to-handle-complex-iot-telemetry-calculations.mdx b/src/content/blog/thingsboard-calculated-fields-an-easy-way-to-handle-complex-iot-telemetry-calculations.mdx index af06fc10f..444f35293 100644 --- a/src/content/blog/thingsboard-calculated-fields-an-easy-way-to-handle-complex-iot-telemetry-calculations.mdx +++ b/src/content/blog/thingsboard-calculated-fields-an-easy-way-to-handle-complex-iot-telemetry-calculations.mdx @@ -10,6 +10,8 @@ featuredImageAlt: 'ThingsBoard Calculated Fields' draft: false --- +import YouTubeVideo from '@components/YouTubeVideo.astro'; + With the release of **[ThingsBoard 4.0](/blog/thingsboard-4-0-release/)**, we’re excited to introduce **[Calculated Fields](/docs/user-guide/calculated-fields/)**—a new feature that simplifies telemetry processing. Calculated Fields let you define calculations in a clean, user-friendly way — making your logic easier to manage, scale, and maintain. ![Calculated fields configuration interface in ThingsBoard](/images/blog/thingsboard-calculated-fields-an-easy-way-to-handle-complex-iot-telemetry-calculations/Calculated-fields-1-1.webp) @@ -106,4 +108,4 @@ Starting with version 4.1, Calculated Fields will gain the ability to **reproces Check out our [example video](https://www.youtube.com/watch?v=wBUcWMSH4QI) and [official documentation](/docs/user-guide/calculated-fields/) to learn more about how Calculated Fields work and how to start using them. - + diff --git a/src/data/homeCarousel.ts b/src/data/homeCarousel.ts index 8a2918cce..8c9c6df60 100644 --- a/src/data/homeCarousel.ts +++ b/src/data/homeCarousel.ts @@ -5,8 +5,8 @@ export interface CarouselItem { description: string; linkLabel: string; href: string; - width: number; - height: number; + width: string | number; + height: string | number; } export const homeCarouselItems: CarouselItem[] = [ diff --git a/src/data/use-cases/air-quality-monitoring.ts b/src/data/use-cases/air-quality-monitoring.ts index 4e7210db5..480b504c4 100644 --- a/src/data/use-cases/air-quality-monitoring.ts +++ b/src/data/use-cases/air-quality-monitoring.ts @@ -17,6 +17,39 @@ export const data: UseCaseData = { 'https://thingsboard.cloud/dashboard/ec564620-82b2-11ed-a624-8360a2a6cb0e?publicId=4978baf0-8a92-11ec-98f9-ff45c37940c6', demoButtonId: 'UseCases_AirQM_ViewLiveDemo', }, + overview: { + type: 'carousel', + carouselImages: [ + { + src: '/src/assets/images/usecases/air-quality/aiq-1.webp', + alt: 'Interactive AQI heatmap of Los Angeles on the ThingsBoard IoT Platform', + title: 'AQI map of Los Angeles monitored via ThingsBoard', + width: 1302, + height: 699, + }, + { + src: '/src/assets/images/usecases/air-quality/aiq-2.webp', + alt: 'Live PM10 air quality metrics for Beverly Hills on ThingsBoard dashboard', + title: 'PM10 air quality levels in Beverly Hills displayed in ThingsBoard', + width: 1302, + height: 699, + }, + { + src: '/src/assets/images/usecases/air-quality/aiq-4.webp', + alt: 'IoT air quality sensors and alerts visualized on ThingsBoard map dashboard', + title: 'Live air quality sensors and alerts across LA in ThingsBoard', + width: 1302, + height: 699, + }, + { + src: '/src/assets/images/usecases/air-quality/aiq-5.webp', + alt: 'Sensor metrics for Beverly Hills including AQI and battery on ThingsBoard', + title: 'Sensor data for Beverly Hills – AQI, battery and status', + width: 1302, + height: 699, + }, + ], + }, solutionStructure: { title: 'Solution structure of air quality monitoring', shortText: diff --git a/src/data/use-cases/scada-energy-management.ts b/src/data/use-cases/scada-energy-management.ts index e6156b27e..b2e9d5f76 100644 --- a/src/data/use-cases/scada-energy-management.ts +++ b/src/data/use-cases/scada-energy-management.ts @@ -18,6 +18,32 @@ export const data: UseCaseData = { 'https://thingsboard.cloud/dashboard/2430dc20-3172-11f0-858a-67efd1bc8a87?publicId=7aa99e80-8acd-11ef-a59e-a9c993dbec14', demoButtonId: 'UseCases_ScadaEnergy_ViewLiveDemo', }, + overview: { + type: 'carousel', + carouselImages: [ + { + src: '/src/assets/images/usecases/scada-energy-management/scada-energy-management-1.webp', + alt: 'Main state of SCADA energy management dashboard', + title: 'Main mimic diagram: generation, storage and consumption', + width: 1286, + height: 660, + }, + { + src: '/src/assets/images/usecases/scada-energy-management/scada-energy-management-2.webp', + alt: 'SCADA energy management dashboard consumption state', + title: 'Live power, voltage, current and frequency by phase', + width: 1286, + height: 660, + }, + { + src: '/src/assets/images/usecases/scada-energy-management/scada-energy-management-3.webp', + alt: 'SCADA energy management dashboard small screen responsiveness', + title: 'Responsive SCADA layout on tablet and phone', + width: 1302, + height: 679, + }, + ], + }, solutionStructure: { title: 'Solution structure', shortText: '', diff --git a/src/data/use-cases/scada-oil-and-gas-drilling-system.ts b/src/data/use-cases/scada-oil-and-gas-drilling-system.ts index f7fee3162..b3c429ad5 100644 --- a/src/data/use-cases/scada-oil-and-gas-drilling-system.ts +++ b/src/data/use-cases/scada-oil-and-gas-drilling-system.ts @@ -24,18 +24,21 @@ export const data: UseCaseData = { { src: '/src/assets/images/usecases/scada-drilling-system/scada-drilling-overview-1.webp', alt: 'Main state of SCADA drilling system dashboard', + title: 'Main mimic diagram: rig, pumps, mud tanks and flow', width: 1310, height: 679, }, { src: '/src/assets/images/usecases/scada-drilling-system/scada-drilling-overview-2.webp', alt: 'SCADA drilling system dashboard small screen responsiveness', + title: 'Responsive SCADA layout on tablet and phone', width: 1310, height: 679, }, { src: '/src/assets/images/usecases/scada-drilling-system/scada-drilling-overview-3.webp', alt: 'Data state of SCADA drilling system dashboard', + title: 'Live drill-bit, rotor, drawwork and mud readings', width: 1310, height: 679, }, diff --git a/src/data/use-cases/smart-metering.ts b/src/data/use-cases/smart-metering.ts index 7ff36edf8..c04cb8f28 100644 --- a/src/data/use-cases/smart-metering.ts +++ b/src/data/use-cases/smart-metering.ts @@ -17,6 +17,43 @@ export const data: UseCaseData = { 'https://demo.thingsboard.io/dashboard/3a1026e0-83f6-11e7-b56d-c7f326cba909?publicId=322a2330-7c36-11e7-835d-c7f326cba909', demoButtonId: 'UseCases_SmartMetering_ViewLiveDemo', }, + overview: { + type: 'carousel', + carouselImages: [ + { + src: '/src/assets/images/usecases/smart-metering/smart-metering-1.webp', + alt: 'ThingsBoard dashboard showing energy and water consumption, district map, and critical alarm for District B in San Francisco', + title: + 'ThingsBoard dashboard – energy and water monitoring, map and alarms for San Francisco districts', + width: 2048, + height: 1090, + }, + { + src: '/src/assets/images/usecases/smart-metering/smart-metering-2.webp', + alt: 'ThingsBoard dashboard displaying District A buildings on the map, energy and water consumption, and a critical high temperature alarm', + title: + 'ThingsBoard dashboard – monitoring buildings in District A with real-time energy, water usage, and critical alarms', + width: 2048, + height: 1090, + }, + { + src: '/src/assets/images/usecases/smart-metering/smart-metering-3.webp', + alt: 'ThingsBoard dashboard with apartment layout of Building A1, showing energy and water usage for Apartments A1-1 and A1-2, and a critical temperature alarm', + title: + 'ThingsBoard dashboard – apartment-level monitoring in Building A1 with real-time energy, water consumption, and alarms', + width: 2048, + height: 1090, + }, + { + src: '/src/assets/images/usecases/smart-metering/smart-metering-4.webp', + alt: 'ThingsBoard dashboard showing thermostat readings, real-time temperature control, a critical high temperature alarm, and historical temperature graph for Apartment A1-1', + title: + 'ThingsBoard dashboard – thermostat monitoring and control with temperature history and alarm for Apartment A1-1', + width: 2048, + height: 1090, + }, + ], + }, solutionStructure: { title: 'Solution structure of smart metering', shortText: diff --git a/src/data/use-cases/smart-retail.ts b/src/data/use-cases/smart-retail.ts index 8a4a7c8d4..df403680a 100644 --- a/src/data/use-cases/smart-retail.ts +++ b/src/data/use-cases/smart-retail.ts @@ -17,6 +17,65 @@ export const data: UseCaseData = { 'https://thingsboard.cloud/dashboard/551d4ca0-8b54-11ec-98f9-ff45c37940c6?publicId=4978baf0-8a92-11ec-98f9-ff45c37940c6', demoButtonId: 'UseCases_SmartRetail_ViewLiveDemo', }, + overview: { + type: 'carousel', + carouselImages: [ + { + src: '/src/assets/images/usecases/smart-retail/smart-retail-1.webp', + alt: + 'ThingsBoard dashboard displaying supermarket locations and active critical alarms on the map', + title: 'Overview of supermarket monitoring with critical and major alerts', + width: 1819, + height: 966, + }, + { + src: '/src/assets/images/usecases/smart-retail/smart-retail-2.webp', + alt: + 'Critical motion sensor and list of active alarms for Supermarket S1 in ThingsBoard interface', + title: 'Device and alarm status for Supermarket S1', + width: 1819, + height: 966, + }, + { + src: '/src/assets/images/usecases/smart-retail/smart-retail-3.webp', + alt: + 'ThingsBoard interface showing Supermarket S1 floor plan with critical motion sensor alerts and alarm chart', + title: 'Floor plan of Supermarket S1 with device states and motion sensor data', + width: 1819, + height: 966, + }, + { + src: '/src/assets/images/usecases/smart-retail/smart-retail-4.webp', + alt: 'Dashboard view of Supermarket S2 with critical door sensor and major chiller alarm', + title: 'Device overview and alarms in Supermarket S2', + width: 1819, + height: 966, + }, + { + src: '/src/assets/images/usecases/smart-retail/smart-retail-5.webp', + alt: 'Supermarket S2 layout with freezer temperature monitoring and no active alarms', + title: 'Temperature graph for freezer in Supermarket S2', + width: 1819, + height: 966, + }, + { + src: '/src/assets/images/usecases/smart-retail/smart-retail-6.webp', + alt: + 'Critical door sensor and multiple major temperature alarms in Supermarket S3 on ThingsBoard', + title: 'Supermarket S3 device list and alarm summary', + width: 1819, + height: 966, + }, + { + src: '/src/assets/images/usecases/smart-retail/smart-retail-7.webp', + alt: + 'Dashboard showing temperature fluctuations of chiller in Supermarket S3 on ThingsBoard', + title: 'Supermarket S3 floor plan and temperature trend for chiller', + width: 1819, + height: 966, + }, + ], + }, solutionStructure: { title: 'Solution structure of smart retail', shortText: diff --git a/src/data/use-cases/water-metering.ts b/src/data/use-cases/water-metering.ts index 03e650d7e..e4f35e310 100644 --- a/src/data/use-cases/water-metering.ts +++ b/src/data/use-cases/water-metering.ts @@ -17,6 +17,46 @@ export const data: UseCaseData = { 'https://thingsboard.cloud/dashboard/aff5f200-8b48-11ec-a344-c767c1ab1bb8?publicId=4978baf0-8a92-11ec-98f9-ff45c37940c6', demoButtonId: 'UseCases_WaterMeter_ViewLiveDemo', }, + overview: { + type: 'carousel', + carouselImages: [ + { + src: '/src/assets/images/usecases/water-metering/water-metering-1.webp', + alt: 'ThingsBoard water-metering dashboard: weekly consumption, active-device counts, a meter map of Santa Monica, the meter table and active alarms', + title: 'Fleet overview: consumption, meter map and active alarms', + width: 1819, + height: 967, + }, + { + src: '/src/assets/images/usecases/water-metering/water-metering-2.webp', + alt: 'ThingsBoard dashboard charting current-week water consumption against the previous week alongside the water-meter list', + title: 'Weekly consumption vs the previous week', + width: 1819, + height: 967, + }, + { + src: '/src/assets/images/usecases/water-metering/water-metering-3.webp', + alt: 'ThingsBoard single water-meter view: weekly and all-time consumption, temperature, battery, consumption history, location map, meter details and a device photo', + title: 'Single meter: usage, status, location and details', + width: 1819, + height: 967, + }, + { + src: '/src/assets/images/usecases/water-metering/water-metering-4.webp', + alt: 'ThingsBoard alarms table listing critical daily and weekly consumption-threshold alarms across the water meters', + title: 'Consumption-threshold alarms across the fleet', + width: 1819, + height: 967, + }, + { + src: '/src/assets/images/usecases/water-metering/water-metering-5.webp', + alt: 'ThingsBoard settings tab configuring system alarm thresholds and SMS and email notifications', + title: 'Alarm thresholds and notification settings', + width: 1819, + height: 967, + }, + ], + }, solutionStructure: { title: 'Solution structure of water metering use case', shortText: diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index f6da02bdd..e68957a08 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -1,5 +1,7 @@ --- import BlogLayout from '../../layouts/BlogLayout.astro'; +import Carousel from '@components/Carousel/Carousel.astro'; +import CarouselSlide from '@components/Carousel/CarouselSlide.astro'; import { getCollection } from 'astro:content'; import { getAuthor } from '~/data/blog/authors'; import { Icon } from 'astro-icon/components'; @@ -67,53 +69,48 @@ const blogUrl = new URL('/blog/', Astro.site).href; {/* ── Featured Carousel ── */} {featuredPosts.length > 0 && (