/* ============================================================================
   effects.css · 전 페이지 인터랙션 (소유: 임무 E · 2026-09-09)
   짝: site/assets/js/effects.js · 로드: templates/partials/head.html 두 줄

   정본(실측 추출): 02_받은자료/effects.html
     이징     cubic-bezier(.22,1,.36,1) 하나로 통일. 다른 이징을 새로 만들지 않는다.
     등장     opacity .8s ease · transform .8s cubic-bezier(.22,1,.36,1)
              🔴 이 트리에서는 transform 축만 쓴다(페이드 제외). 사유·실측은 §2 주석.
     카드     transform .5s cubic-bezier(.22,1,.36,1), box-shadow .5s
     버튼     transform .25s ease, box-shadow .25s ease
     stagger  자식마다 60~80ms (여기서는 70ms · 최대 5칸)

   🔴 이 파일의 규율
   1) 다른 임무의 파일을 고치지 않는다. 여기 있는 선택자는 전부 「이미 있는 마크업」을 가리킬 뿐이고
      마크업에 클래스를 새로 박지 않는다. 런타임 클래스(.fx-in)는 effects.js 가 붙였다 뗀다.
   2) 애니메이션 속성은 transform · opacity 뿐이다. width·left·top·height 를 애니메이션하지 않는다
      (리플로우 0). 진행바도 width 가 아니라 scaleX 다.
   3) 🔴 초기 숨김을 두지 않는다. 요소의 기본 상태는 「보이는 상태」이고, 등장은 뷰포트에 들어오기
      직전에 JS 가 .fx-in 을 붙여 애니메이션(opacity 0 → 1)으로 재생한다. 그래서 JS 가 죽거나
      느리면 애니메이션만 없고 콘텐츠는 전부 보인다(백지 사고 구조적 차단). html.js-fx 는
      effects.js 가 붙이는 「모션 켜짐」 스위치이며, 이 스위치가 없으면 등장 규칙 자체가 죽는다.
   4) 색값을 새로 만들지 않는다. stage.css §1-1 토큰만 참조한다.
   5) 다른 파일이 나중에 실리는 자리(catalog.css · calc.css · internet.css 는 body 에서 실린다)에서는
      같은 (0,1,0)·(0,2,0) 로는 순서에 밀린다. 그래서 그런 선택자만 클래스를 두 번 써서
      (.el-tile.el-tile) 특정도를 한 칸 올린다. !important 는 reduced-motion 에서만 쓴다.
   6) 숫자 카운트업은 쓰지 않는다(불변 규칙 1 · 금액 슬롯 중간 프레임 사고). 타이핑·heroZoom 도 뺐다.

   목차: 1 모션 토큰  2 등장(reveal)  3 순차 등장  4 카드 호버  5 버튼 호버·프레스
         6 스크롤 진행바 폴백  7 주 CTA 강조  8 reduced-motion
   ========================================================================== */


/* 1. 모션 토큰 ------------------------------------------------------------- */
/* 색 토큰은 stage.css §1-1 이 정본이다. 여기서는 모션 값만 만든다(--fx-*). */
:root{
  --fx-ease:cubic-bezier(.22,1,.36,1);   /* 참고 페이지의 유일한 이징 */
  --fx-rise:12px;                        /* 아래에서 올라오는 거리 (지시 8~16px 범위) */
  --fx-in:.8s;                           /* 등장 */
  --fx-card:.5s;                         /* 카드 호버 */
  --fx-btn:.25s;                         /* 버튼 호버 */
  --fx-press:.12s;                       /* 눌림은 짧게 — 손끝 반응은 즉답이어야 한다 */
}


