// ═══════════════════════════════════════════════════════════════════════════ // 3ES INTERACTIONS — 은은한 AI 반응형 인터랙션 레이어 // 기존 마크업을 수정하지 않고 위임(delegation) 방식으로 동작합니다. // prefers-reduced-motion / (hover:none) / 저사양 환경에서 자동 비활성화. // ═══════════════════════════════════════════════════════════════════════════ // ── 테마 데이터 (단일 소스) ──────────────────────────────────────────────── const THEMES = { about: { primary:'#6366F1', glow:'rgba(99,102,241,0.16)' }, // 인디고 solutions: { primary:'#06B6D4', glow:'rgba(6,182,212,0.15)' }, // 사이언 partner: { primary:'#8B5CF6', glow:'rgba(139,92,246,0.15)' }, // 바이올렛 support: { primary:'#10B981', glow:'rgba(16,185,129,0.14)' }, // 그린/민트 news: { primary:'#818CF8', glow:'rgba(129,140,248,0.15)' }, // 블루-퍼플 contact: { primary:'#22D3EE', glow:'rgba(34,211,238,0.14)' }, }; // 솔루션 카테고리별 포인트 컬러 (무지개 띠가 아닌 카테고리 식별용) const CAT_THEMES = { email:'#06B6D4', spamout:'#2563EB', checkout:'#10B981', arch5:'#F59E0B', network:'#6366F1', sniper:'#F97316', genian:'#0EA5E9', edr:'#34D399', mdr:'#14B8A6', privacy:'#8B5CF6', system:'#2563EB', ai:'#0F9650', mailinsight:'#06B6D4', }; const interactionStyles = ` /* ══════ 1. NAV — 테마 글로우 + 라이트 바 ══════ */ .nav-link{--th:#06B6D4;--thg:rgba(6,182,212,0.15);isolation:isolate} .nav-link::before{ content:'';position:absolute;inset:-6px -10px;border-radius:10px;z-index:-1; background:radial-gradient(120px circle at var(--mx,50%) var(--my,50%),var(--thg),transparent 70%); opacity:0;transition:opacity .38s cubic-bezier(.2,.7,.3,1);pointer-events:none; } .nav-link::after{ content:'';position:absolute;left:14px;right:14px;bottom:3px;height:1px;border-radius:1px; background:currentColor; transform:scaleX(0);transform-origin:center;opacity:0; transition:transform .3s cubic-bezier(.2,.7,.3,1),opacity .25s ease;pointer-events:none; } .nav-link:focus-visible{outline:2px solid var(--th);outline-offset:3px;border-radius:8px} @media (hover:hover){ .nav-link:hover::before{opacity:1} .nav-link:hover::after{transform:scaleX(1);opacity:.9} .nav-link:hover{color:#fff} } .nav-link:focus-visible::after{transform:scaleX(1);opacity:.9} .nav-link.active{color:#fff} .nav-link.active::after{transform:scaleX(1);opacity:.55} /* ══════ 2. 솔루션 메가 메뉴 — 카테고리 반응 ══════ */ .nav-sub{--dim:0} .nav-sub-item,.nav-sub-group{position:relative;isolation:isolate;transition:background .22s ease,opacity .26s ease,color .22s ease} .nav-sub-item::before{ content:'';position:absolute;inset:0;border-radius:7px;z-index:-1; background:radial-gradient(90px circle at 20% 50%,var(--cg,rgba(6,182,212,.14)),transparent 70%); opacity:0;transition:opacity .3s ease;pointer-events:none; } @media (hover:hover){ .nav-sub:hover .nav-sub-item:not(:hover){opacity:.52} .nav-sub-item:hover::before{opacity:1} .nav-sub-item:hover{color:#fff} /* 데이터 흐름 라이트 라인 */ .nav-sub-item:hover::after{ content:'';position:absolute;left:0;right:0;bottom:0;height:1px; background:linear-gradient(90deg,transparent,var(--cd,#06B6D4),transparent); opacity:.5;animation:flowLine .9s ease-out;pointer-events:none; } } @keyframes flowLine{from{transform:translateX(-60%);opacity:0}40%{opacity:.6}to{transform:translateX(60%);opacity:0}} .nav-sub-dot{transition:box-shadow .3s ease} .nav-sub-item:hover .nav-sub-dot{box-shadow:0 0 10px 1px var(--cd,#06B6D4)} /* ══════ 3. 마우스 추적 광원 (Hero / Nav) ══════ */ .ai-cursor-light{ position:absolute;inset:0;pointer-events:none;z-index:0; background:radial-gradient(380px circle at var(--gx,50%) var(--gy,40%),var(--gc,rgba(6,182,212,0.10)),transparent 42%); opacity:0;transition:opacity .5s ease,background-color .6s ease; will-change:opacity; } .ai-cursor-light.on{opacity:1} .hero{isolation:isolate} .hero > .hero-content{position:relative;z-index:1} .nav-wrap{isolation:isolate} /* ══════ 4. 카테고리 테마 연동 (문서 루트 변수) ══════ */ :root{--accent-live:#06B6D4;--accent-live-glow:rgba(6,182,212,0.15)} .theme-react{transition:border-color .6s ease,box-shadow .6s ease,color .6s ease} /* ══════ 5. AI 상태 배지 ══════ */ .ai-status{display:flex;flex-wrap:wrap;gap:8px 12px;margin-top:30px} .ai-status-item{ display:inline-flex;align-items:center;gap:7px;padding:5px 11px;border-radius:100px; background:rgba(255,255,255,0.045);border:1px solid rgba(255,255,255,0.09); font-size:12px;font-weight:500;color:rgba(255,255,255,0.72);letter-spacing:-0.1px; } .ai-status-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;position:relative} .ai-status-dot::after{ content:'';position:absolute;inset:-3px;border-radius:50%; background:inherit;opacity:.28;animation:softPulse 2.8s ease-in-out infinite; } @keyframes softPulse{0%,100%{transform:scale(.7);opacity:.28}50%{transform:scale(1.25);opacity:.05}} /* ══════ 6. 버튼 라이트 스윕 ══════ */ .btn-primary,.btn-outline,.btn-ghost,.btn-demo,.btn-cta-nav{position:relative;overflow:hidden;isolation:isolate} .btn-primary::after,.btn-outline::after,.btn-ghost::after,.btn-demo::after,.btn-cta-nav::after{ content:'';position:absolute;top:0;bottom:0;width:45%;left:-60%;z-index:0;pointer-events:none; background:linear-gradient(100deg,transparent,rgba(255,255,255,.16),transparent); transition:none; } @media (hover:hover){ .btn-primary:hover::after,.btn-outline:hover::after,.btn-ghost:hover::after,.btn-demo:hover::after,.btn-cta-nav:hover::after{ animation:sweep .62s cubic-bezier(.3,.7,.4,1) forwards; } .btn-primary:hover,.btn-demo:hover{box-shadow:0 8px 24px rgba(37,99,235,.34),0 0 0 1px rgba(34,211,238,.28)} .btn-ghost:hover,.btn-outline:hover{box-shadow:0 0 0 1px rgba(34,211,238,.3),0 6px 18px rgba(6,182,212,.12)} .btn-primary:hover svg,.btn-ghost:hover svg,.btn-demo:hover svg{transform:translateX(3px)} } @keyframes sweep{from{left:-60%}to{left:115%}} .btn-primary svg,.btn-ghost svg,.btn-demo svg{transition:transform .28s cubic-bezier(.2,.7,.3,1)} .btn-primary:active,.btn-outline:active,.btn-ghost:active,.btn-demo:active,.btn-cta-nav:active{transform:scale(.98);transition:transform .12s ease} /* ══════ 7. 카드 인터랙션 ══════ */ .sol-card,.value-card,.news-card,.ref-card{position:relative;isolation:isolate;transition:transform .3s cubic-bezier(.2,.7,.3,1),box-shadow .3s ease,border-color .3s ease} .sol-card::before,.value-card::before{ content:'';position:absolute;inset:0;border-radius:inherit;z-index:-1;pointer-events:none; background:radial-gradient(220px circle at var(--cx,50%) 0%,var(--cardglow,rgba(6,182,212,.09)),transparent 62%); opacity:0;transition:opacity .34s ease; } @media (hover:hover){ .sol-card:hover,.value-card:hover{transform:translateY(-4px)} .sol-card:hover::before,.value-card:hover::before{opacity:1} .news-card:hover,.ref-card:hover{transform:translateY(-3px)} .sol-card:hover .sol-icon{box-shadow:0 0 22px -4px var(--carddot,rgba(6,182,212,.5))} } .sol-icon{transition:box-shadow .34s ease} /* ══════ 8. AI 개발(맞춤 솔루션) 섹션 그라디언트 ══════ */ .custom-section{position:relative;overflow:hidden} .custom-section::before{ content:'';position:absolute;inset:-20%;z-index:0;pointer-events:none;opacity:.5; background: radial-gradient(38% 45% at 18% 26%,rgba(245,158,11,.13),transparent 62%), radial-gradient(36% 42% at 76% 30%,rgba(236,72,153,.11),transparent 62%), radial-gradient(42% 48% at 46% 78%,rgba(139,92,246,.13),transparent 62%), radial-gradient(36% 40% at 88% 74%,rgba(6,182,212,.10),transparent 62%); animation:meshDrift 26s ease-in-out infinite alternate; will-change:transform; } .custom-section > *{position:relative;z-index:1} @keyframes meshDrift{ 0%{transform:translate3d(0,0,0) scale(1)} 50%{transform:translate3d(2.5%,-2%,0) scale(1.05)} 100%{transform:translate3d(-2%,2.5%,0) scale(1.02)} } .ai-gradient-text{ background:linear-gradient(110deg,#F59E0B,#EC4899,#8B5CF6,#06B6D4,#F59E0B); background-size:280% 100%;-webkit-background-clip:text;background-clip:text; -webkit-text-fill-color:transparent;color:transparent; animation:gradShift 11s linear infinite; } @keyframes gradShift{to{background-position:280% 0}} /* ══════ 9. 문의 완료 파동 ══════ */ .lead-done-ring{position:relative;display:inline-flex;align-items:center;justify-content:center} .lead-done-ring::after{ content:'';position:absolute;inset:0;border-radius:50%;border:1.5px solid rgba(34,211,238,.6); animation:doneRing .9s cubic-bezier(.2,.7,.3,1) forwards;pointer-events:none; } @keyframes doneRing{from{transform:scale(.6);opacity:.9}to{transform:scale(2.1);opacity:0}} /* ══════ 10. 모바일 / 터치 — 효과 단순화 ══════ */ @media (hover:none){ .ai-cursor-light{display:none!important} .nav-link::before{display:none} .custom-section::before{animation:none;opacity:.35} .sol-card::before,.value-card::before{display:none} .btn-primary::after,.btn-outline::after,.btn-ghost::after,.btn-demo::after,.btn-cta-nav::after{display:none} .sol-card:active,.value-card:active,.news-card:active{transform:scale(.995);border-color:var(--carddot,#2563EB)} .nav-sub-item:active{background:rgba(255,255,255,.09)} } /* ══════ 11. 접근성 — 모션 최소화 ══════ */ @media (prefers-reduced-motion:reduce){ .ai-cursor-light{display:none!important} .ai-status-dot::after,.custom-section::before,.ai-gradient-text,.lead-done-ring::after{animation:none!important} .ai-gradient-text{-webkit-text-fill-color:#A78BFA;color:#A78BFA;background:none} .nav-link::after{transition:none} .sol-card,.value-card,.news-card,.ref-card{transition:border-color .2s ease} .sol-card:hover,.value-card:hover,.news-card:hover,.ref-card:hover{transform:none} .btn-primary::after,.btn-outline::after,.btn-ghost::after,.btn-demo::after,.btn-cta-nav::after{display:none} } /* 저사양 기기 */ body.low-power .ai-cursor-light{display:none!important} body.low-power .custom-section::before{animation:none;opacity:.3} /* ══════ 12. NAV 상단 AI 라이트 스트립 ══════ */ .nav-wrap::before{ content:'';position:absolute;top:0;left:18px;right:18px;height:1.5px;z-index:2; pointer-events:none;border-radius:inherit; background:linear-gradient(90deg, rgba(45,212,191,.42),rgba(14,165,233,.40),rgba(59,130,246,.36),rgba(139,92,246,.38),rgba(45,212,191,.42)); background-size:220% 100%;background-position:0% 0; opacity:.5; box-shadow:0 0 6px -1px rgba(56,189,248,.28); transition:opacity .6s ease; } @media (hover:hover){ .nav-wrap:hover::before{opacity:.82;animation:navStripFlow 14s linear infinite} } @keyframes navStripFlow{to{background-position:220% 0}} /* 메뉴 hover 시 해당 구간만 미세 강조 */ .nav-wrap::after{ content:'';position:absolute;top:0;height:1.5px;width:150px;z-index:3;pointer-events:none; left:var(--sx,50%);transform:translateX(-50%); background:radial-gradient(60px 2px at 50% 50%,var(--sc,rgba(56,189,248,.85)),transparent 72%); opacity:0;transition:opacity .42s ease,left .5s cubic-bezier(.2,.7,.3,1); } @media (hover:hover){ .nav-wrap.strip-on::after{opacity:.9} } /* ══════ 13. HERO — AI 보안 데이터 물결 ══════ */ .hero-ai-wave,.hero-ai-streak,.hero-ai-flash{position:absolute;inset:0;pointer-events:none;z-index:0} .hero-ai-wave{ overflow:hidden; background: radial-gradient(58% 44% at 22% 78%,rgba(45,212,191,.085),transparent 64%), radial-gradient(52% 40% at 78% 26%,rgba(99,102,241,.075),transparent 64%), radial-gradient(46% 34% at 50% 52%,rgba(59,130,246,.055),transparent 66%); filter:blur(34px); transform:translate3d(var(--pxw,0),var(--pyw,0),0); transition:transform 1.5s cubic-bezier(.16,.8,.24,1); animation:waveDrift 22s ease-in-out infinite alternate; will-change:transform; } @keyframes waveDrift{ 0%{background-position:0% 0%,0% 0%,0% 0%} 100%{background-position:6% -3%,-5% 4%,3% 2%} } .hero-ai-streak{ overflow:hidden;opacity:.5; transform:translate3d(var(--pxs,0),var(--pys,0),0); transition:transform 2.1s cubic-bezier(.16,.8,.24,1); } .hero-ai-streak::before,.hero-ai-streak::after{ content:'';position:absolute;left:-30%;right:-30%;height:1px; background:linear-gradient(90deg,transparent,rgba(103,232,249,.30),rgba(139,92,246,.22),transparent); filter:blur(.6px); } .hero-ai-streak::before{top:34%;transform:rotate(-3.2deg);animation:streakA 17s ease-in-out infinite alternate} .hero-ai-streak::after{top:63%;transform:rotate(2.4deg);animation:streakB 21s ease-in-out infinite alternate} @keyframes streakA{0%{transform:rotate(-3.2deg) translateX(-3%)}100%{transform:rotate(-3.2deg) translateX(3%)}} @keyframes streakB{0%{transform:rotate(2.4deg) translateX(2.5%)}100%{transform:rotate(2.4deg) translateX(-2.5%)}} /* 진입 시 1회 라이트 통과 */ .hero-ai-flash{overflow:hidden} .hero-ai-flash::before{ content:'';position:absolute;width:58%;top:-40%;bottom:-40%;left:-60%; background:linear-gradient(100deg,transparent,rgba(125,211,252,.085),rgba(167,139,250,.06),transparent); filter:blur(26px);transform:rotate(14deg); animation:heroWake 2.3s cubic-bezier(.32,.72,.3,1) .35s 1 both; } @keyframes heroWake{from{left:-60%;opacity:0}22%{opacity:1}to{left:118%;opacity:0}} /* 모바일 / 터치 — 단순화 */ @media (hover:none){ .nav-wrap::before{animation:none!important;opacity:.42} .nav-wrap::after{display:none} .hero-ai-streak,.hero-ai-flash{display:none} .hero-ai-wave{animation:none;filter:blur(28px);transform:none!important} } /* 모션 최소화 */ @media (prefers-reduced-motion:reduce){ .nav-wrap::before{animation:none!important;opacity:.4} .nav-wrap::after{display:none} .hero-ai-wave{animation:none!important;transform:none!important} .hero-ai-streak::before,.hero-ai-streak::after{animation:none!important} .hero-ai-flash{display:none} } /* ══════ 14. HERO — 호흡 글로우 · SVG 데이터 웨이브 ══════ */ .hero-ai-breath{ position:absolute;inset:0;pointer-events:none;z-index:0;overflow:hidden; background: radial-gradient(44% 40% at 12% 88%,rgba(45,212,191,.10),transparent 62%), radial-gradient(40% 36% at 90% 10%,rgba(139,92,246,.085),transparent 62%); filter:blur(46px); animation:breathe 12s ease-in-out infinite alternate; will-change:opacity,transform; } @keyframes breathe{ 0%{opacity:.55;transform:scale(1)} 100%{opacity:1;transform:scale(1.06)} } .hero-ai-svg{ position:absolute;inset:-8% -14%;pointer-events:none;z-index:0;overflow:hidden; opacity:.85; transform:translate3d(var(--pxg,0),var(--pyg,0),0); transition:transform 1.8s cubic-bezier(.16,.8,.24,1); } .hero-ai-svg svg{position:absolute;inset:0;width:100%;height:100%;display:block} .hero-ai-svg .wv{animation:svgDrift 22s ease-in-out infinite alternate;will-change:transform} .hero-ai-svg .wv2{animation:svgDrift2 26s ease-in-out infinite alternate;will-change:transform} .hero-ai-svg .nd{animation:nodeBreathe 9s ease-in-out infinite alternate} @keyframes svgDrift{0%{transform:translate3d(-1.6%,0,0)}100%{transform:translate3d(1.6%,-.8%,0)}} @keyframes svgDrift2{0%{transform:translate3d(1.4%,.6%,0)}100%{transform:translate3d(-1.4%,-.4%,0)}} @keyframes nodeBreathe{0%{opacity:.35}100%{opacity:.85}} @media (hover:none){ .hero-ai-breath{animation:none;opacity:.7;filter:blur(38px)} .hero-ai-svg{transform:none!important;opacity:.6} .hero-ai-svg .wv2{display:none} .hero-ai-svg .nd{animation:none;opacity:.45} } @media (prefers-reduced-motion:reduce){ .hero-ai-breath{animation:none!important;opacity:.7} .hero-ai-svg{transform:none!important} .hero-ai-svg .wv,.hero-ai-svg .wv2,.hero-ai-svg .nd{animation:none!important} } body.low-power .hero-ai-breath{animation:none} body.low-power .hero-ai-svg .wv2,body.low-power .hero-ai-svg .nd{display:none} body.low-power .hero-ai-streak,body.low-power .hero-ai-flash{display:none} body.low-power .hero-ai-wave{animation:none} /* ══════ 15. HERO INTRO — AI 시스템 부팅 시퀀스 (≤2s, 1회) ══════ */ /* 0.0s 배경만 · 어둡게 시작 → 0.8s 정상 밝기 */ body.hero-intro .hero::after{ content:'';position:absolute;inset:0;z-index:2;pointer-events:none; background:rgba(4,8,20,.55); animation:introDim 2.1s cubic-bezier(.32,.72,.3,1) both; } @keyframes introDim{0%{opacity:1}24%{opacity:1}72%{opacity:.34}100%{opacity:0}} /* 0.2s 에너지 물결 1회 통과 (좌하 → 우상) */ body.hero-intro .hero-ai-flash::before{ animation:introSweep 1.55s cubic-bezier(.34,.7,.28,1) .5s 1 both; } @keyframes introSweep{ 0%{left:-70%;top:20%;opacity:0} 18%{opacity:1} 100%{left:120%;top:-45%;opacity:0} } /* 배경 레이어 자체도 부드럽게 살아남 */ body.hero-intro .hero-ai-breath, body.hero-intro .hero-ai-svg, body.hero-intro .hero-ai-wave{animation-delay:.9s} body.hero-intro .hero-ai-svg{animation:introFadeBg 1.6s ease-out .6s both} @keyframes introFadeBg{from{opacity:0}to{opacity:.85}} /* 1.0s 배지 → 1.2s 제목 → 1.5s 본문 → 1.7s CTA → 1.9s 상태 */ body.hero-intro .hero-badge{animation:introRise .66s cubic-bezier(.2,.75,.28,1) 2s both} body.hero-intro .hero-title{animation:introRise .74s cubic-bezier(.2,.75,.28,1) 2.12s both} body.hero-intro .hero-title-accent{display:inline-block;animation:introRise .74s cubic-bezier(.2,.75,.28,1) 2.24s both} body.hero-intro .hero-sub{animation:introRise .68s cubic-bezier(.2,.75,.28,1) 2.38s both} body.hero-intro .hero-ctas > *{animation:introPop .58s cubic-bezier(.2,.75,.28,1) both} body.hero-intro .hero-ctas > *:nth-child(1){animation-delay:2.52s} body.hero-intro .hero-ctas > *:nth-child(2){animation-delay:2.62s} body.hero-intro .hero-ctas > *:nth-child(3){animation-delay:2.72s} body.hero-intro .hero-ctas > *:nth-child(4){animation-delay:2.82s} body.hero-intro .ai-status-item{animation:introRise .5s cubic-bezier(.2,.75,.28,1) both} body.hero-intro .ai-status-item:nth-child(1){animation-delay:2.88s} body.hero-intro .ai-status-item:nth-child(2){animation-delay:2.98s} body.hero-intro .ai-status-item:nth-child(3){animation-delay:3.08s} body.hero-intro .ai-status-item:nth-child(4){animation-delay:3.08s} body.hero-intro .hero-stats{animation:introRise .6s cubic-bezier(.2,.75,.28,1) 3.02s both} body.hero-intro .hero-visual{animation:introVisual 1.2s cubic-bezier(.2,.75,.28,1) 2.1s both} /* 상단 메뉴 fade */ body.hero-intro .nav-wrap{animation:introFade 1s ease-out 1.9s both} @keyframes introUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:none}} @keyframes introRise{from{opacity:0;transform:translateY(20px) scale(.98)}to{opacity:1;transform:none}} @keyframes introPop{from{opacity:0;transform:translateY(12px) scale(.97)}to{opacity:1;transform:none}} @keyframes introFade{from{opacity:0}to{opacity:1}} @keyframes introVisual{from{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}} /* 모바일 — 약 40% 단순화 (전체 1.2s 내 완료) */ @media (hover:none){ body.hero-intro .hero::after{animation-duration:1.1s} body.hero-intro .hero-ai-flash::before{animation-duration:1s;animation-delay:.25s} body.hero-intro .hero-badge{animation-delay:1.05s} body.hero-intro .hero-title{animation-delay:1.16s} body.hero-intro .hero-title-accent{animation:none} body.hero-intro .hero-sub{animation-delay:1.3s} body.hero-intro .hero-ctas > *{animation-delay:1.42s!important;animation-duration:.42s} body.hero-intro .ai-status-item{animation-delay:1.54s!important;animation-duration:.4s} body.hero-intro .hero-stats{animation-delay:1.6s} body.hero-intro .nav-wrap{animation-delay:1s;animation-duration:.6s} } /* 모션 최소화 — 인트로 전면 비활성 */ @media (prefers-reduced-motion:reduce){ body.hero-intro .hero::after, body.hero-intro .hero-ai-flash::before{animation:none!important;display:none} body.hero-intro .hero-badge,body.hero-intro .hero-title,body.hero-intro .hero-title-accent, body.hero-intro .hero-sub,body.hero-intro .hero-ctas > *,body.hero-intro .ai-status-item, body.hero-intro .hero-stats,body.hero-intro .hero-visual,body.hero-intro .nav-wrap, body.hero-intro .hero-ai-svg{animation:none!important;opacity:1!important;transform:none!important} } body.low-power.hero-intro .hero::after{animation-duration:.6s} `; // ── 런타임: 마우스 추적 · 테마 적용 ──────────────────────────────────────── function initInteractions() { if (window.__3esInteractions) return; window.__3esInteractions = true; const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; const noHover = window.matchMedia('(hover: none)').matches; const lowPower = (navigator.hardwareConcurrency || 4) <= 2 || (navigator.deviceMemory || 4) <= 2; if (lowPower) document.body.classList.add('low-power'); // HERO INTRO — 세션 내 최초 진입 1회만 실행 if (!sessionStorage.getItem('3es_intro_done')) { document.body.classList.add('hero-intro'); sessionStorage.setItem('3es_intro_done', '1'); setTimeout(() => document.body.classList.remove('hero-intro'), 4400); } const enableLight = !reduce && !noHover && !lowPower; // 1) nav-link 테마 변수 주입 + 마우스 좌표 const applyNavThemes = () => { document.querySelectorAll('.nav-link[data-theme]').forEach(el => { const th = THEMES[el.dataset.theme] || THEMES.solutions; el.style.setProperty('--th', th.primary); el.style.setProperty('--thg', th.glow); }); // 서브메뉴 카테고리 컬러 (dot 색을 그대로 사용) document.querySelectorAll('.nav-sub-item').forEach(el => { const dot = el.querySelector('.nav-sub-dot'); const c = dot && getComputedStyle(dot).backgroundColor; if (c && c !== 'rgba(0, 0, 0, 0)') { el.style.setProperty('--cd', c); el.style.setProperty('--cg', c.replace('rgb(', 'rgba(').replace(')', ', 0.16)')); } }); // 솔루션 카드 컬러 (아이콘 배경에서 추출) document.querySelectorAll('.sol-card').forEach(el => { const ic = el.querySelector('.sol-icon'); const c = ic && getComputedStyle(ic).backgroundColor; if (c && c !== 'rgba(0, 0, 0, 0)') { el.style.setProperty('--cardglow', c); const solid = getComputedStyle(ic.querySelector('span') || ic).color; if (solid) el.style.setProperty('--carddot', solid); } }); }; applyNavThemes(); const mo = new MutationObserver(() => { clearTimeout(mo._t); mo._t = setTimeout(applyNavThemes, 120); }); mo.observe(document.getElementById('root') || document.body, { childList: true, subtree: true }); if (!enableLight) return; // 1.5) HERO 배경 레이어 마운트 (마크업 수정 없이 주입) const mountHeroLayers = () => { const hero = document.querySelector('.hero'); if (!hero || hero.querySelector(':scope > .hero-ai-wave')) return; ['hero-ai-breath','hero-ai-wave','hero-ai-streak','hero-ai-flash'].forEach(cls => { const el = document.createElement('div'); el.className = cls; el.setAttribute('aria-hidden','true'); hero.prepend(el); }); // SVG 데이터 웨이브 (곡선 + 네트워크 노드) const svgHost = document.createElement('div'); svgHost.className = 'hero-ai-svg'; svgHost.setAttribute('aria-hidden','true'); svgHost.innerHTML = [ '', ].join(''); hero.prepend(svgHost); }; mountHeroLayers(); const heroMo = new MutationObserver(() => { clearTimeout(heroMo._t); heroMo._t = setTimeout(mountHeroLayers, 100); }); heroMo.observe(document.getElementById('root') || document.body, { childList:true, subtree:true }); // 2) 마우스 추적 광원 — hero + nav let raf = 0, pending = null; const mount = (host, color) => { if (host.querySelector(':scope > .ai-cursor-light')) return host.querySelector(':scope > .ai-cursor-light'); const layer = document.createElement('div'); layer.className = 'ai-cursor-light'; layer.style.setProperty('--gc', color); host.prepend(layer); return layer; }; const onMove = e => { pending = e; if (raf) return; raf = requestAnimationFrame(() => { raf = 0; const ev = pending; pending = null; if (!ev) return; // hero const hero = document.querySelector('.hero'); if (hero) { const r = hero.getBoundingClientRect(); const inside = ev.clientY >= r.top && ev.clientY <= r.bottom; const layer = mount(hero, 'rgba(6,182,212,0.10)'); layer.classList.toggle('on', inside); if (inside) { layer.style.setProperty('--gx', `${ev.clientX - r.left}px`); layer.style.setProperty('--gy', `${ev.clientY - r.top}px`); } } // nav-link 로컬 좌표 const link = ev.target.closest && ev.target.closest('.nav-link'); if (link) { const lr = link.getBoundingClientRect(); link.style.setProperty('--mx', `${ev.clientX - lr.left}px`); link.style.setProperty('--my', `${ev.clientY - lr.top}px`); const th = THEMES[link.dataset.theme]; if (th) { document.documentElement.style.setProperty('--accent-live', th.primary); document.documentElement.style.setProperty('--accent-live-glow', th.glow); } } // nav 상단 스트립 — hover 위치 반응 const nav = document.querySelector('.nav-wrap'); if (nav) { const nr = nav.getBoundingClientRect(); const inNav = ev.clientY >= nr.top && ev.clientY <= nr.bottom; nav.classList.toggle('strip-on', inNav && !!link); if (inNav && link) { nav.style.setProperty('--sx', `${ev.clientX - nr.left}px`); const th = THEMES[link.dataset.theme]; if (th) nav.style.setProperty('--sc', th.primary); } } // hero 배경 parallax (3~8px, 지연 반응) const heroEl = document.querySelector('.hero'); if (heroEl) { const hr = heroEl.getBoundingClientRect(); if (ev.clientY >= hr.top && ev.clientY <= hr.bottom) { const nx = (ev.clientX - hr.left) / hr.width - .5; const ny = (ev.clientY - hr.top) / hr.height - .5; const w = heroEl.querySelector(':scope > .hero-ai-wave'); const st = heroEl.querySelector(':scope > .hero-ai-streak'); if (w) { w.style.setProperty('--pxw', `${(nx*8).toFixed(1)}px`); w.style.setProperty('--pyw', `${(ny*6).toFixed(1)}px`); } if (st) { st.style.setProperty('--pxs', `${(nx*-5).toFixed(1)}px`); st.style.setProperty('--pys', `${(ny*-4).toFixed(1)}px`); } const sv = heroEl.querySelector(':scope > .hero-ai-svg'); if (sv) { sv.style.setProperty('--pxg', `${(nx*6).toFixed(1)}px`); sv.style.setProperty('--pyg', `${(ny*4).toFixed(1)}px`); } } } // 카드 상단 글로우 x좌표 const card = ev.target.closest && ev.target.closest('.sol-card,.value-card'); if (card) { const cr = card.getBoundingClientRect(); card.style.setProperty('--cx', `${ev.clientX - cr.left}px`); } }); }; window.addEventListener('pointermove', onMove, { passive: true }); window.addEventListener('pagehide', () => { window.removeEventListener('pointermove', onMove); if (raf) cancelAnimationFrame(raf); mo.disconnect(); heroMo.disconnect(); }, { once: true }); } // ── AI 상태 배지 컴포넌트 ───────────────────────────────────────────────── const AiStatusBadge = ({ lang }) => { const isKo = lang === 'ko'; const items = isKo ? [ { t:'보안 컨설팅', c:'#22D3EE' }, { t:'구축 · 운영', c:'#10B981' }, { t:'기술지원', c:'#8B5CF6' }, ] : lang === 'ja' ? [ { t:'セキュリティ相談', c:'#22D3EE' }, { t:'構築・運用', c:'#10B981' }, { t:'技術サポート', c:'#8B5CF6' }, ] : [ { t:'Consulting', c:'#22D3EE' }, { t:'Deploy & operate', c:'#10B981' }, { t:'Technical support', c:'#8B5CF6' }, ]; return (