-
+ {/* Desktop / Tablet View */}
+
+
+
+ {/* The base faint line */}
+
+ {/* The animated data pulse line */}
+
+
+
+
+ {steps.map((s, i) => (
+
{s.label}
{s.desc}
- {i < steps.length - 1 &&
}
+ ))}
+
+
+
+ {/* Mobile Fallback View */}
+
+
+
+ {steps.map((s, i) => (
+
+ {s.label}
+ {s.desc}
))}
-
-
-
-
- feedback loop — model improves with every fix
-
-
-
);
}
diff --git a/web/src/components/PipelineDiagram.module.css b/web/src/components/PipelineDiagram.module.css
index 38685aa..b2865bc 100644
--- a/web/src/components/PipelineDiagram.module.css
+++ b/web/src/components/PipelineDiagram.module.css
@@ -1,99 +1,157 @@
.wrapper {
- padding: 48px 0 8px;
+ padding: 48px 0;
+ width: 100%;
+ max-width: 1000px;
+ margin: 0 auto;
}
-.pipeline {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 0;
- flex-wrap: wrap;
+.diagramDesktop {
+ position: relative;
+ width: 100%;
+ aspect-ratio: 10 / 6; /* 1000x600 */
}
-.step {
- display: flex;
- align-items: center;
+/* ── SVG Lines ── */
+.svgContainer {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ z-index: 1;
+}
+
+.linesSvg {
+ width: 100%;
+ height: 100%;
+ overflow: visible;
+}
+
+.basePath {
+ stroke: var(--border-color);
+ stroke-width: 2;
+ fill: none;
+}
+
+.animatedPath {
+ stroke: var(--text-primary);
+ stroke-width: 3;
+ fill: none;
+ stroke-linecap: round;
+ stroke-dasharray: 20 60;
+ animation: flowAnimation 3s linear infinite;
+}
+
+@keyframes flowAnimation {
+ 0% {
+ stroke-dashoffset: 80;
+ }
+ 100% {
+ stroke-dashoffset: 0;
+ }
}
-.box {
+/* ── Nodes ── */
+.nodesContainer {
+ position: absolute;
+ inset: 0;
+ z-index: 2;
+ pointer-events: none;
+}
+
+.node {
+ position: absolute;
+ transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
- background: var(--surface);
+ justify-content: center;
+ background: var(--bg-primary);
border: 1px solid var(--border-color);
- border-radius: 12px;
- padding: 20px 24px;
- min-width: 130px;
- transition: border-color 0.3s, box-shadow 0.3s, background 0.35s;
+ border-radius: 50%;
+ padding: 16px;
+ width: 160px;
+ height: 160px;
+ box-shadow: var(--shadow-sm);
+ pointer-events: auto;
+ transition: transform 0.3s, box-shadow 0.3s, border-color 0.35s;
+ text-align: center;
}
-.box:hover {
- border-color: var(--text-primary);
+.node:hover {
+ transform: translate(-50%, -54%);
box-shadow: var(--shadow-md);
+ border-color: var(--text-primary);
}
.label {
font-family: "ALTGumbo", system-ui, sans-serif;
font-weight: 700;
- font-size: 15px;
+ font-size: 16px;
color: var(--text-primary);
- transition: color 0.35s;
}
.desc {
font-family: "ALTGumbo", system-ui, sans-serif;
font-weight: 400;
- font-size: 11px;
+ font-size: 12px;
color: var(--text-muted);
margin-top: 6px;
white-space: nowrap;
- transition: color 0.35s;
}
-.arrow {
- display: flex;
- align-items: center;
- padding: 0 4px;
- user-select: none;
-}
-
-.arrowSvg {
- display: block;
- color: var(--border-color);
- transition: color 0.35s;
-}
+/* Positions matching viewBox="0 0 1000 600"
+ Path: M 100 250 L 500 50 L 900 250 L 750 500 L 250 500 Z
+*/
+.node1 { left: 10%; top: 41.66%; } /* 100, 250 */
+.node2 { left: 50%; top: 8.33%; } /* 500, 50 */
+.node3 { left: 90%; top: 41.66%; } /* 900, 250 */
+.node4 { left: 75%; top: 83.33%; } /* 750, 500 */
+.node5 { left: 25%; top: 83.33%; } /* 250, 500 */
-.arrowSvg path {
- stroke: currentColor;
+/* ── Mobile Fallback ── */
+.diagramMobile {
+ display: none;
+ flex-direction: column;
+ align-items: center;
+ gap: 32px;
+ position: relative;
}
-.feedback {
- display: flex;
- justify-content: center;
- margin-top: 20px;
+.mobileLine {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 2px;
+ background: var(--border-color);
+ z-index: 1;
}
-.feedbackSvg {
- width: 100%;
- max-width: 640px;
- height: 72px;
+.mobileAnimatedLine {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 2px;
+ background: repeating-linear-gradient(to bottom, var(--text-primary) 0, var(--text-primary) 20px, transparent 20px, transparent 80px);
+ z-index: 2;
+ background-size: 100% 80px;
+ animation: scrollDown 2s linear infinite;
}
-.feedbackPath {
- stroke: var(--border-color);
- stroke-width: 2;
- stroke-dasharray: 6 4;
- fill: none;
- transition: stroke 0.35s;
+@keyframes scrollDown {
+ 0% { background-position: 0 -80px; }
+ 100% { background-position: 0 0; }
}
-.wrapper:hover .feedbackPath {
- stroke: var(--text-muted);
+.nodeMobile {
+ position: relative;
+ z-index: 3;
+ transform: none !important;
}
-.feedbackText {
- font-family: "ALTGumbo", system-ui, sans-serif;
- font-size: 11px;
- fill: var(--text-muted);
- transition: fill 0.35s;
+@media (max-width: 768px) {
+ .diagramDesktop { display: none; }
+ .diagramMobile { display: flex; }
}
diff --git a/web/src/pages/LandingPage.jsx b/web/src/pages/LandingPage.jsx
index 959a33b..5f6822a 100644
--- a/web/src/pages/LandingPage.jsx
+++ b/web/src/pages/LandingPage.jsx
@@ -25,7 +25,7 @@ const features = [
},
{
icon:
,
- title: "Self-Learning",
+ title: "Self Learning",
description: "Every fix enriches the knowledge base. The model gets smarter with each resolved fault.",
},
];
@@ -111,13 +111,13 @@ export default function LandingPage() {
-
Fault-to-Fix Engine
+
Fault to Fix Engine
From fault code
to fixed.
- TORQ autonomously diagnoses machine faults, generates trilingual work orders, and dispatches the right technician — all in real time.
+ TORQ autonomously diagnoses machine faults, generates trilingual work orders, and dispatches the right technician all in real time.
@@ -166,8 +166,8 @@ export default function LandingPage() {
{/* ── Pipeline ── */}
-
- Pipeline
+
+ How TORQ drives the repair