/* 2. 등장 (스크롤 진입) ---------------------------------------------------- */
/* 아래에서 12px 올라온다. 재생이 끝나면 effects.js 가 .fx-in 을 떼고, 요소는 원래
   (=보이는) 상태로 돌아간다.
   🔴 클래스를 떼는 이유: fill:both 가 계속 남으면 transform:none 이 굳어 카드의 :hover
      들뜸(translateY)까지 눌러 버린다.

   🔴 페이드(opacity 0 → 1)를 뺐다. 정본 규격은 `opacity .8s ease` 를 함께 걸지만,
      이 트리에서는 못 쓴다 — 근거는 추측이 아니라 실측이다.
        · render-contrast 는 브라우저가 계산한 색으로 대비를 잰다. 요소를 깨울 때
          전 페이지를 훑어 내린 뒤 **350ms** 만 기다리고 측정한다(tools/render-contrast.mjs
          wakeJs). 0.8s 페이드는 그 시점에 아직 도는 중이다.
        · 그래서 페이드를 넣은 판으로 돌렸더니 🔴 미달 33건이 났다
          (예: span.el-tile__label 1.09:1 · p.ajd-card__d 1.66:1 · .form-card 안 폼 19건).
          반투명한 순간의 글자를 게이트가 정직하게 잡아낸 것이다.
        · 대비를 지키면서 페이드를 남기려면 최저 opacity 를 0.95 부근까지 올려야 하는데,
          그건 페이드가 아니다. 게이트를 낮추는 선택지는 없다(불변 규칙 7).
      👉 등장은 transform 한 축(올라오기)만 쓴다. 이러면 글자는 언제나 최종 색이라
         게이트가 흔들리지 않고, 「애니메이션은 transform·opacity 만」도 더 좁게 지켜진다.
      되살리려면 게이트의 대기 시간이 애니메이션보다 길어져야 한다 — render-contrast.mjs 는
      다른 소유라 여기서 고치지 않았다(통합자 판단 사항). */
@keyframes fxRise{ from{transform:translate3d(0,var(--fx-rise),0)} to{transform:none} }

html.js-fx .fx-in{
  animation:fxRise var(--fx-in) var(--fx-ease) both;
  animation-delay:var(--fx-d,0ms);
}


/* 3. 순차 등장(stagger) ---------------------------------------------------- */
/* 지연값은 effects.js 가 --fx-d 인라인 커스텀 속성으로 넣는다(같은 부모의 형제 순번 × 70ms).
   CSS 에 n번째 자식 규칙을 박아 두지 않는 이유는, 그리드 자식 수가 페이지마다 다르고
   목록이 데이터에서 오기 때문이다. */


/* 4. 카드 호버 ------------------------------------------------------------- */
/* 이미 들뜸이 있는 카드(.rg-tile · .rg-router__link — home.css 소유)는 건드리지 않는다.
   2026-09-22 홈 퀵 구획(#quick)을 걷어 .ajd-quick__link 를 이 목록 · 아래 reduced-motion 목록에서 뺐다(쓰는 화면 0).
   여기 있는 것은 호버 반응이 아예 없던 카드들이다. 들뜸은 -3px 로 지시(-4px 이내)를 지킨다.
   그림자는 stage.css 토큰 --cs-shadow-card 를 그대로 쓴다(새 그림자 신설 0). */
.ajd-service.ajd-service,
.el-tile.el-tile,
.el-banner.el-banner,
.pcard__link.pcard__link{
  transition:transform var(--fx-card) var(--fx-ease),box-shadow var(--fx-card),border-color var(--fx-btn) ease,background-color var(--fx-btn) ease;
}
@media (hover:hover){
  .ajd-service.ajd-service:hover,
  .el-tile.el-tile:hover,
  .el-banner.el-banner:hover,
  .pcard__link.pcard__link:hover{
    transform:translateY(-3px);
    box-shadow:var(--cs-shadow-card);
  }
}
.ajd-service.ajd-service:active,
.el-tile.el-tile:active,
.el-banner.el-banner:active,
.pcard__link.pcard__link:active{
  transform:translateY(0) scale(.995);
  transition-duration:var(--fx-press);
}


/* 5. 버튼 호버 · 프레스 ---------------------------------------------------- */
/* .btn 은 stage.css 가 이미 8상태를 다 갖고 있다(hover -1px · active scale .97 ·
   ::after 그림자). 두 번 칠하지 않는다. 여기서는 반응이 없던 두 부품만 채운다. */
