/* ─── Keyframes ──────────────────────────────────────── */ @keyframes blob { 0% { transform: translate3d(0, 0, 0) scale(1); } 33% { transform: translate3d(15px, -25px, 0) scale(1.05); } 66% { transform: translate3d(-10px, 10px, 0) scale(0.95); } 100% { transform: translate3d(0, 0, 0) scale(1); } } @keyframes blob-large { 0% { transform: translate3d(0, 0, 0) scale(1); } 33% { transform: translate3d(4vw, -4vh, 0) scale(1.05); } 66% { transform: translate3d(-4vw, 4vh, 0) scale(0.95); } 100% { transform: translate3d(0, 0, 0) scale(1); } } /* GPU-accelerate blob animations to prevent layout jitter */ .animate-blob, .animate-blob-large { will-change: transform; contain: layout style; backface-visibility: hidden; } .animate-blob-large { animation: blob-large 25s infinite ease-in-out; } .animation-delay-2000 { animation-delay: 2s; } .animation-delay-4000 { animation-delay: 4s; } .animation-delay-7000 { animation-delay: 7s; } .animation-delay-14000 { animation-delay: 14s; } /* ─── 글로벌 effect 클래스 (데모 호환) ─────────────────── */ .text-gradient { background: linear-gradient(to right, var(--brand-navy), #3b5998); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; color: transparent; } .glass-card { @apply bg-white/70 backdrop-blur-xl border border-white/40 shadow-[0_8px_32px_0_rgba(31,38,135,0.07)] rounded-2xl; } .gradient-bg { background: radial-gradient(circle at top left, #fdfbfb, #f3e7e9); @apply relative; } .gradient-bg::before { content: ""; @apply absolute inset-0 bg-white/30 backdrop-blur-[2px] pointer-events-none; } .soft-gradient { background: linear-gradient(145deg, #fdfbfb 0%, #ebedee 100%); } /* ─── Print / PDF (브라우저 네이티브 인쇄 → PDF) ──────────── useExportPDF 훅이 window.print()를 호출하면 이 규칙이 적용됨. 리포트/플랜 본문(data-report-content / data-plan-content)만 인쇄. */ @media print { @page { size: A4; margin: 15mm 10mm 10mm 10mm; } /* 브랜드 색·다크 섹션·그라데이션 그대로 유지 */ *, *::before, *::after { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; } html, body { background: #ffffff !important; margin: 0 !important; padding: 0 !important; } /* 인쇄에서 제외할 UI 요소 */ [data-no-print], [data-report-nav], [data-plan-nav], [data-cta-card], [data-radix-popper-content-wrapper], [role="menu"], [role="dialog"], [role="tooltip"], nav { display: none !important; } /* sticky/fixed 요소는 매 페이지마다 반복 인쇄되므로 정적으로 */ .sticky, .fixed { position: static !important; } /* 가로 스크롤 영역은 줄바꿈으로 펼쳐 모든 콘텐츠를 보이게 */ [data-report-content] .overflow-x-auto, [data-report-content] .overflow-x-scroll, [data-report-content] .scrollbar-thin, [data-plan-content] .overflow-x-auto, [data-plan-content] .overflow-x-scroll, [data-plan-content] .scrollbar-thin { overflow: visible !important; flex-wrap: wrap !important; } [data-report-content] .shrink-0, [data-plan-content] .shrink-0 { flex-shrink: 1 !important; min-width: 0 !important; } /* SectionWrapper의 화면용 py-16/md:py-20 (≈64-80px)은 인쇄에선 너무 큼 → 살짝만 압축. 좌우 padding(px-6)과 PageContainer의 max-w-7xl/px-6은 그대로 유지하여 가독성 보존. */ [data-report-content] section, [data-plan-content] section { padding-top: 10mm !important; padding-bottom: 10mm !important; } /* 화면의 sticky/fixed nav 오프셋용 상단 padding 제거 (인쇄에선 nav가 숨겨지므로 불필요) */ .pt-16, .pt-20, .pt-24, .pt-28, .pt-32 { padding-top: 0 !important; } /* ReportHeader/PlanHeader 등 첫 섹션 상단 — @page top margin (15mm) 외 약간의 여유 */ [data-report-content] > section:first-child, [data-plan-content] > section:first-child { padding-top: 4mm !important; } /* break-inside: avoid는 의도적으로 안 씀. KPI 표·로드맵·Transformation 칩 카드처럼 한 페이지보다 긴 요소가 통째로 다음 페이지로 밀려서 큰 빈 공간을 만들기 때문. 필요한 곳은 [data-print-keep] 명시 시 그 요소만 묶어주는 방식 사용. */ [data-print-keep] { break-inside: avoid; page-break-inside: avoid; } /* framer-motion whileInView 잔여 inline opacity 처리 (useExportPDF에서 JS로도 강제하지만 안전장치) */ [style*="opacity: 0"], [style*="opacity:0"] { opacity: 1 !important; } }