diff --git a/src/css/common.css b/src/css/common.css
index 4076549..d091492 100644
--- a/src/css/common.css
+++ b/src/css/common.css
@@ -1012,77 +1012,62 @@ body{overflow-x:hidden;}
}
-/* ════════════════════════════════
- MaintenancePage (mt-)
-════════════════════════════════ */
-
-/* ── 인트로 ── */
-.mt-intro {display:flex;gap:80px;align-items:flex-start;padding:80px 0 100px;}
-.mt-intro__left {flex:0 0 420px;}
-.mt-intro__right {flex:1;min-width:0;padding-top:8px;}
+/*maintenance page*/
+.mt-intro {display:flex;gap:80px;align-items:center;padding:80px 0 100px;}
+.mt-intro__left {flex:0 0 400px;}
+.mt-intro__right {flex:1;min-width:0;display:flex;justify-content:center;}
.mt-title-line {overflow:hidden;padding-bottom:.06em;margin-bottom:-.06em;}
-.mt-intro__title {font-size:clamp(26px,2.8vw,38px);font-weight:800;color:var(--color-primary);line-height:1.3;letter-spacing:-.03em;margin:0;}
+.mt-intro__title {font-size:clamp(28px,3vw,42px);font-weight:800;color:var(--color-primary);line-height:1.25;letter-spacing:-.03em;margin:0;}
.mt-intro__desc {font-size:.9rem;color:#666;line-height:1.9;margin:28px 0 36px;word-break:keep-all;}
.mt-intro__cta {display:inline-flex;align-items:center;gap:8px;font-size:.88rem;font-weight:700;color:var(--pink);text-decoration:none;letter-spacing:-.01em;transition:gap .25s;}
.mt-intro__cta:hover {gap:14px;}
-/* ── Quote 카드 ── */
-.mt-quote {position:relative;margin-top:40px;padding:32px 28px 28px;border-radius:20px;background:var(--color-primary);overflow:hidden;}
-.mt-quote::before {content:'';position:absolute;inset:0;background:var(--grad-brand);opacity:.18;pointer-events:none;}
-.mt-quote::after {content:'';position:absolute;inset:0;background-image:radial-gradient(rgba(255,255,255,.07) 1px,transparent 1px);background-size:18px 18px;pointer-events:none;}
-.mt-quote__mark {position:relative;z-index:1;font-size:2.5rem;font-weight:900;color:var(--pink);line-height:1;margin-bottom:12px;}
-.mt-quote__text {position:relative;z-index:1;font-size:1.05rem;font-weight:700;color:#fff;line-height:1.65;letter-spacing:-.02em;margin:0 0 20px;}
-.mt-quote__brand {position:relative;z-index:1;font-size:.72rem;font-weight:600;color:rgba(255,255,255,.35);letter-spacing:.12em;text-transform:uppercase;}
-
-/* ── 서비스 리스트 ── */
-.mt-svc-list {list-style:none;margin:0;padding:0;}
-.mt-svc-item {position:relative;display:flex;align-items:center;gap:24px;padding:20px 0;border-top:1px solid var(--color-primary-soft-border);cursor:default;overflow:hidden;transition:padding-left .35s cubic-bezier(.22,1,.36,1);}
-.mt-svc-list li:last-child {border-bottom:1px solid var(--color-primary-soft-border);}
-.mt-svc-item:hover, .mt-svc-item.is-active {padding-left:12px;}
+/* ── OPS CENTER ── */
+.mt-ops {position:relative;width:100%;max-width:560px;aspect-ratio:1/1;}
+.mt-ops__svg {width:100%;height:100%;overflow:visible;}
-.mt-svc-item__num {font-size:.7rem;font-weight:800;letter-spacing:.1em;color:var(--color-primary-border-strong);flex-shrink:0;width:28px;transition:color .3s;}
-.mt-svc-item:hover .mt-svc-item__num, .mt-svc-item.is-active .mt-svc-item__num {color:var(--pink);}
+.mt-ops__pulse {transform-origin:320px 320px;}
-.mt-svc-item__body {flex:1;min-width:0;}
-.mt-svc-item__title {display:block;font-size:1rem;font-weight:700;color:#bbb;letter-spacing:-.01em;transition:color .3s;}
-.mt-svc-item:hover .mt-svc-item__title, .mt-svc-item.is-active .mt-svc-item__title {color:var(--color-primary);}
-.mt-svc-item__desc {display:block;font-size:.78rem;color:#bbb;line-height:1.5;margin-top:4px;max-height:0;opacity:0;overflow:hidden;transform:translateY(4px);transition:max-height .35s ease, opacity .3s ease, transform .3s ease;}
-.mt-svc-item:hover .mt-svc-item__desc, .mt-svc-item.is-active .mt-svc-item__desc {max-height:3rem;opacity:1;transform:translateY(0);}
+@keyframes mt-pulse-1 {
+ 0% { transform: scale(1); opacity: 1; }
+ 100% { transform: scale(3.2); opacity: 0; }
+}
+@keyframes mt-pulse-2 {
+ 0% { transform: scale(1); opacity: 1; }
+ 100% { transform: scale(2.6); opacity: 0; }
+}
-.mt-svc-item__icon-wrap {flex-shrink:0;width:64px;height:64px;display:flex;align-items:center;justify-content:center;opacity:0;transform:scale(.85) translateX(8px);transition:opacity .35s ease, transform .35s cubic-bezier(.22,1,.36,1);}
-.mt-svc-item:hover .mt-svc-item__icon-wrap, .mt-svc-item.is-active .mt-svc-item__icon-wrap {opacity:1;transform:scale(1) translateX(0);}
-.mt-svc-item__icon {width:100%;height:100%;object-fit:contain;}
+.mt-ops__pulse--1 {animation: mt-pulse-1 2.8s ease-out infinite;}
+.mt-ops__pulse--2 {animation: mt-pulse-2 2.8s ease-out infinite 1.4s;}
-.mt-svc-item__bar {position:absolute;bottom:0;left:0;right:0;height:1px;background:var(--grad-brand-h);transform:scaleX(0);transform-origin:left;transition:transform .4s cubic-bezier(.22,1,.36,1);}
-.mt-svc-item:hover .mt-svc-item__bar, .mt-svc-item.is-active .mt-svc-item__bar {transform:scaleX(1);}
+.mt-ops__center {position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:108px;height:108px;border-radius:50%;background:var(--grad-brand);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;box-shadow:0 8px 32px rgba(123,63,160,.35);}
+.mt-ops__center-label {font-size:.95rem;font-weight:900;color:#fff;letter-spacing:.08em;line-height:1;}
+.mt-ops__center-sub {font-size:.6rem;font-weight:700;color:rgba(255,255,255,.7);letter-spacing:.15em;}
/* ── KPI 바 ── */
.mt-kpi {background:var(--color-primary);padding:56px 0;margin:0 0 100px;}
.mt-kpi__grid {display:grid;grid-template-columns:repeat(4,1fr);gap:0;}
-.mt-kpi__item {display:flex;flex-direction:column;align-items:center;gap:8px;padding:20px 16px;border-right:1px solid rgba(255,255,255,.1);text-align:center;transition:background .2s;}
+.mt-kpi__item {display:flex;flex-direction:column;align-items:center;gap:10px;padding:20px 16px;border-right:1px solid rgba(255,255,255,.1);text-align:center;}
.mt-kpi__item:last-child {border-right:none;}
-.mt-kpi__item:hover {background:rgba(255,255,255,.05);}
-.mt-kpi__icon {font-size:1.4rem;margin-bottom:4px;opacity:.7;}
-.mt-kpi__value {font-size:clamp(28px,3.5vw,48px);font-weight:900;color:#fff;letter-spacing:-.04em;line-height:1;}
+.mt-kpi__value {font-size:clamp(28px,3.5vw,52px);font-weight:900;color:#fff;letter-spacing:-.04em;line-height:1;}
.mt-kpi__label {font-size:.78rem;font-weight:500;color:rgba(255,255,255,.45);line-height:1.4;}
/* ── 5컬럼 서비스 ── */
.mt-services {padding-bottom:120px;}
-.mt-services__grid {display:grid;grid-template-columns:repeat(5,1fr);gap:0;border:1px solid var(--color-primary-soft-border);border-radius:16px;overflow:hidden;margin-top:40px;}
+.mt-services__grid {display:grid;grid-template-columns:repeat(5,1fr);gap:0;border:1px solid var(--color-primary-soft-border);border-radius:16px;overflow:hidden;}
.mt-service-card {position:relative;display:flex;flex-direction:column;gap:12px;padding:32px 24px 28px;border-right:1px solid var(--color-primary-soft-border);overflow:hidden;transition:background .25s;}
.mt-service-card:last-child {border-right:none;}
.mt-service-card:hover {background:var(--color-primary-soft);}
-.mt-service-card__img-wrap {width:72px;height:72px;margin-bottom:8px;flex-shrink:0;transition:transform .4s cubic-bezier(.22,1,.36,1);}
-.mt-service-card:hover .mt-service-card__img-wrap {transform:translateY(-6px) scale(1.06);}
+.mt-service-card__img-wrap {width:72px;height:72px;margin-bottom:8px;transition:transform .4s cubic-bezier(.22,1,.36,1);}
+.mt-service-card:hover .mt-service-card__img-wrap {transform:translateY(-6px) scale(1.08);}
.mt-service-card__img {width:100%;height:100%;object-fit:contain;}
-/* 이미지 파일명: mt_icon01.png ~ mt_icon05.png */
-.mt-service-card__num {font-size:.7rem;font-weight:800;letter-spacing:.12em;color:var(--pink);opacity:.7;}
+.mt-service-card__num {font-size:.7rem;font-weight:800;letter-spacing:.12em;color:var(--pink);opacity:.8;}
.mt-service-card__title {font-size:1rem;font-weight:800;color:var(--color-primary);letter-spacing:-.02em;margin:0;}
.mt-service-card__desc {font-size:.78rem;color:#888;line-height:1.7;word-break:keep-all;margin:0;}
@@ -1098,6 +1083,7 @@ body{overflow-x:hidden;}
@media (max-width: 1024px) {
.mt-intro {flex-direction:column;gap:48px;padding:60px 0 80px;}
.mt-intro__left {flex:none;width:100%;}
+ .mt-ops {max-width:420px;}
.mt-services__grid {grid-template-columns:repeat(3,1fr);}
.mt-service-card:nth-child(3) {border-right:none;}
.mt-service-card:nth-child(4), .mt-service-card:nth-child(5) {border-top:1px solid var(--color-primary-soft-border);}
@@ -1110,7 +1096,7 @@ body{overflow-x:hidden;}
@media (max-width: 768px) {
.mt-intro {padding:48px 0 64px;}
- .mt-intro__title {font-size:clamp(22px,6vw,30px);}
+ .mt-ops {max-width:340px;}
.mt-services__grid {grid-template-columns:repeat(2,1fr);}
.mt-service-card:nth-child(2n) {border-right:none;}
.mt-service-card:nth-child(3) {border-right:1px solid var(--color-primary-soft-border);}
@@ -1124,5 +1110,4 @@ body{overflow-x:hidden;}
.mt-service-card {border-right:none !important;}
.mt-service-card:nth-child(n+2) {border-top:1px solid var(--color-primary-soft-border);}
.mt-service-card:nth-child(5) {grid-column:span 1;}
- .mt-kpi__grid {grid-template-columns:repeat(2,1fr);}
}
\ No newline at end of file
diff --git a/src/pages/business/MaintenancePage.jsx b/src/pages/business/MaintenancePage.jsx
index 9fbc2a8..a7d064d 100644
--- a/src/pages/business/MaintenancePage.jsx
+++ b/src/pages/business/MaintenancePage.jsx
@@ -1,5 +1,5 @@
-import { useRef, useState, useEffect } from "react";
-import { motion, useInView, animate } from "framer-motion";
+import { useRef } from "react";
+import { motion, useInView, useAnimationFrame } from "framer-motion";
import SubHero from "../../components/SubHero";
import useFadeIn from "../../hooks/useFadeIn";
@@ -15,58 +15,139 @@ const SERVICES = [
{
num: "01",
title: "모니터링",
- desc: "시스템 및 네트워크 상태를 24/7 실시간 모니터링",
+ desc: "시스템·네트워크·애플리케이션 전 계층을 24/7 실시간으로 감시하여 장애 발생 전 이상 징후를 선제적으로 포착합니다.",
img: "./images/mt_icon01.png",
},
{
num: "02",
title: "장애 대응",
- desc: "이상 감지 시 전문 인력이 신속하게 원인 분석 및 복구",
+ desc: "이상 감지 즉시 전담 엔지니어가 원인을 분석하고 신속하게 복구합니다. 단순 대응을 넘어 재발 방지까지 책임집니다.",
img: "./images/mt_icon02.png",
},
{
num: "03",
title: "보안 관리",
- desc: "취약점 점검 및 패치 관리로 안전한 시스템 운영",
+ desc: "정기 취약점 점검과 패치 관리로 외부 위협으로부터 시스템을 보호합니다. 안전한 운영 환경을 지속적으로 유지합니다.",
img: "./images/mt_icon03.png",
},
{
num: "04",
title: "기술 지원",
- desc: "운영 가이드, 문의 응대 및 기술 지원 제공",
+ desc: "운영 중 발생하는 기술적 문의에 신속히 응대하고, 가이드 및 교육을 통해 고객 역량 강화까지 지원합니다.",
img: "./images/mt_icon04.png",
},
{
num: "05",
title: "지속적 개선",
- desc: "정기 리포트 및 분석을 통한 지속적인 서비스 개선",
+ desc: "정기 리포트와 데이터 분석을 기반으로 서비스 품질을 꾸준히 높입니다. 운영 효율과 안정성을 함께 끌어올립니다.",
img: "./images/mt_icon05.png",
},
];
const KPI = [
- { value: 99.9, suffix: "%", label: "서비스 가용성", icon: "⏱" },
- { value: 24, suffix: "/7", label: "365일 실시간 운영", icon: "📡" },
- { value: 10, suffix: "m 24s", label: "평균 응답 시간", icon: "⚡" },
- { value: 100, suffix: "%", label: "SLA 준수율", icon: "✓" },
+ { value: "99.9%", label: "서비스 가용성" },
+ { value: "24/7", label: "365일 실시간 운영" },
+ { value: "10m 24s", label: "평균 응답 시간" },
+ { value: "100%", label: "SLA 준수율" },
];
-function CountUp({ target, suffix, inView }) {
- const [display, setDisplay] = useState(0);
- useEffect(() => {
- if (!inView) return;
- const controls = animate(0, target, {
- duration: 1.8,
- ease: "easeOut",
- onUpdate: (v) => setDisplay(Math.round(v * 10) / 10),
- });
- return controls.stop;
- }, [inView, target]);
+/* 아이콘 5개 위치 — 정오각형, 상단에서 시작 */
+const NODE_ANGLES = [-90, -18, 54, 126, 198];
+const CX = 320,
+ CY = 320,
+ R = 190,
+ ICON_R = 44;
+
+function OpsCircle({ inView }) {
return (
-
- {display}
- {suffix}
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* pulse 링 — CSS 애니메이션 */}
+
+
+
+ {/* 궤도 링 */}
+
+
+ {/* 연결선 아이콘 → 중심 */}
+ {NODE_ANGLES.map((deg, i) => {
+ const rad = (deg * Math.PI) / 180;
+ const ix = CX + R * Math.cos(rad);
+ const iy = CY + R * Math.sin(rad);
+ const mx = CX + 80 * Math.cos(rad);
+ const my = CY + 80 * Math.sin(rad);
+ return ;
+ })}
+
+ {/* 아이콘 노드 원 배경 */}
+ {NODE_ANGLES.map((deg, i) => {
+ const rad = (deg * Math.PI) / 180;
+ const ix = CX + R * Math.cos(rad);
+ const iy = CY + R * Math.sin(rad);
+ return ;
+ })}
+
+ {/* 아이콘 이미지 — SVG foreignObject */}
+ {NODE_ANGLES.map((deg, i) => {
+ const rad = (deg * Math.PI) / 180;
+ const ix = CX + R * Math.cos(rad);
+ const iy = CY + R * Math.sin(rad);
+ const size = 54;
+ return (
+
+
+
+ );
+ })}
+
+ {/* 아이콘 라벨 */}
+ {NODE_ANGLES.map((deg, i) => {
+ const rad = (deg * Math.PI) / 180;
+ const ix = CX + R * Math.cos(rad);
+ const iy = CY + R * Math.sin(rad);
+ const labelOffset = 58;
+ const lx = CX + (R + 68) * Math.cos(rad);
+ const ly = CY + (R + 68) * Math.sin(rad);
+ return (
+
+ {SERVICES[i].title}
+
+ );
+ })}
+
+
+ {/* OPS CENTER 중앙 — DOM 오버레이 */}
+
+ OPS
+ CENTER
+
+
);
}
@@ -74,11 +155,10 @@ function MaintenancePage() {
const ref = useFadeIn();
const introRef = useRef(null);
const kpiRef = useRef(null);
- const servicesRef = useRef(null);
+ const colsRef = useRef(null);
const introInView = useInView(introRef, { once: true, margin: "-80px" });
const kpiInView = useInView(kpiRef, { once: true, margin: "-80px" });
- const servicesInView = useInView(servicesRef, { once: true, margin: "-60px" });
- const [activeIdx, setActiveIdx] = useState(0);
+ const colsInView = useInView(colsRef, { once: true, margin: "-60px" });
return (
@@ -94,16 +174,15 @@ function MaintenancePage() {
- {/* ── 인트로 섹션 ── */}
+ {/* ── 인트로 ── */}
- {/* 좌측 */}
OUR SERVICE
- {["운영부터 개선까지", "전문적인 관리 서비스"].map((line, i) => (
+ {["운영·유지보수는", "서비스의 안정성을", "완성합니다"].map((line, i) => (
{line}
@@ -112,50 +191,22 @@ function MaintenancePage() {
))}
-
- 전문 엔지니어가 시스템 전반을 관리하고,
+
+ PAL Networks는 24/7 통합 모니터링과 체계적인 유지보수로
- 문제 발생 시 신속하게 대응하여 서비스 안정성을 유지합니다.
+ 시스템의 가용성과 안정성을 지속적으로 보장합니다.
-
+
서비스 자세히 보기
-
- {/* quote 카드 */}
-
- "
-
- 안정적인 운영은
-
- 지속 가능한 성장의
-
- 기반입니다.
-
- PAL Networks
-
- {/* 우측 서비스 리스트 */}
@@ -166,10 +217,7 @@ function MaintenancePage() {
{KPI.map((k, i) => (
- {k.icon}
-
-
-
+ {k.value}
{k.label}
))}
@@ -179,13 +227,10 @@ function MaintenancePage() {
{/* ── 5컬럼 서비스 ── */}
-
-
- SERVICE DETAIL
-
+
{SERVICES.map((svc, i) => (
-
+