yanghao 1 сар өмнө
parent
commit
4343bb3e72

BIN
src/assets/images/l.png


BIN
src/assets/images/ll.png


BIN
src/assets/images/mk.png


BIN
src/assets/images/n.png


BIN
src/assets/images/o.png


BIN
src/assets/images/ok.png


BIN
src/assets/images/p.png


BIN
src/assets/images/pp.png


BIN
src/assets/images/s.png


BIN
src/assets/images/v.png


BIN
src/assets/images/w.png


BIN
src/assets/images/z.png


+ 1 - 0
src/views/HomeView.vue

@@ -556,6 +556,7 @@ const partners = Array.from({ length: 10 }).map((_, idx) => ({
             class="capPlatformCard card hover-lift"
             :data-variant="p.variant"
             :delay="80 + idx * 80"
+            style="border: none"
           >
             <div class="capPlatformHead">
               <div class="capPlatformCopy">

+ 670 - 44
src/views/SolutionsView.vue

@@ -1,12 +1,11 @@
 <script setup>
 import PageHero from "../components/PageHero.vue";
-import solutionsBgUrl from "../assets/images/bg.jpg?url";
-import Reveal from "../components/motion/Reveal.vue";
 import { Icon } from "@iconify/vue";
 import { onBeforeUnmount, onMounted, ref } from "vue";
-import platformCover from "../assets/images/p1.png?url";
-import equipmentCover from "../assets/images/sence3.png?url";
+import platformCover from "../assets/images/pbg.png?url";
+import equipmentCover from "../assets/images/case2.png?url";
 import productionCover from "../assets/images/sence2.jpg?url";
+import qhseCover from "../assets/images/sence3.png?url";
 
 const activeTab = ref("platform");
 const tabBarRef = ref(null);
@@ -19,86 +18,91 @@ const pillars = [
   {
     key: "platform",
     title: "设备升级改造能力",
-    lead: "油气专属底座,打通“数采—数据—系统—AI”,为全场景应用落地提供稳定支撑",
+    lead: "实现设备升级改造与生产管理全生命周期的闭环管理",
     icon: "lucide:layers-3",
     cover: platformCover,
     items: [
       {
         title: "全景设备升级 适配平台接入",
-        desc: "依托工业互联网平台底座,提供油气领域全类型设备升级改造服务,针对老旧设备、传统设备,完成仪器仪表升级、PLC 控制系统改造或加装,确保改造后设备可无缝接入平台,打通设备与平台的数据联通通道,为后续智能管控奠定基础",
+        desc: "依托工业互联网平台底座,提供油气领域全类型设备升级改造服务,针对老旧设备、传统设备,完成仪器仪表升级、PLC控制系统改造或加装,确保改造后设备可无缝接入平台,打通设备与平台的数据联通通道,为后续智能管控奠定基础。",
+        image: new URL("../assets/images/l.png", import.meta.url).href,
       },
       {
         title: "实时数采远程管控 提升作业便捷度",
         desc: "通过设备升级改造,结合平台数采能力,实现现场设备运行数据实时采集、同步上传,打破现场操作局限,支持远程对设备进行控制、参数调试,无需现场值守,降低人工成本,提升设备运维与操作的便捷性、高效性。",
+        image: new URL("../assets/images/n.png", import.meta.url).href,
       },
       {
-        title: "AI 大模型赋能  智能动态调参",
-        desc: "升级后的设备联动工业互联网平台 AI 大模型算法,基于实时采集的设备运行数据,进行智能分析、精准研判,自动输出动态调参建议或完成自动调参,优化设备运行状态,确保设备始终处于最佳运行工况,提升运行效率。",
+        title: "AI大模型赋能  智能动态调参",
+        desc: "升级后的设备联动工业互联网平台AI大模型算法,基于实时采集的设备运行数据,进行智能分析、精准研判,自动输出动态调参建议或完成自动调参,优化设备运行状态,确保设备始终处于最佳运行工况,提升运行效率。",
+        image: new URL("../assets/images/p.png", import.meta.url).href,
       },
       {
         title: "设备专项赋能 预测性维护",
         desc: "针对油气领域部分核心设备,在升级改造基础上,结合平台数据处理与大模型能力,实时监测运行参数,精准预判设备潜在故障、损耗情况,提前触发维护提醒,实现预测性维护,减少停机损失,延长设备使用寿命。",
+        image: new URL("../assets/images/w.png", import.meta.url).href,
       },
     ],
   },
   {
     key: "equipment",
     title: "智慧注气",
-    lead: "围绕设备全生命周期,实现台账、巡检维保、预测维护与实时监控预警的闭环管理",
+    lead: "实现智能注气、调度、管理,提升生产效率与安全",
     icon: "lucide:cpu",
     cover: equipmentCover,
     items: [
       {
         title: "老旧设备升级 筑牢无人值守基础",
         desc: "依托工业互联网平台底座,针对油气注气领域老旧设备,开展专项升级改造,加装远程控制器、智能阀门等核心组件,完成设备智能化升级,打破传统人工操作局限,为注气现场无人值守搭建硬件支撑,确保设备可无缝接入平台实现协同管控。",
+        image: new URL("../assets/images/o.png", import.meta.url).href,
       },
       {
         title: "实时数据采集 精准把控运行状态",
         desc: "升级后的注气设备联动平台数采能力,实时采集现场压力、温度、流量等核心运行参数,同步上传至工业互联网平台,实现参数实时可视化监控,全面掌握注气全流程运行状态,为无人值守下的智能调控提供精准数据支撑。",
+        image: new URL("../assets/images/v.png", import.meta.url).href,
       },
       {
         title: "智能动态调参 实现无人管控",
         desc: "依托工业互联网平台算法能力,基于实时采集的运行数据,自动分析注气工况,动态调整注入参数,无需人工现场操作,真正实现注气现场无人少人值守,大幅减少人工干预,确保注气过程稳定、高效、精准。",
+        image: new URL("../assets/images/z.png", import.meta.url).href,
       },
       {
         title: "降本增效保安全 赋能场景升级",
-        desc: "通过无人值守模式,大幅减少现场值守人员,降低人力成本;智能动态调参优化注气效率,提升作业产能;减少人员现场作业频次,规避现场安全风险,实现降本、增效、保安全三重价值,推动注气场景数字化、智能化转型。",
+        desc: "通过无人值守模式,大幅减少现场值守人员,降低人力成本;智能动态调参优化注气效率,提升作业产能;减少人员现场作业频次,规避现场安全风险,实现“降本、增效、保安全”三重价值,推动注气场景数字化、智能化转型。",
+        image: new URL("../assets/images/s.png", import.meta.url).href,
       },
     ],
   },
   {
     key: "production",
     title: "智慧钻井",
-    lead: "面向油气生产项目,贯通任务、计划、数据与报表,提升协同效率与过程可控性",
+    lead: "提升生产效率与安全",
     icon: "lucide:clipboard-check",
     cover: productionCover,
     items: [
       {
         title: "数据精准采集  筑牢钻井分析基础",
-        desc: "依托工业互联网平台数采能力,深度联动录井仪设备,实时采集钻井全流程工况数据,全面记录钻井过程中的各项核心参数,实现数据精准捕捉、实时上传、规范存储,为后续 AI 分析、钻井优化及完井报告生成,提供完整、可靠的数据支撑。",
+        desc: "依托工业互联网平台数采能力,深度联动录井仪设备,实时采集钻井全流程工况数据,全面记录钻井过程中的各项核心参数,实现数据精准捕捉、实时上传、规范存储,为后续AI分析、钻井优化及完井报告生成,提供完整、可靠的数据支撑。",
+        image: new URL("../assets/images/ok.png", import.meta.url).href,
       },
       {
-        title: "AI 大模型深度赋能 精准分析钻井工况",
-        desc: "基于工业互联网平台 AI 大模型能力,对采集的录井数据进行深度挖掘、智能分析,精准识别钻井过程中的工况异常、参数偏差等问题,快速研判钻井态势,为钻井作业优化提供科学、精准的数据分析支撑,规避盲目操作风险。",
+        title: "AI大模型深度赋能 精准分析钻井工况",
+        desc: "基于工业互联网平台AI大模型能力,对采集的录井数据进行深度挖掘、智能分析,精准识别钻井过程中的工况异常、参数偏差等问题,快速研判钻井态势,为钻井作业优化提供科学、精准的数据分析支撑,规避盲目操作风险。",
+        image: new URL("../assets/images/ll.png", import.meta.url).href,
       },
       {
         title: "钻井参数智能优化 提升钻井作业交通",
-        desc: "结合 AI 大模型的工况分析结果,联动工业互联网平台管控能力,为钻井现场提供精准的参数优化建议,指导现场调整钻井参数,优化钻井工艺,有效提升钻速、降低钻井损耗,助力钻井作业提质增效,契合油气勘探开发高效化需求。",
+        desc: "结合AI大模型的工况分析结果,联动工业互联网平台管控能力,为钻井现场提供精准的参数优化建议,指导现场调整钻井参数,优化钻井工艺,有效提升钻速、降低钻井损耗,助力钻井作业提质增效,契合油气勘探开发高效化需求。",
+        image: new URL("../assets/images/mk.png", import.meta.url).href,
       },
       {
         title: "智能生成完井报告 提升报告编制效率",
-        desc: "依托平台数据沉淀与 AI 处理能力,自动汇总钻井全流程录井数据、工况分析结果及优化记录,一键生成标准化完井报告,无需人工繁琐录入,大幅缩短报告编制周期,确保报告数据精准、内容规范,为钻井成果复盘、后续作业提供有力支撑。",
+        desc: "依托平台数据沉淀与AI处理能力,自动汇总钻井全流程录井数据、工况分析结果及优化记录,一键生成标准化完井报告,无需人工繁琐录入,大幅缩短报告编制周期,确保报告数据精准、内容规范,为钻井成果复盘、后续作业提供有力支撑。",
+        image: new URL("../assets/images/pp.png", import.meta.url).href,
       },
     ],
   },
 ];
-
-const deliver = [
-  { title: "SaaS", desc: "开箱即用,按需订阅,快速试点与复制。" },
-  { title: "私有化", desc: "数据本地化部署,适配企业安全与合规要求。" },
-  { title: "混合云", desc: "核心数据本地,弹性算力上云,兼顾成本与性能。" },
-];
-
 const approach = [
   { step: "01", title: "数据采集", desc: "实时采集设备、生产等现场数据" },
   { step: "02", title: "数据传输", desc: "通过边缘网关传输至平台" },
@@ -128,6 +132,83 @@ function scrollToTab(key) {
 }
 
 let observer = null;
+
+const currentImageIndex = ref({
+  platform: 0,
+  equipment: 0,
+  production: 0,
+});
+
+const imageTimers = ref({});
+
+const getActiveIndex = (key, totalItems) => {
+  const rawIndex = currentImageIndex.value[key];
+  const index = Number.isFinite(rawIndex) ? rawIndex : 0;
+  if (!totalItems || totalItems <= 0) return 0;
+  return ((index % totalItems) + totalItems) % totalItems;
+};
+
+const getActiveItem = (pillar) => {
+  const totalItems = pillar?.items?.length || 0;
+  const index = getActiveIndex(pillar?.key, totalItems);
+  return pillar?.items?.[index] || null;
+};
+
+const getActiveImageSrc = (pillar) =>
+  getActiveItem(pillar)?.image || pillar.cover;
+const getActiveImageAlt = (pillar) =>
+  getActiveItem(pillar)?.title || pillar.title;
+
+const startImageCarousel = (key, totalItems) => {
+  if (prefersReducedMotion()) return;
+  if (!totalItems || totalItems < 2) return;
+
+  stopImageCarousel(key);
+
+  imageTimers.value[key] = setInterval(() => {
+    currentImageIndex.value[key] =
+      (currentImageIndex.value[key] + 1) % totalItems;
+  }, 4000);
+};
+
+const stopImageCarousel = (key) => {
+  if (imageTimers.value[key]) {
+    clearInterval(imageTimers.value[key]);
+    imageTimers.value[key] = null;
+  }
+};
+
+const goToImageSlide = (key, index, totalItems) => {
+  currentImageIndex.value[key] = index;
+  startImageCarousel(key, totalItems);
+};
+
+function updateActiveTab() {
+  const sections = pillars
+    .map((p) => document.getElementById(`product-${p.key}`))
+    .filter(Boolean);
+  const offset = headerOffsetPx();
+
+  const scrollPos = window.scrollY + offset;
+
+  let currentSection = null;
+  for (const section of sections) {
+    const rect = section.getBoundingClientRect();
+    if (rect.top <= 100) {
+      currentSection = section;
+    } else {
+      break;
+    }
+  }
+
+  if (currentSection) {
+    const key = currentSection.id.replace("product-", "");
+    if (activeTab.value !== key) {
+      activeTab.value = key;
+    }
+  }
+}
+
 onMounted(() => {
   const offset = headerOffsetPx();
   observer = new IntersectionObserver(
@@ -142,8 +223,8 @@ onMounted(() => {
     },
     {
       root: null,
-      threshold: [0.25, 0.45, 0.6],
-      rootMargin: `-${offset}px 0px -55% 0px`,
+      threshold: [0.3, 0.5, 0.7],
+      rootMargin: `-${offset}px 0px -40% 0px`,
     },
   );
 
@@ -151,11 +232,26 @@ onMounted(() => {
     const el = document.getElementById(`product-${p.key}`);
     if (el) observer.observe(el);
   }
+
+  for (const p of pillars) {
+    if (currentImageIndex.value[p.key] === undefined)
+      currentImageIndex.value[p.key] = 0;
+    startImageCarousel(p.key, p.items?.length || 0);
+  }
+
+  window.addEventListener("scroll", updateActiveTab, { passive: true });
+  updateActiveTab();
 });
 
 onBeforeUnmount(() => {
   observer?.disconnect?.();
   observer = null;
+
+  for (const key of Object.keys(imageTimers.value || {})) {
+    stopImageCarousel(key);
+  }
+
+  window.removeEventListener("scroll", updateActiveTab);
 });
 </script>
 
@@ -203,16 +299,12 @@ onBeforeUnmount(() => {
           </button>
         </div>
 
-        <div class="productStac">
+        <div class="productStac container">
           <section
             v-for="p in pillars"
             :id="`product-${p.key}`"
             :key="p.key"
-            :class="{
-              'section--soft': p.title === '智慧注气',
-              productSection: true,
-            }"
-            style="padding: 0 100px"
+            class="productSection"
           >
             <header class="productHead">
               <div class="productHeadTop">
@@ -221,18 +313,59 @@ onBeforeUnmount(() => {
               <p class="productLead">{{ p.lead }}</p>
             </header>
 
-            <div v-if="p.key === 'platform'" class="platformLayout">
-              <div class="platformImage">
-                <img :src="p.cover" :alt="p.title" />
+            <div class="tabContentLayout">
+              <div class="tabContentImage">
+                <div class="imageCarouselWrapper">
+                  <div class="imageCarouselViewport">
+                    <Transition name="image-carousel-slide" mode="out-in">
+                      <div
+                        v-if="p.items?.length"
+                        :key="`${p.key}-${getActiveIndex(p.key, p.items.length)}`"
+                        class="imageCarouselSlide"
+                      >
+                        <img
+                          :src="getActiveImageSrc(p)"
+                          :alt="getActiveImageAlt(p)"
+                          loading="lazy"
+                          decoding="async"
+                        />
+                      </div>
+                    </Transition>
+                  </div>
+                </div>
+
+                <div class="carouselIndicators">
+                  <button
+                    v-for="(item, idx) in p.items"
+                    :key="idx"
+                    :class="[
+                      'indicator',
+                      { 'is-active': idx === currentImageIndex[p.key] },
+                    ]"
+                    @click="goToImageSlide(p.key, idx, p.items.length)"
+                    @mouseenter="stopImageCarousel(p.key)"
+                    @mouseleave="startImageCarousel(p.key, p.items.length)"
+                    :aria-label="`第${idx + 1}张图片`"
+                  ></button>
+                </div>
               </div>
-              <div class="platformFeatures">
+              <div class="tabContentFeatures">
                 <div
-                  v-for="it in p.items"
+                  v-for="(it, idx) in p.items"
                   :key="it.title"
-                  class="platformFeature"
+                  class="tabFeatureRow"
+                  :class="{
+                    'is-highlighted': idx === currentImageIndex[p.key],
+                  }"
+                  @mouseenter="
+                    () => {
+                      stopImageCarousel(p.key);
+                      currentImageIndex[p.key] = idx;
+                    }
+                  "
+                  @mouseleave="() => startImageCarousel(p.key, p.items.length)"
                 >
-                  <div class="featureDot" aria-hidden="true"></div>
-                  <div class="featureMain">
+                  <div class="tabFeatureMain">
                     <div class="featureTitle">{{ it.title }}</div>
                     <div class="muted featureDesc">{{ it.desc }}</div>
                   </div>
@@ -240,15 +373,22 @@ onBeforeUnmount(() => {
               </div>
             </div>
 
-            <div v-else class="tabContentLayout" style="padding-bottom: 20px">
-              <div class="tabContentImage">
-                <img :src="p.cover" :alt="p.title" />
-              </div>
+            <!-- <div class="tabContentLayout" v-else>
               <div class="tabContentFeatures">
                 <div
                   v-for="(it, idx) in p.items"
                   :key="it.title"
                   class="tabFeatureRow"
+                  :class="{
+                    'is-highlighted': idx === currentImageIndex[p.key],
+                  }"
+                  @mouseenter="
+                    () => {
+                      stopImageCarousel(p.key);
+                      currentImageIndex[p.key] = idx;
+                    }
+                  "
+                  @mouseleave="() => startImageCarousel(p.key, p.items.length)"
                 >
                   <div class="tabFeatureMain">
                     <div class="featureTitle">{{ it.title }}</div>
@@ -256,7 +396,42 @@ onBeforeUnmount(() => {
                   </div>
                 </div>
               </div>
-            </div>
+              <div class="tabContentImage">
+                <div class="imageCarouselWrapper">
+                  <div class="imageCarouselViewport">
+                    <Transition name="image-carousel-slide" mode="out-in">
+                      <div
+                        v-if="p.items?.length"
+                        :key="`${p.key}-${getActiveIndex(p.key, p.items.length)}`"
+                        class="imageCarouselSlide"
+                      >
+                        <img
+                          :src="getActiveImageSrc(p)"
+                          :alt="getActiveImageAlt(p)"
+                          loading="lazy"
+                          decoding="async"
+                        />
+                      </div>
+                    </Transition>
+                  </div>
+                </div>
+
+                <div class="carouselIndicators">
+                  <button
+                    v-for="(item, idx) in p.items"
+                    :key="idx"
+                    :class="[
+                      'indicator',
+                      { 'is-active': idx === currentImageIndex[p.key] },
+                    ]"
+                    @click="goToImageSlide(p.key, idx, p.items.length)"
+                    @mouseenter="stopImageCarousel(p.key)"
+                    @mouseleave="startImageCarousel(p.key, p.items.length)"
+                    :aria-label="`第${idx + 1}张图片`"
+                  ></button>
+                </div>
+              </div>
+            </div> -->
           </section>
         </div>
       </div>
@@ -731,4 +906,455 @@ onBeforeUnmount(() => {
 :deep(.pageHero__subtitle) {
   color: #4f5055;
 }
+
+.productSection {
+  scroll-margin-top: calc(var(--header-h) + 84px);
+  border: 0;
+  border-radius: 0;
+  background: transparent;
+  box-shadow: none;
+  margin-top: 50px;
+}
+
+.productHead {
+  padding: 18px 18px 14px;
+  text-align: center;
+}
+
+.productHeadTop {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 12px;
+}
+
+.productTitle {
+  letter-spacing: -0.02em;
+  color: var(--ink);
+  font-size: 30px;
+  line-height: 1.25;
+  text-align: center;
+}
+
+.productLead {
+  margin-top: 10px;
+  max-width: 92ch;
+  text-align: center;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.platformLayout {
+  margin-top: 40px;
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 50px;
+  align-items: start;
+}
+
+.platformImage {
+  /* border-radius: 16px; */
+  overflow: hidden;
+  box-shadow: 0 12px 40px rgba(2, 6, 23, 0.12);
+}
+
+.platformImage img {
+  width: 100%;
+  height: auto;
+  object-fit: contain;
+  display: block;
+}
+
+.platformFeatures {
+  display: grid;
+  gap: 24px;
+}
+
+.platformFeature {
+  display: grid;
+  grid-template-columns: 22px 1fr;
+  align-items: start;
+  gap: 10px;
+  padding: 22px;
+  padding-bottom: 0;
+  background: #fff;
+  /* border-radius: 16px; */
+  box-shadow: 0 8px 24px rgba(2, 6, 23, 0.08);
+  min-height: 160px;
+  transition:
+    transform 180ms ease,
+    box-shadow 180ms ease;
+}
+
+.platformFeature:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 12px 32px rgba(2, 6, 23, 0.12);
+}
+
+.tabContentLayout {
+  margin-top: 40px;
+  display: grid;
+  grid-template-columns: 1fr 1.2fr;
+  gap: 50px;
+  align-items: start;
+}
+
+.tabContentImage {
+  /* border-radius: 16px; */
+  --carousel-h: 500px;
+  overflow: hidden;
+  box-shadow: 0 12px 40px rgba(2, 6, 23, 0.12);
+  position: sticky;
+  top: calc(var(--header-h) + 100px);
+}
+
+.tabContentImage img {
+  width: 100%;
+  height: var(--carousel-h);
+  object-fit: cover;
+  display: block;
+}
+
+.tabContentFeatures {
+  display: grid;
+  gap: 20px;
+}
+
+.tabFeatureRow {
+  padding: 28px;
+  background: #fff;
+  /* border-radius: 16px; */
+  box-shadow: 0 8px 24px rgba(2, 6, 23, 0.08);
+  min-height: 140px;
+  transition:
+    transform 180ms ease,
+    box-shadow 180ms ease;
+}
+
+.tabFeatureRow:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 12px 32px rgba(2, 6, 23, 0.12);
+}
+
+.featureDot {
+  width: 18px;
+  height: 18px;
+  border-radius: 999px;
+  background: linear-gradient(180deg, #0766cd, #0d4a9e);
+  box-shadow:
+    0 10px 22px rgba(10, 71, 156, 0.25),
+    inset 0 0 0 2px rgba(255, 255, 255, 0.85);
+  margin-top: 4px;
+}
+
+.featureMain,
+.tabFeatureMain {
+  min-width: 0;
+}
+
+.featureTitle {
+  letter-spacing: -0.01em;
+  color: rgba(2, 6, 23, 0.9);
+  font-size: 22px;
+  font-weight: 700;
+  line-height: 1.35;
+}
+
+.featureDesc {
+  margin-top: 10px;
+  line-height: 1.75;
+  color: #666666;
+  text-align: left;
+}
+
+.deliverTitle {
+  /* font-weight: 900; */
+  margin-bottom: 6px;
+}
+
+@media (max-width: 960px) {
+  .sectionHead {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 12px;
+  }
+
+  .tabBar {
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+  }
+
+  .platformLayout,
+  .tabContentLayout {
+    grid-template-columns: 1fr;
+    gap: 30px;
+  }
+
+  .tabContentImage {
+    position: static;
+    --carousel-h: 300px;
+  }
+}
+
+@media (max-width: 560px) {
+  .platformFeature,
+  .tabFeatureRow {
+    padding: 20px;
+    min-height: auto;
+  }
+
+  .featureTitle {
+    font-size: 18px;
+  }
+
+  .featureDesc {
+    font-size: 14px;
+  }
+}
+
+@media (prefers-reduced-motion: reduce) {
+  .tabBtn {
+    transition: none !important;
+    transform: none !important;
+  }
+
+  .tabText {
+    transition: none !important;
+  }
+
+  .platformFeature,
+  .tabFeatureRow {
+    transition: none !important;
+    transform: none !important;
+  }
+}
+
+.imageCarouselWrapper {
+  position: relative;
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.imageCarouselViewport {
+  flex: 1;
+  overflow: hidden;
+  position: relative;
+  height: var(--carousel-h);
+}
+
+.imageCarouselSlide {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+}
+
+.imageCarouselSlide img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+  display: block;
+}
+
+.imageOverlay {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  padding: 20px;
+  background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
+  color: #fff;
+}
+
+.overlayText {
+  font-size: 16px;
+  font-weight: 600;
+  line-height: 1.4;
+  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
+}
+
+.image-carousel-slide-enter-active,
+.image-carousel-slide-leave-active {
+  transition: all 0.6s ease;
+}
+
+.image-carousel-slide-enter-from {
+  opacity: 0;
+  transform: translateY(50px);
+}
+
+.image-carousel-slide-leave-to {
+  opacity: 0;
+  transform: translateY(-50px);
+}
+
+.carouselBtn {
+  width: 44px;
+  height: 44px;
+  border-radius: 50%;
+  border: 2px solid rgba(7, 102, 205, 0.3);
+  background: rgba(255, 255, 255, 0.95);
+  color: #0766cd;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  transition: all 0.2s ease;
+  flex-shrink: 0;
+  z-index: 2;
+}
+
+.carouselBtn:hover {
+  background: #0766cd;
+  color: #fff;
+  border-color: #0766cd;
+  transform: scale(1.08);
+}
+
+.carouselBtn:focus-visible {
+  outline: none;
+  box-shadow: 0 0 0 3px rgba(7, 102, 205, 0.24);
+}
+
+.carouselIndicators {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: end;
+  gap: 10px;
+  /* margin-top: 16px; */
+  padding-right: 10px;
+  position: relative;
+
+  top: -300px;
+}
+
+.indicator {
+  width: 8px;
+  height: 8px;
+  /* border-radius: 50%; */
+  border: none;
+  background: rgba(7, 102, 205, 0.25);
+  cursor: pointer;
+  padding: 0;
+  transition: all 0.3s ease;
+}
+
+.indicator:hover {
+  background: rgba(7, 102, 205, 0.6);
+  transform: scale(1.3);
+}
+
+.indicator.is-active {
+  background: #0766cd;
+}
+
+.indicator:focus-visible {
+  outline: none;
+  box-shadow: 0 0 0 3px rgba(7, 102, 205, 0.24);
+}
+
+.tabFeatureRow {
+  padding: 28px;
+  background: #fff;
+  /* border-radius: 16px; */
+  box-shadow: 0 8px 24px rgba(2, 6, 23, 0.08);
+  min-height: 140px;
+  transition:
+    transform 180ms ease,
+    box-shadow 180ms ease,
+    border-left 0.3s ease;
+  border-left: 3px solid transparent;
+}
+
+.tabFeatureRow:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 12px 32px rgba(2, 6, 23, 0.12);
+}
+
+.tabFeatureRow.is-highlighted {
+  border-left: 3px solid #0766cd;
+  box-shadow: 0 8px 24px rgba(7, 102, 205, 0.15);
+}
+
+/* ... existing code ... */
+
+.tabContentImage {
+  /* border-radius: 16px; */
+  --carousel-h: 500px;
+  overflow: hidden;
+  box-shadow: 0 12px 40px rgba(2, 6, 23, 0.12);
+  position: sticky;
+  top: calc(var(--header-h) + 100px);
+}
+
+.imageCarouselWrapper {
+  position: relative;
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.imageCarouselViewport {
+  flex: 1;
+  overflow: hidden;
+  position: relative;
+}
+
+.imageCarouselSlide {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+}
+
+.imageCarouselSlide img {
+  width: 100%;
+  height: 500px;
+  object-fit: cover;
+  display: block;
+}
+
+.carouselIndicators {
+  position: absolute;
+  right: 20px;
+  top: 50%;
+  transform: translateY(-50%);
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  gap: 10px;
+  z-index: 10;
+}
+
+.indicator {
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  border: none;
+  background: rgba(255, 255, 255, 0.5);
+  cursor: pointer;
+  padding: 0;
+  transition: all 0.3s ease;
+}
+
+.indicator:hover {
+  background: rgba(255, 255, 255, 0.9);
+  transform: scale(1.3);
+}
+
+.indicator.is-active {
+  background: #014198;
+  width: 6px;
+  height: 20px;
+  border-radius: 3px;
+}
+
+.indicator:focus-visible {
+  outline: none;
+  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.5);
+}
 </style>