diff --git a/client/src/App.jsx b/client/src/App.jsx index d91590d..40987d0 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -9,7 +9,6 @@ import Contact from './pages/Contact' import RemoteSensing from './pages/RemoteSensing' import Communications from './pages/Communications' import Trainings from './pages/Trainings' -import ProjectManagement from './pages/ProjectManagement' const THEME_COOKIE = 'graphyma-theme' @@ -93,7 +92,6 @@ function AnimatedRoutes() { } /> } /> } /> - } /> ) diff --git a/client/src/assets/services/communications-dark.png b/client/src/assets/services/communications-dark.png index f2540c7..1d79b46 100644 Binary files a/client/src/assets/services/communications-dark.png and b/client/src/assets/services/communications-dark.png differ diff --git a/client/src/assets/services/communications-light.png b/client/src/assets/services/communications-light.png index af2e3a3..4c43bd3 100644 Binary files a/client/src/assets/services/communications-light.png and b/client/src/assets/services/communications-light.png differ diff --git a/client/src/assets/services/index.js b/client/src/assets/services/index.js index b29f722..f129d42 100644 --- a/client/src/assets/services/index.js +++ b/client/src/assets/services/index.js @@ -4,8 +4,6 @@ import communicationsImgLight from './communications-light.png' import communicationsImgDark from './communications-dark.png' import trainingsImgLight from './trainings-light.png' import trainingsImgDark from './trainings-dark.png' -import projectManagementImgLight from './project-management-light.png' -import projectManagementImgDark from './project-management-dark.png' export { remoteSensingImgLight, @@ -14,6 +12,4 @@ export { communicationsImgDark, trainingsImgLight, trainingsImgDark, - projectManagementImgLight, - projectManagementImgDark, } \ No newline at end of file diff --git a/client/src/assets/services/project-management-dark.png b/client/src/assets/services/project-management-dark.png deleted file mode 100644 index 1d79b46..0000000 Binary files a/client/src/assets/services/project-management-dark.png and /dev/null differ diff --git a/client/src/assets/services/project-management-light.png b/client/src/assets/services/project-management-light.png deleted file mode 100644 index 4c43bd3..0000000 Binary files a/client/src/assets/services/project-management-light.png and /dev/null differ diff --git a/client/src/pages/Communications.jsx b/client/src/pages/Communications.jsx index 65f5a4e..f766756 100644 --- a/client/src/pages/Communications.jsx +++ b/client/src/pages/Communications.jsx @@ -10,10 +10,30 @@ const page = { } const CHANNELS = [ - { title: 'Stakeholder Mapping', detail: 'Prioritize audiences, incentives, and adoption blockers.' }, - { title: 'Narrative Design', detail: 'Translate EO complexity into human-ready stories.' }, - { title: 'Campaign Orchestration', detail: 'Multi-channel delivery and feedback loops.' }, - { title: 'Impact Measurement', detail: 'Usage analytics and adoption KPIs.' }, + { + step: 'Mapping', + title: 'Stakeholder Mapping', + detail: 'Prioritize audiences, incentives, and adoption blockers to focus effort where it matters most.', + duration: 2.8, + }, + { + step: 'Narrative', + title: 'Narrative Design', + detail: 'Translate EO complexity into human-ready stories that resonate with decision-makers.', + duration: 3.05, + }, + { + step: 'Campaign', + title: 'Campaign Orchestration', + detail: 'Multi-channel delivery with continuous feedback loops to maximise reach and relevance.', + duration: 3.3, + }, + { + step: 'Impact', + title: 'Impact Measurement', + detail: 'Usage analytics and adoption KPIs that prove the value of every communication effort.', + duration: 3.55, + }, ] export default function Communications() { @@ -74,7 +94,7 @@ export default function Communications() { transition={{ duration: 0.65, delay: 0.12 }} className="comms-hero-copy" > - We turn Earth Observation insights into business actions, making the value obvious at every level. + We turn Earth Observation insights into business actions, making the value obvious at every level. {/* Rotating belt around the central node */} @@ -198,7 +218,7 @@ export default function Communications() {
-
+
to adoption - - We design the communication flow as a system: every touchpoint drives momentum, every insight gets turned into accessible value for your users. - +
+ {/* + We build communication systems that flow — every interaction drives results, and every insight creates real value for our users. + */} +
+ +
+ {CHANNELS.map((item, i) => ( - {CHANNELS.map((item) => ( - -
{item.title}
-
{item.detail}
-
- ))} -
-
+
+
{String(i + 1).padStart(2, '0')}
+
+
- -
-
- {['Awareness', 'Trial', 'Adoption', 'Advocacy'].map((stage, i) => ( -
-
{stage}
-
- -
+
+
+
{item.step}
+
+
- ))} +
+
{item.title}
+
{item.detail}
-
- + + ))}
diff --git a/client/src/pages/Home.jsx b/client/src/pages/Home.jsx index 3a05006..eb38774 100644 --- a/client/src/pages/Home.jsx +++ b/client/src/pages/Home.jsx @@ -14,8 +14,6 @@ import { communicationsImgDark, trainingsImgLight, trainingsImgDark, - projectManagementImgLight, - projectManagementImgDark, } from '../assets/services/index.js' /* ── Page variants ─────────────────────────────── */ @@ -50,13 +48,6 @@ const SERVICES = [ link: '/services/trainings', delay: 0.2, }, - { - number: '04', icon: 'pm', - title: 'Project Management', - description: 'Strategic oversight and coordination of Earth Observation projects across public, private, and international stakeholder environments.', - link: '/services/project-management', - delay: 0.3, - }, ] const STATS = [ @@ -72,28 +63,6 @@ const FLOAT_LABELS = [ { label: 'Change Detection', top: '38%', left: '-12%', delay: 1.7 }, ] -const MARKET_FACTS = [ - { - value: '$46.8B', - label: 'Projected global satellite market by 2031', - sub: 'Driven by EO, geospatial intelligence & remote sensing', - }, - { - value: '25%', - label: 'Of the global satellite industry', - sub: 'Earth Observation is one of the largest segments', - }, - { - value: '50%+', - label: 'Of EO applications', - sub: 'Supporting agriculture, forestry, environmental monitoring & natural resource management', - }, - { - value: '60%', - label: 'Of Essential Climate Variables', - sub: 'Can be addressed by satellite data', - }, -] const ORBIT_NODES = [ { label: 'ESA', cx: 80, cy: 230 }, @@ -119,11 +88,6 @@ const SERVICE_VISUALS = [ imgDark: trainingsImgDark, imgLight: trainingsImgLight, }, - { - title: 'Project Management', - imgDark: projectManagementImgDark, - imgLight: projectManagementImgLight, - }, ] @@ -307,52 +271,6 @@ export default function Home() { - - {/* ══════════════════════════════════════ - MARKET FACTS - ══════════════════════════════════════ */} - {/*
-
- - Industry at a Glance - - - - The scale of Earth Observation - - -
- {MARKET_FACTS.map(({ value, label, sub }, i) => ( - -
-
{value}
-
{label}
-
{sub}
- - ))} -
-
-
*/} - {/* ══════════════════════════════════════ SERVICES ══════════════════════════════════════ */} diff --git a/client/src/pages/ProjectManagement.jsx b/client/src/pages/ProjectManagement.jsx deleted file mode 100644 index 9dbc3f3..0000000 --- a/client/src/pages/ProjectManagement.jsx +++ /dev/null @@ -1,245 +0,0 @@ -import { useRef, useState } from 'react' -import { motion } from 'framer-motion' -import { Link } from 'react-router-dom' -import './styles/ProjectManagement.css' - -const page = { - initial: { opacity: 0, y: 40 }, - animate: { opacity: 1, y: 0, transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] } }, - exit: { opacity: 0, y: -30, transition: { duration: 0.35, ease: [0.4, 0, 1, 1] } }, -} - -const GOVERNANCE = [ - { title: 'Scope Control', detail: 'Clear milestones, structured risk tracking.' }, - { title: 'Stakeholder Alignment', detail: 'Multi-actor coordination and consensus.' }, - { title: 'Delivery Assurance', detail: 'Quality gates, documentation, handover.' }, - { title: 'Impact Reporting', detail: 'Performance metrics and ROI tracking.' }, -] - -export default function ProjectManagement() { - const ganttRef = useRef(null) - const [ganttOffset, setGanttOffset] = useState({ x: 0, y: 0 }) - - function handleGanttMove(e) { - const rect = ganttRef.current?.getBoundingClientRect() - if (!rect) return - const x = ((e.clientX - rect.left) / rect.width - 0.5) * 30 - const y = ((e.clientY - rect.top) / rect.height - 0.5) * 30 - setGanttOffset({ x, y }) - } - - function handleGanttLeave() { - setGanttOffset({ x: 0, y: 0 }) - } - - return ( - -
-
-
- - Project Management - -
-
- - Programmes delivered - with precision - - - We guide EO initiatives from concept to completion across public and private stakeholders. Our management approach ensures clarity, governance, and on-time delivery. - - - Plan a Programme - Delivery Framework - -
- - -
-
- - - - - - - - - - {[ - { x: 40, y: 50, w: 90, h: 48, delay: 0 }, - { x: 210, y: 44, w: 84, h: 46, delay: 0.2 }, - { x: 32, y: 150, w: 100, h: 50, delay: 0.4 }, - { x: 208, y: 150, w: 92, h: 50, delay: 0.6 }, - ].map((card, i) => ( - - - - - - - ))} - - {[ - { x1: 120, y1: 118, x2: 88, y2: 92 }, - { x1: 200, y1: 118, x2: 232, y2: 92 }, - { x1: 120, y1: 164, x2: 86, y2: 170 }, - { x1: 200, y1: 164, x2: 232, y2: 172 }, - ].map((line, i) => ( - - ))} - - - - -
- -
-
-
- -
-
-
-
- - Delivery System - - - Structured governance - with momentum - - - Our project management model blends agile execution with public-sector compliance, giving you full visibility while keeping delivery velocity high. - - - {GOVERNANCE.map((item) => ( - -
{item.title}
-
{item.detail}
-
- ))} -
-
- - -
-
- {['Discovery', 'Planning', 'Execution', 'Validation', 'Handover'].map((stage, i) => ( -
-
{String(i + 1).padStart(2, '0')}
-
- -
-
{stage}
-
- ))} -
-
-
-
-
-
-
- ) -} - diff --git a/client/src/pages/RemoteSensing.jsx b/client/src/pages/RemoteSensing.jsx index 041e69c..0615ad8 100644 --- a/client/src/pages/RemoteSensing.jsx +++ b/client/src/pages/RemoteSensing.jsx @@ -11,26 +11,36 @@ const page = { const CAPABILITIES = [ { - title: 'Understand Your Needs', - detail: 'Aligning Earth Observation solutions with your objectives.', + step: 'Acquisition', + title: 'Acquisition Strategy', + detail: 'Choose the right sensors, providers and datasets for your specific use case and budget.', + duration: 2.8, }, { + step: 'Identify', title: 'Identify the Right EO Data', - detail: 'Selecting the most suitable satellite data and platforms.', + detail: 'Prepare and organise Earth Observation data from the most relevant platforms and archives.', + duration: 3.05, }, { + step: 'Analyse', title: 'Analyse & Interpret', - detail: 'Transforming satellite data into meaningful insights.', + detail: 'Extract meaningful insights using advanced processing techniques and domain expertise.', + duration: 3.3, }, { + step: 'Deliver', title: 'Deliver Actionable Insights', - detail: 'Clear reports, dashboards, and decision-ready outputs.', + detail: 'Verify results, ensure quality and produce decision-ready outputs for your team.', + duration: 3.55, }, { + step: 'Support', title: 'Support & Capacity Building', - detail: 'Training teams for confident Earth Observation adoption.', + detail: 'Train and upskill your team for confident, long-term Earth Observation adoption.', + duration: 3.8, }, -]; +] function SatelliteGraphic() { return ( @@ -234,7 +244,7 @@ export default function RemoteSensing() {
-
+
built for clarity - - We deliver fast, high-quality insights using a proven process. Most importantly, we adapt our workflow to fit your business decisions, not the other way around. - +
+ {/* + We deliver fast, high-quality insights using a proven process — adapted to fit your decisions, not the other way around. + */} +
+ +
+ {CAPABILITIES.map((item, i) => ( - {CAPABILITIES.map((item) => ( - -
{item.title}
-
{item.detail}
-
- ))} -
-
+
+
{String(i + 1).padStart(2, '0')}
+
+
- -
-
- {['Understand', 'Identify', 'Analyse', 'Deliver', 'Support'].map((step, i) => ( -
-
{String(i + 1).padStart(2, '0')}
-
- -
-
{step}
+
+
+
{item.step}
+
+
- ))} +
+
{item.title}
+
{item.detail}
-
- + + ))}
diff --git a/client/src/pages/Trainings.jsx b/client/src/pages/Trainings.jsx index e2c6bd2..aeea073 100644 --- a/client/src/pages/Trainings.jsx +++ b/client/src/pages/Trainings.jsx @@ -10,10 +10,30 @@ const page = { } const MODULES = [ - { title: 'EO Fundamentals', detail: 'Satellite systems, sensors, and data types.' }, - { title: 'GIS Platforms', detail: 'QGIS, ArcGIS, and web-based mapping stacks.' }, - { title: 'Analytics', detail: 'Indices, ML pipelines, and evaluation.' }, - { title: 'Operational Delivery', detail: 'Dashboards, APIs, and deployment workflows.' }, + { + step: 'Fundamentals', + title: 'EO Fundamentals', + detail: 'Satellite systems, sensors, and data types — the foundation every practitioner needs.', + duration: 2.8, + }, + { + step: 'GIS', + title: 'GIS Platforms', + detail: 'QGIS, ArcGIS, and web-based mapping stacks with hands-on lab exercises.', + duration: 3.05, + }, + { + step: 'Analytics', + title: 'Analytics & ML', + detail: 'Indices, machine learning pipelines, and rigorous evaluation frameworks.', + duration: 3.3, + }, + { + step: 'Delivery', + title: 'Operational Delivery', + detail: 'Dashboards, APIs, and deployment workflows your team can use from day one.', + duration: 3.55, + }, ] export default function Trainings() { @@ -176,7 +196,7 @@ export default function Trainings() {
-
+
that scale - - Choose standalone modules or build a multi-week programme. Every module includes exercises, datasets, and applied deliverables that your team can use immediately. - +
+ {/* + Choose standalone modules or build a multi-week programme. Every module includes exercises, datasets, and applied deliverables your team can use immediately. + */} +
+ +
+ {MODULES.map((item, i) => ( - {MODULES.map((item) => ( - -
{item.title}
-
{item.detail}
-
- ))} -
-
+
+
{String(i + 1).padStart(2, '0')}
+
+
- -
-
- {['Bootcamp', 'Applied Labs', 'Certification'].map((stage, i) => ( -
-
{String(i + 1).padStart(2, '0')}
-
- -
-
{stage}
+
+
+
{item.step}
+
+
- ))} +
+
{item.title}
+
{item.detail}
-
- + + ))}
diff --git a/client/src/pages/styles/Communications.css b/client/src/pages/styles/Communications.css index fe99896..d6d732e 100644 --- a/client/src/pages/styles/Communications.css +++ b/client/src/pages/styles/Communications.css @@ -100,12 +100,6 @@ border: 1px solid rgba(var(--accent-rgb),0.5); } -.comms-section-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 3rem; - align-items: center; -} .comms-section-title { font-size: clamp(2rem, 3.4vw, 2.8rem); @@ -116,82 +110,141 @@ display: block; } -.comms-section-copy { - color:var(--text-2); - line-height: 1.85; - margin-bottom: 2rem; -} - -.comms-channel-list { +.comms-pipeline-header { display: grid; - gap: 1rem; + grid-template-columns: 1fr 1fr; + gap: 3rem; + align-items: end; + margin-bottom: 3rem; } -.comms-channel-card { - padding: 1rem 1.25rem; - border-radius: 16px; - border: 1px solid rgba(var(--accent-rgb),0.12); - background: rgba(var(--accent-rgb),0.02); +.comms-pipeline-copy { + color: var(--text-2); + line-height: 1.85; + font-size: 0.95rem; + padding-bottom: 0.25rem; } -.comms-channel-title { - font-family: var(--font-display); - font-weight: 700; - color: var(--text-1); - margin-bottom: 0.4rem; +.comms-pipeline-list { + display: grid; + gap: 0; } -.comms-channel-detail { - color: var(--text-2); - font-size: 0.88rem; - line-height: 1.6; +.comms-pipeline-card { + display: flex; + gap: 1.75rem; + padding: 1.75rem 1rem; + border-bottom: 1px solid rgba(var(--accent-rgb), 0.07); + border-radius: 12px; + cursor: default; + transition: background 0.3s; } -.comms-stage-card { - border-radius: 22px; - border: 1px solid rgba(var(--accent-rgb),0.14); - background: rgba(var(--accent-rgb),0.025); - padding: 2rem; +.comms-pipeline-card:first-child { + border-top: 1px solid rgba(var(--accent-rgb), 0.07); } -.comms-stage-list { - display: grid; - gap: 1.25rem; +.comms-pipeline-card:hover { + background: rgba(var(--accent-rgb), 0.025); } -.comms-stage-row { +.comms-pipeline-left { display: flex; + flex-direction: column; align-items: center; - gap: 1rem; + flex-shrink: 0; } -.comms-stage-pill { - width: 56px; - height: 56px; - border-radius: 14px; - border: 1px solid rgba(var(--accent-rgb),0.25); +.comms-pipeline-number { + width: 40px; + height: 40px; + border-radius: 50%; + border: 1px solid rgba(var(--accent-rgb), 0.3); + background: rgba(var(--accent-rgb), 0.05); display: flex; align-items: center; justify-content: center; color: var(--accent); font-family: var(--font-mono); - font-size: 0.7rem; - letter-spacing: 0.1em; + font-size: 0.68rem; + letter-spacing: 0.06em; + flex-shrink: 0; + transition: background 0.3s, border-color 0.3s; +} + +.comms-pipeline-card:hover .comms-pipeline-number { + background: rgba(var(--accent-rgb), 0.12); + border-color: rgba(var(--accent-rgb), 0.55); +} + +.comms-pipeline-connector { + width: 1px; + flex: 1; + background: rgba(var(--accent-rgb), 0.1); + margin: 6px 0; +} + +.comms-pipeline-card:last-child .comms-pipeline-connector { + display: none; +} + +.comms-pipeline-body { + flex: 1; + padding-top: 0.5rem; + padding-bottom: 0.25rem; +} + +.comms-pipeline-top { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 0.65rem; +} + +.comms-pipeline-step { + font-family: var(--font-mono); + font-size: 0.75rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--accent); + white-space: nowrap; + opacity: 0.75; } -.comms-stage-bar { +.comms-pipeline-bar { flex: 1; - height: 8px; + height: 3px; border-radius: 999px; - background: rgba(var(--accent-rgb),0.08); + background: rgba(var(--accent-rgb), 0.07); position: relative; overflow: hidden; } -.comms-stage-sweep { +.comms-pipeline-sweep { position: absolute; inset: 0; - width: 45%; - background: linear-gradient(90deg, rgba(var(--accent-rgb),0.1), rgba(var(--accent-rgb),0.6), rgba(var(--accent-rgb),0.1)); + width: 40%; + background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb), 0.55), transparent); +} + +.comms-pipeline-title { + font-family: var(--font-display); + font-size: 1.05rem; + font-weight: 700; + color: var(--text); + margin-bottom: 0.4rem; +} + +.comms-pipeline-detail { + color: var(--text-2); + font-size: 0.87rem; + line-height: 1.65; +} + +@media (max-width: 900px) { + .comms-pipeline-header { + grid-template-columns: 1fr; + gap: 1rem; + } } diff --git a/client/src/pages/styles/Home.css b/client/src/pages/styles/Home.css index 835a456..a73891e 100644 --- a/client/src/pages/styles/Home.css +++ b/client/src/pages/styles/Home.css @@ -309,7 +309,7 @@ .home-service-visual-grid { display: grid; - grid-template-columns: repeat(4, 1fr); + grid-template-columns: repeat(3, 1fr); gap: 1.25rem; margin-bottom: 1.5rem; } diff --git a/client/src/pages/styles/ProjectManagement.css b/client/src/pages/styles/ProjectManagement.css deleted file mode 100644 index 2421c74..0000000 --- a/client/src/pages/styles/ProjectManagement.css +++ /dev/null @@ -1,176 +0,0 @@ -.pm-hero { - padding-top: 120px; - position: relative; -} - -.pm-hero-container { - position: relative; - z-index: 2; -} - -.pm-hero-grid { - display: grid; - grid-template-columns: 1.05fr 0.95fr; - gap: 3.5rem; - align-items: center; -} - -.pm-hero-title { - font-size: clamp(2.6rem, 4.6vw, 4rem); - line-height: 1.05; - margin-bottom: 1.5rem; -} - -.pm-title-break { - display: block; -} - -.pm-hero-copy { - color: var(--text-2); - line-height: 1.9; - max-width: 560px; - margin-bottom: 2rem; -} - -.pm-hero-actions { - display: flex; - gap: 1rem; - flex-wrap: wrap; -} - -.pm-card-wrap { - position: relative; -} - -.pm-card { - padding: 2.5rem; - border-radius: 22px; - border: 1px solid rgba(var(--accent-rgb),0.12); - background: rgba(var(--accent-rgb),0.02); - position: relative; - overflow: hidden; -} - -.pm-card-grid { - opacity: 0.35; -} - -.pm-card-shift { - transition: transform 0.15s ease; -} - -.pm-card-svg { - width: 100%; - height: 100%; -} - -.pm-scan-line { - position: absolute; - bottom: 58px; - left: 0; - height: 8px; - width: 220px; - background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb),0.5), transparent); -} - -.pm-section-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 3rem; - align-items: center; -} - -.pm-section-title { - font-size: clamp(2rem, 3.4vw, 2.8rem); - margin-bottom: 1.25rem; -} - -.pm-section-title-break { - display: block; -} - -.pm-section-copy { - color: var(--text-2); - line-height: 1.85; - margin-bottom: 2rem; -} - -.pm-governance-list { - display: grid; - gap: 1rem; -} - -.pm-governance-card { - padding: 1rem 1.25rem; - border-radius: 16px; - border: 1px solid rgba(var(--accent-rgb),0.12); - background: rgba(var(--accent-rgb),0.02); -} - -.pm-governance-title { - font-family: var(--font-display); - font-weight: 700; - color: var(--text); - margin-bottom: 0.4rem; -} - -.pm-governance-detail { - color: var(--text-2); - font-size: 0.88rem; - line-height: 1.6; -} - -.pm-path-card { - border-radius: 22px; - border: 1px solid rgba(var(--accent-rgb),0.14); - background: rgba(var(--accent-rgb),0.025); - padding: 2rem; -} - -.pm-path-list { - display: grid; - gap: 1.1rem; -} - -.pm-path-row { - display: flex; - align-items: center; - gap: 1rem; -} - -.pm-path-pill { - width: 36px; - height: 36px; - border-radius: 50%; - border: 1px solid rgba(var(--accent-rgb),0.4); - display: flex; - align-items: center; - justify-content: center; - color: var(--accent); - font-family: var(--font-mono); - font-size: 0.7rem; -} - -.pm-path-bar { - flex: 1; - height: 6px; - border-radius: 999px; - background: rgba(var(--accent-rgb),0.08); - position: relative; - overflow: hidden; -} - -.pm-path-sweep { - position: absolute; - inset: 0; - width: 45%; - background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb),0.5), transparent); -} - -.pm-path-label { - min-width: 92px; - color: var(--text-2); - font-family: var(--font-mono); - font-size: 0.7rem; - letter-spacing: 0.12em; -} diff --git a/client/src/pages/styles/RemoteSensing.css b/client/src/pages/styles/RemoteSensing.css index b22a7cc..d5be463 100644 --- a/client/src/pages/styles/RemoteSensing.css +++ b/client/src/pages/styles/RemoteSensing.css @@ -207,12 +207,6 @@ position: relative; } -.rs-section-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 3rem; - align-items: center; -} .rs-section-title { font-size: clamp(2rem, 3.4vw, 2.8rem); @@ -223,93 +217,143 @@ display: block; } -.rs-section-copy { - color:var(--text-2); - line-height: 1.85; - margin-bottom: 2rem; -} - -.rs-capability-list { +.rs-pipeline-header { display: grid; - gap: 1rem; + grid-template-columns: 1fr 1fr; + gap: 3rem; + align-items: end; + margin-bottom: 3rem; } -.rs-capability-card { - padding: 1rem 1.25rem; - border-radius: 16px; - border: 1px solid rgba(var(--accent-rgb),0.12); - background: rgba(var(--accent-rgb),0.02); +.rs-pipeline-copy { + color: var(--text-2); + line-height: 1.85; + font-size: 0.95rem; + padding-bottom: 0.25rem; } -.rs-capability-title { - font-family: var(--font-display); - font-weight: 700; - color: var(--text-1); - margin-bottom: 0.4rem; +.rs-pipeline-list { + display: grid; + gap: 0; } -.rs-capability-detail { - color:var(--text-2); - font-size: 0.88rem; - line-height: 1.6; +.rs-pipeline-card { + display: flex; + gap: 1.75rem; + padding: 1.75rem 0; + border-bottom: 1px solid rgba(var(--accent-rgb), 0.07); + cursor: default; + transition: background 0.3s; + border-radius: 12px; + padding-left: 1rem; + padding-right: 1rem; } -.rs-stage-card { - border-radius: 22px; - border: 1px solid rgba(var(--accent-rgb),0.14); - background: rgba(var(--accent-rgb),0.025); - padding: 2rem; +.rs-pipeline-card:first-child { + border-top: 1px solid rgba(var(--accent-rgb), 0.07); } -.rs-stage-list { - display: grid; - gap: 3rem; +.rs-pipeline-card:hover { + background: rgba(var(--accent-rgb), 0.025); } -.rs-stage-row { +.rs-pipeline-left { display: flex; + flex-direction: column; align-items: center; - gap: 1rem; + gap: 0; + flex-shrink: 0; } -.rs-stage-number { - width: 36px; - height: 36px; +.rs-pipeline-number { + width: 40px; + height: 40px; border-radius: 50%; - border: 1px solid rgba(var(--accent-rgb),0.4); + border: 1px solid rgba(var(--accent-rgb), 0.3); + background: rgba(var(--accent-rgb), 0.05); display: flex; align-items: center; justify-content: center; color: var(--accent); font-family: var(--font-mono); - font-size: 0.7rem; + font-size: 0.68rem; + letter-spacing: 0.06em; + flex-shrink: 0; + transition: background 0.3s, border-color 0.3s; } -.rs-stage-bar { +.rs-pipeline-card:hover .rs-pipeline-number { + background: rgba(var(--accent-rgb), 0.12); + border-color: rgba(var(--accent-rgb), 0.55); +} + +.rs-pipeline-connector { + width: 1px; + flex: 1; + background: rgba(var(--accent-rgb), 0.1); + margin: 6px 0; +} + +.rs-pipeline-card:last-child .rs-pipeline-connector { + display: none; +} + +.rs-pipeline-body { flex: 1; - height: 6px; + padding-top: 0.5rem; + padding-bottom: 0.25rem; +} + +.rs-pipeline-top { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 0.65rem; +} + +.rs-pipeline-step { + font-family: var(--font-mono); + font-size: 0.75rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--accent); + white-space: nowrap; + opacity: 0.75; +} + +.rs-pipeline-bar { + flex: 1; + height: 3px; border-radius: 999px; - background: rgba(var(--accent-rgb),0.08); + background: rgba(var(--accent-rgb), 0.07); position: relative; overflow: hidden; } -.rs-stage-sweep { +.rs-pipeline-sweep { position: absolute; inset: 0; - width: 45%; - background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb),0.5), transparent); + width: 40%; + background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb), 0.55), transparent); } -.rs-stage-label { - min-width: 90px; - color:var(--text-2); - font-family: var(--font-mono); - font-size: 0.7rem; - letter-spacing: 0.12em; +.rs-pipeline-title { + font-family: var(--font-display); + font-size: 1.05rem; + font-weight: 700; + color: var(--text); + margin-bottom: 0.4rem; } -.rs-stage-align { - align-self: end; - padding-bottom: 2.2rem; +.rs-pipeline-detail { + color: var(--text-2); + font-size: 0.87rem; + line-height: 1.65; } + +@media (max-width: 900px) { + .rs-pipeline-header { + grid-template-columns: 1fr; + gap: 1rem; + } +} \ No newline at end of file diff --git a/client/src/pages/styles/Trainings.css b/client/src/pages/styles/Trainings.css index e5dded2..f9bc586 100644 --- a/client/src/pages/styles/Trainings.css +++ b/client/src/pages/styles/Trainings.css @@ -73,12 +73,7 @@ background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb),0.7), transparent); } -.train-section-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 3rem; - align-items: center; -} + .train-section-title { font-size: clamp(2rem, 3.4vw, 2.8rem); @@ -89,89 +84,141 @@ display: block; } -.train-section-copy { - color: var(--text-2); - line-height: 1.85; - margin-bottom: 2rem; -} -.train-module-list { +.train-pipeline-header { display: grid; - gap: 1rem; + grid-template-columns: 1fr 1fr; + gap: 3rem; + align-items: end; + margin-bottom: 3rem; } -.train-module-card { - padding: 1rem 1.25rem; - border-radius: 16px; - border: 1px solid rgba(var(--accent-rgb),0.12); - background: rgba(var(--accent-rgb),0.02); +.train-pipeline-copy { + color: var(--text-2); + line-height: 1.85; + font-size: 0.95rem; + padding-bottom: 0.25rem; } -.train-module-title { - font-family: var(--font-display); - font-weight: 700; - color: var(--text); - margin-bottom: 0.4rem; +.train-pipeline-list { + display: grid; + gap: 0; } -.train-module-detail { - color: var(--text-2); - font-size: 0.88rem; - line-height: 1.6; +.train-pipeline-card { + display: flex; + gap: 1.75rem; + padding: 1.75rem 1rem; + border-bottom: 1px solid rgba(var(--accent-rgb), 0.07); + border-radius: 12px; + cursor: default; + transition: background 0.3s; } -.train-path-card { - border-radius: 22px; - border: 1px solid rgba(var(--accent-rgb),0.14); - background: rgba(var(--accent-rgb),0.025); - padding: 2rem; +.train-pipeline-card:first-child { + border-top: 1px solid rgba(var(--accent-rgb), 0.07); } -.train-path-list { - display: grid; - gap: 1.25rem; +.train-pipeline-card:hover { + background: rgba(var(--accent-rgb), 0.025); } -.train-path-row { +.train-pipeline-left { display: flex; + flex-direction: column; align-items: center; - gap: 1rem; + flex-shrink: 0; } -.train-path-pill { - width: 46px; - height: 46px; - border-radius: 12px; - border: 1px solid rgba(var(--accent-rgb),0.25); +.train-pipeline-number { + width: 40px; + height: 40px; + border-radius: 50%; + border: 1px solid rgba(var(--accent-rgb), 0.3); + background: rgba(var(--accent-rgb), 0.05); display: flex; align-items: center; justify-content: center; color: var(--accent); font-family: var(--font-mono); - font-size: 0.7rem; - letter-spacing: 0.1em; + font-size: 0.68rem; + letter-spacing: 0.06em; + flex-shrink: 0; + transition: background 0.3s, border-color 0.3s; +} + +.train-pipeline-card:hover .train-pipeline-number { + background: rgba(var(--accent-rgb), 0.12); + border-color: rgba(var(--accent-rgb), 0.55); +} + +.train-pipeline-connector { + width: 1px; + flex: 1; + background: rgba(var(--accent-rgb), 0.1); + margin: 6px 0; +} + +.train-pipeline-card:last-child .train-pipeline-connector { + display: none; +} + +.train-pipeline-body { + flex: 1; + padding-top: 0.5rem; + padding-bottom: 0.25rem; +} + +.train-pipeline-top { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 0.65rem; +} + +.train-pipeline-step { + font-family: var(--font-mono); + font-size: 0.75rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--accent); + white-space: nowrap; + opacity: 0.75; } -.train-path-bar { +.train-pipeline-bar { flex: 1; - height: 8px; + height: 3px; border-radius: 999px; - background: rgba(var(--accent-rgb),0.08); + background: rgba(var(--accent-rgb), 0.07); position: relative; overflow: hidden; } -.train-path-sweep { +.train-pipeline-sweep { position: absolute; inset: 0; - width: 45%; - background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb),0.5), transparent); + width: 40%; + background: linear-gradient(90deg, transparent, rgba(var(--accent-rgb), 0.55), transparent); +} + +.train-pipeline-title { + font-family: var(--font-display); + font-size: 1.05rem; + font-weight: 700; + color: var(--text); + margin-bottom: 0.4rem; } -.train-path-label { - min-width: 90px; +.train-pipeline-detail { color: var(--text-2); - font-family: var(--font-mono); - font-size: 0.7rem; - letter-spacing: 0.12em; + font-size: 0.87rem; + line-height: 1.65; } + +@media (max-width: 900px) { + .train-pipeline-header { + grid-template-columns: 1fr; + gap: 1rem; + } +} \ No newline at end of file