.ajd-contact__btn.ajd-contact__btn,
.rg-btn.rg-btn{
  transition:transform var(--fx-btn) ease,box-shadow var(--fx-btn) ease,background-color var(--fx-btn) ease,opacity var(--fx-btn) ease;
}
@media (hover:hover){
  .ajd-contact__btn.ajd-contact__btn:hover,
  .rg-btn.rg-btn:hover{ transform:translateY(-2px); box-shadow:var(--cs-shadow-hover) }
}
.ajd-contact__btn.ajd-contact__btn:active,
.rg-btn.rg-btn:active{ transform:translateY(0) scale(.98); box-shadow:none; transition-duration:var(--fx-press) }


/* 6. 스크롤 진행바 폴백 ---------------------------------------------------- */
/* 정본은 stage.css .scroll-progress + stage.js initScrollProgress 다. 그런데 그 요소가
   없는 템플릿이 있다(internet.html · internet-carrier.html — 다른 임무 소유라 손대지 않는다).
   그 페이지에서만 effects.js 가 이 막대를 만들어 붙인다. 모양·높이·z-index 는 정본과 같은 값이다.
   폭이 아니라 scaleX 로 움직인다(리플로우 0). */
.fx-progress{
  position:fixed; top:0; left:0; z-index:60;
  height:3px; width:100%;
  transform:scaleX(0); transform-origin:left center;
  background:var(--fg-brand);
  pointer-events:none;
}


/* 7. 주 CTA 강조 ----------------------------------------------------------- */
/* 🔴 한 곳만 쓴다. 홈 마지막 문의 버튼(.ajd-contact__btn) 이다 — 페이지당 1개, 사이트 전체 1개.
   참고 페이지의 ctaPulse 는 box-shadow 를 애니메이션했는데, 그건 매 프레임 리페인트다.
   같은 인상을 transform·opacity 만으로 다시 그렸다: 테두리 링 하나가 커지며 사라진다.
   글자 위를 덮는 오버레이가 아니라 바깥으로 퍼지는 링이라 대비를 낮추지 않는다.
   position:relative 를 새로 얹지만 이 버튼의 자손은 텍스트뿐이다(불변 규칙 6 확인). */
@keyframes fxCtaRing{
  0%{ opacity:.55; transform:scale(1) }
  70%{ opacity:0; transform:scale(1.07) }
  100%{ opacity:0; transform:scale(1.07) }
}
.ajd-contact__btn{ position:relative }
.ajd-contact__btn::after{
  content:""; position:absolute; inset:-2px;
  border:2px solid var(--border-brand); border-radius:inherit;
  pointer-events:none; opacity:0;
  animation:fxCtaRing 2.6s var(--fx-ease) infinite;
}


/* 8. reduced-motion -------------------------------------------------------- */
/* 🔴 전부 끈다. 등장은 즉시 최종 상태로(요소의 기본 상태가 이미 최종 상태이므로 animation:none
   하나면 끝이다 — 초기 숨김이 없어서 「꺼짐 = 보임」이 저절로 성립한다).
   위 4·5 절이 (0,3,0) 이라 여기서도 같은 특정도 + !important 로 확실히 덮는다. */
@media (prefers-reduced-motion:reduce){
  html.js-fx .fx-in{ animation:none!important }
  .ajd-contact__btn::after{ animation:none!important; opacity:0!important }

  .ajd-service.ajd-service,
  .el-tile.el-tile,
  .el-banner.el-banner,
  .pcard__link.pcard__link,
  .ajd-contact__btn.ajd-contact__btn,
  .rg-btn.rg-btn{ transition:none!important }

  .ajd-service.ajd-service:hover,   .ajd-service.ajd-service:active,
  .el-tile.el-tile:hover,           .el-tile.el-tile:active,
  .el-banner.el-banner:hover,       .el-banner.el-banner:active,
  .pcard__link.pcard__link:hover,   .pcard__link.pcard__link:active,
  .ajd-contact__btn.ajd-contact__btn:hover, .ajd-contact__btn.ajd-contact__btn:active,
  .rg-btn.rg-btn:hover,             .rg-btn.rg-btn:active{ transform:none!important }
}
