/* ==========================================================================
   Reset / Base
   ========================================================================== */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  overflow-x: hidden;
  scrollbar-gutter: stable;
}

/* 화면에는 안 보이지만 크롤러·스크린리더에는 읽히는 텍스트.
   display:none이나 visibility:hidden은 보조기술에서도 제외되므로
   clip 방식을 쓴다. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

body {
  font-family: 'Pretendard Variable', 'Pretendard', -apple-system, BlinkMacSystemFont,
    'Noto Sans KR', sans-serif;
  color: #1a1a1a;
  background: #fff;
}

/* ==========================================================================
   스크롤 등장 애니메이션 (Reveal)
   JS(initReveal)가 IntersectionObserver로 .is-in을 부여하면 나타난다.
   JS가 없거나 실패해도 .js-reveal 클래스가 없으면 항상 보이는 상태(안전 폴백).
   ========================================================================== */
.js-reveal [data-reveal] {
  opacity: 0;
  transform: translate3d(var(--rv-x, 0), var(--rv-y, 32px), 0) scale(var(--rv-s, 1));
  transition:
    opacity var(--rv-dur, 0.85s) cubic-bezier(0.22, 0.61, 0.36, 1) var(--rv-d, 0ms),
    transform var(--rv-dur, 0.85s) cubic-bezier(0.22, 0.61, 0.36, 1) var(--rv-d, 0ms);
  will-change: opacity, transform;
}

.js-reveal [data-reveal].is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

[data-reveal="up"]    { --rv-y: 40px; }
[data-reveal="rise"]  { --rv-y: 220px; --rv-dur: 1.8s; }
[data-reveal="left"]  { --rv-x: -40px; --rv-y: 0; }
[data-reveal="right"] { --rv-x: 40px; --rv-y: 0; }
[data-reveal="zoom"]  { --rv-y: 24px; --rv-s: 1.06; }
[data-reveal="fade"]  { --rv-y: 0; }

@media (prefers-reduced-motion: reduce) {
  .js-reveal [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

img {
  display: block;
  max-width: 100%;
}

a {
  text-decoration: none;
  color: inherit;
}

button {
  font-family: inherit;
  border: none;
  background: none;
  cursor: pointer;
}

/* ==========================================================================
   Section 1: Hero
   ========================================================================== */
.hero {
  position: relative;
  width: 100%;
  height: 100vh;
  min-height: 700px;
  overflow: hidden;
  background: #f0f0f0;
}

.hero__bg-wrap {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  /* Figma 993px 중 영상 950px : 하단 빈 공간 43px 비율(950/993 ≈ 95.67%).
     .hero는 pin 스크롤 메커니즘상 vh 기반 가변 높이라 993px로 고정할 수
     없어(pin 길이 계산과 얽힘), 대신 이 비율로 영상 영역을 줄이고 나머지를
     .hero의 배경색(#f0f0f0)이 비치는 고정 띠로 남긴다. */
  height: 95.67%;
  border-bottom-right-radius: min(200px, 15vw);
  overflow: hidden;
}

.hero__bg-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.hero__overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
}

.hero__header {
  position: absolute;
  top: 40px;
  left: 16.3vw;
  z-index: 5;
  will-change: opacity;
}

@media (min-width: 1920px) {
  .hero__header {
    left: 313px;
  }
}

.hero__logo {
  height: 45px;
  width: auto;
}

.hero__content {
  position: relative;
  z-index: 5;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  max-width: 1920px;
  margin: 0 auto;
  /* --hero-content-px를 padding과 .hero__text의 left/right(PC 전용
     absolute 배치)가 공유한다. absolute 자식의 containing block은 이
     요소의 padding box "바깥쪽 가장자리"까지다 — padding은 오직 일반
     흐름 자식에게만 영향을 주고, absolute 자식의 left:0/right:0은
     padding을 무시하고 그 가장자리(=border 안쪽, 사실상 padding 포함
     전체 폭)에 바로 붙는다. 그래서 값을 여기서 만들어 .hero__text에도
     그대로 넘겨야 실제로 같은 여백이 재현된다(실측으로 확정: right:0을
     썼을 때 텍스트가 뷰포트 끝까지 붙었었다). */
  --hero-content-px: 8.9vw;
  padding: 0 var(--hero-content-px);
}

@media (min-width: 1025px) {
  /* --hero-p: 히어로 pin 트랙(0~1) 스크롤 진행률. initHeroPinFx가 매 프레임 갱신한다.
     다음 막(뷰어)이 올라올수록 히어로 콘텐츠가 서서히 물러나며 사라진다. */
  .hero {
    --hero-p: 0;
  }

  .hero__content {
    opacity: calc(1 - var(--hero-p));
    transform: translateY(calc(var(--hero-p) * -60px));
  }

  .hero__bg-wrap {
    transform: scale(calc(1 + var(--hero-p) * 0.06));
  }
}

@media (min-width: 1025px) and (prefers-reduced-motion: reduce) {
  .hero__content,
  .hero__bg-wrap {
    opacity: 1 !important;
    transform: none !important;
  }
}

@media (min-width: 1920px) {
  .hero__content {
    --hero-content-px: 171px;
    padding: 0 var(--hero-content-px);
  }
}

.hero__text {
  display: none;
  flex-direction: column;
  gap: 20px;
  color: #fff;
  max-width: 865px;
}

.hero__text.is-active {
  display: flex;
}

.hero__text--right {
  align-items: flex-end;
  align-self: flex-end;
  text-align: right;
}

.hero__text--center {
  align-items: center;
  align-self: center;
  text-align: center;
  max-width: 1040px;
}

.hero__text--left {
  align-items: flex-start;
  align-self: flex-start;
  text-align: left;
  max-width: 1040px;
}

/* PC: display:none/flex 토글은 즉시 전환이라 "툭툭 튀는" 느낌을 준다.
   .viewer__panel과 동일한 크로스페이드 관용구(opacity+visibility, 항상
   display:flex로 겹쳐두고 opacity로 보이고/숨김)로 교체한다.
   position:absolute라 4개 텍스트가 같은 자리에 겹친다.

   ⚠️ left:0;right:0을 동시에 고정하고 max-width + margin:auto로 정렬하는
   첫 시도는 실제로 텍스트가 좌우 끝에 딱 붙는 버그를 냈다. left/right를
   둘 다 고정하면 width가 그 두 제약만으로 결정되어 over-constrained가
   되고, 이 상태에서 max-width가 적용될 때 남는 공간을 margin:auto가
   정확히 흡수하지 못하는 경우가 있었다(브라우저 계산 순서 문제로 보임).
   해결: left/right 중 정렬 방향에 맞는 쪽 "하나만" 고정한다 — 그러면
   width가 순수하게 auto가 되어 max-width가 항상 명확하게 적용된다.
   over-constrained 자체가 생기지 않으므로 margin:auto 트릭이 필요 없다. */
@media (min-width: 1025px) {
  .hero__text {
    display: flex;
    position: absolute;
    top: 50%;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    /* --hero-text-y: 0px = 순수 페이드(A안), 40px = 페이드+슬라이드(B안).
       이 값만 바꿔서 두 방식을 비교할 수 있다(사용자 요청: "두개를 다
       적용해줘봐 내가 비교 선택 할 수 있게"). 값을 올리면 새 텍스트가
       그만큼 아래에서 시작해 중앙으로 올라오며 페이드인하고, 사라지는
       텍스트는 중앙에서 그만큼 아래로 내려가며 페이드아웃한다(대칭).
       24px → 40px로 확대(사용자 요청: "더 확실하게") — 이동 자체가
       커지면 페이드와 별개로 슬라이드 움직임도 눈에 뚜렷해진다. */
    --hero-text-y: 40px;
    /* ⚠️ cubic-bezier(0.16,1,0.3,1)를 썼던 첫 시도는 실측(playwright로
       프레임별 opacity 샘플링)해보니 처음 100ms 안에 opacity가 이미
       0.63까지 뛰어올라(그 곡선은 초반 10~15%의 시간에 변화량의 상당
       부분이 몰리는 "급출발형" 곡선이다), 나머지 600ms 동안은 0.63→1.0
       사이 미세한 변화만 남아 눈에는 사실상 "즉시 나타난 뒤 안 변한다"로
       보였다 — 이게 "그냥 나타난다" 피드백의 실제 원인이었다.
       ease로 되돌려 변화량이 구간 전체에 고르게 분산되도록 한다.
       지속시간도 0.7s → 1.1s로 늘려 페이드가 더 오래, 더 확실하게
       보이도록 한다(사용자 요청: "더 확실하게"). 영상 구간 경계 간
       최소 간격(6.08s)보다 충분히 짧아 다음 전환과 겹치지 않는다. */
    transition: opacity 1.1s ease, transform 1.1s ease;
  }

  .hero__text.is-active {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }

  .hero__text--right {
    /* right:0이 아니라 부모 padding과 같은 값을 써야 한다 — absolute
       자식의 right:0은 부모 padding box의 "바깥쪽" 가장자리에 붙어서
       padding을 무시해버린다(실측 확인: right:0일 때 텍스트가 뷰포트
       끝까지 붙었다). --hero-content-px를 그대로 넣어 부모의
       padding-right와 정확히 같은 지점에 오도록 한다. */
    right: var(--hero-content-px);
    transform: translateY(calc(-50% + var(--hero-text-y)));
  }

  .hero__text--right.is-active {
    transform: translateY(-50%);
  }

  .hero__text--left {
    left: var(--hero-content-px);
    transform: translateY(calc(-50% + var(--hero-text-y)));
  }

  .hero__text--left.is-active {
    transform: translateY(-50%);
  }

  /* center만 좌우 어느 쪽에도 고정하지 않고 수평 중앙에 배치해야 하므로
     left:50% + translateX(-50%)로 앵커링한다 — 세로 이동(translateY)과
     함께 하나의 transform에 담아야 한다. */
  .hero__text--center {
    left: 50%;
    transform: translate(-50%, calc(-50% + var(--hero-text-y)));
  }

  .hero__text--center.is-active {
    transform: translate(-50%, -50%);
  }
}

@media (min-width: 1025px) and (prefers-reduced-motion: reduce) {
  .hero__text--right,
  .hero__text--right.is-active {
    transition: none !important;
    transform: translateY(-50%) !important;
  }

  .hero__text--left,
  .hero__text--left.is-active {
    transition: none !important;
    transform: translateY(-50%) !important;
  }

  .hero__text--center,
  .hero__text--center.is-active {
    transition: none !important;
    transform: translate(-50%, -50%) !important;
  }
}

.hero__title {
  font-weight: 700;
  font-size: clamp(32px, 4.6vw, 88px);
  line-height: 1.1;
  letter-spacing: -0.03em;
}

.hero__desc {
  font-weight: 400;
  font-size: clamp(15px, 1.7vw, 32px);
  line-height: 1.29;
  letter-spacing: -0.04em;
}

.hero__text--right .hero__desc {
  max-width: 609px;
}

.hero__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 10px;
  padding: 18px 40px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.6);
  color: #fff;
  font-size: 18px;
  font-weight: 500;
  transition: background 0.25s ease, color 0.25s ease;
}

.hero__btn:hover {
  background: #fff;
  color: #142b4f;
}

.hero__indicators {
  position: absolute;
  bottom: 60px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 10px;
}

.hero__dot {
  width: 12px;
  height: 8px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.3);
  transition: width 0.3s ease, background 0.3s ease;
}

.hero__dot.is-active {
  width: 31px;
  background: #fff;
}

@media (max-width: 768px) {
  .hero__content {
    align-items: center;
    justify-content: flex-end;
    text-align: center;
    padding: 0 24px;
    padding-bottom: 120px;
  }
  .hero__text,
  .hero__text.is-active {
    align-items: center;
  }
  .hero__header {
    left: 24px;
    top: 24px;
  }
  .hero__indicators {
    bottom: 32px;
  }
}

/* ==========================================================================
   Section 2: AI Multi Viewer
   공통 배경(장식 포함, 텍스트/콘텐츠 없는 순수 배경) 위에
   탭별 콘텐츠 비주얼(투명 PNG) + 실제 HTML 텍스트 + 실제 버튼(탭바)을 오버레이.
   좌표는 피그마 1920x993 절대좌표를 %로 환산해 .viewer__stage 안에 배치한다.
   (Figma Section 2 프레임이 1920x993 — 스크린샷 픽셀 실측으로 확인.
    가로는 /1920, 세로는 /993으로 나눈다.)
   ========================================================================== */
.viewer {
  position: relative;
  width: 100%;
  background: #f0f0f0;
  overflow: hidden;
}

.viewer__stage {
  position: relative;
  width: 100%;
  aspect-ratio: 1920 / 993;
  max-width: 1920px;
  margin: 0 auto;
  z-index: 2;
}

.viewer__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.viewer__bg.is-active {
  opacity: 1;
  z-index: 1;
}

.viewer__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.viewer__logo {
  position: absolute;
  left: 16.3%;
  top: 3.7%;
  height: 4.17%;
  width: auto;
  z-index: 5;
}

/* Figma: x=1579 y=17 w=141 h=46 (1920x993) */
.viewer__more {
  position: absolute;
  left: 82.24%;
  top: 1.71%;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 7.34%;
  height: 4.63%;
  border-radius: 60px;
  background: #fff;
  color: #1b1b1b;
  font-size: clamp(11px, 1.15vw, 22px);
  white-space: nowrap;
  transition: background 0.25s ease, color 0.25s ease;
}

.viewer__more:hover {
  background: #e6e6e6;
}

/* Figma: x=496 y=134 w=928 (1920x993) */
.viewer__title {
  position: absolute;
  left: 25.83%;
  top: 13.49%;
  width: 48.33%;
  height: auto;
  z-index: 3;
}

.viewer__panel {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 2;
}

.viewer__panel.is-active {
  display: block;
}

/* PC: 뷰어가 pin되어 스크롤로 패널이 전환되므로 display 토글 대신 크로스페이드로 부드럽게 전환한다. */
@media (min-width: 1025px) {
  .viewer__panel {
    display: block;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.5s ease;
    pointer-events: none;
  }

  .viewer__panel.is-active {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }
}

@media (min-width: 1025px) and (prefers-reduced-motion: reduce) {
  .viewer__panel {
    transition: none;
  }
}

/* Figma Frame 515: x=361 y=617 w=1199 h=120 (1920x993)
   제목 32px → 구분선(100x2, #82acbe) → 본문 22px, 전부 가운데 정렬. */
.viewer__panel-text {
  position: absolute;
  left: 18.80%;
  top: 62.13%;
  width: 62.45%;
  text-align: center;
  z-index: 3;
}

.viewer__panel-text h3 {
  font-size: clamp(16px, 1.67vw, 32px);
  font-weight: 700;
  color: #293553;
  margin-bottom: 14px;
  position: relative;
  display: inline-block;
  padding-bottom: 14px;
}

.viewer__panel-text h3::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 100px;
  max-width: 40%;
  height: 2px;
  background: #82acbe;
}

.viewer__panel-text p {
  font-size: clamp(11px, 1.15vw, 22px);
  color: #1b1b1b;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

/* 탭별 애니메이션(WebP, 1920x993 원본 해상도 = .viewer__stage와 동일 비율)이
   스테이지 전체를 채운다. once 1회 재생 후 loop로 전환하는 로직은
   main.js의 initViewerPanelAnimations()가 담당(src 교체 방식).

   object-fit: contain은 이미지(캔버스) 자체를 스테이지 세로 중앙에
   맞출 뿐인데, 프레임 안의 실제 그림은 캔버스 안에서 탭마다 다른
   위치에 그려져 있어(6개 탭 프레임을 alpha 기준 실측) 그대로 두면
   "타이틀~탭바 사이" 여백에서 탭마다 위/아래 균형이 들쭉날쭉했다.
   top(탭별 px값, index.html 인라인 스타일, 크롬 개발자도구에서 직접
   확인한 값)으로 그 여백의 중앙에 오도록 보정한다. 겹침 허용(사용자
   확정) — 이 보정을 적용하면 애니메이션 하단이 텍스트 영역과 겹치는
   탭이 있는데, .viewer__panel-text가 z-index 3(애니메이션은 2)이라
   텍스트가 항상 위에 깔끔하게 보인다. */
.viewer__panel-anim {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  z-index: 2;
}

/* Figma: 개별 탭 y=852.39 h=42, 첫 탭 x=405.5 ~ 마지막 탭 우측 1514.5
   (1920x993 기준). gap 29px = 1.51%. */
.viewer__tabs {
  position: absolute;
  left: 50%;
  top: 85.84%;
  transform: translateX(-50%);
  z-index: 5;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 1.51%;
  width: 100%;
  padding: 0 24px;
}

.viewer__tab {
  padding: 8px 23px;
  border-radius: 59px;
  background: rgba(255, 255, 255, 0.42);
  color: #333;
  font-size: clamp(13px, 1.15vw, 22px);
  line-height: 1.17;
  white-space: nowrap;
  transition: background 0.25s ease, color 0.25s ease;
}

.viewer__tab:hover {
  background: rgba(255, 255, 255, 0.75);
}

.viewer__tab.is-active {
  padding: 8px 14px;
  background: #004fb7;
  color: #fff;
  box-shadow: 0 4px 2px rgba(0, 0, 0, 0.25);
}

.viewer__tab.is-active:hover {
  background: #003d91;
}


@media (max-width: 640px) {
  .viewer__stage {
    aspect-ratio: auto;
    max-width: 100%;
    padding: 127px 24px 40px;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .viewer__logo,
  .viewer__more,
  .viewer__title {
    position: static;
    inset: auto;
  }

  .viewer__logo {
    height: 32px;
    align-self: flex-start;
    margin-bottom: 40px;
  }

  .viewer__more {
    order: 10;
    margin-top: 32px;
    padding: 8px 20px;
    border-radius: 40px;
    background: rgba(255, 255, 255, 0.49);
    backdrop-filter: blur(5px);
    color: #bcd6de;
    font-size: 15px;
    letter-spacing: -0.03em;
  }

  .viewer__title {
    width: min(85%, 320px);
    align-self: flex-start;
    margin-bottom: 44px;
  }

  .viewer__panel {
    position: static;
    display: none;
    width: 100%;
  }

  .viewer__panel.is-active {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .viewer__panel-anim {
    position: static;
    width: auto;
    max-width: min(80%, 320px);
    height: 260px;
    margin-bottom: 44px;
  }

  .viewer__panel-text {
    position: static;
    width: 100%;
    max-width: 460px;
  }

  .viewer__panel-text h3 {
    min-height: 34px;
  }

  .viewer__panel-text p {
    font-size: 15px;
    min-height: 76px;
  }

  .viewer__tabs {
    display: none;
  }

  .viewer__dots {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 32px;
  }

  .viewer__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(41, 53, 83, 0.25);
    transition: background 0.25s ease, width 0.25s ease;
  }

  .viewer__dot.is-active {
    width: 20px;
    border-radius: 4px;
    background: #004fb7;
  }
}

@media (min-width: 641px) {
  .viewer__dots {
    display: none;
  }
}

/* ==========================================================================
   Section 3: How We Work
   ========================================================================== */
.work {
  position: relative;
  width: 100%;
  background: #fff;
  border-top-left-radius: 0;
  padding: 0;
  /* overflow:hidden 대신 clip-path 사용 — Our Works 오버레이용 sticky 엔드캡
     (.work__endcap)이 이 안에 있는데, overflow:hidden 조상은 그 안의
     position:sticky를 조용히 죽인다. clip-path는 sticky에 영향을 주지 않으면서
     모서리 라운딩이 클리핑해야 하는 것(현재는 아무것도 없음, 실측 확인)을
     그대로 클리핑한다. */
  clip-path: inset(0 round 0);
  transition: border-top-left-radius 0.9s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.work.is-entered {
  border-top-left-radius: min(140px, 10.4vw);
  clip-path: inset(0 round min(140px, 10.4vw) 0 0 0);
}

@media (prefers-reduced-motion: reduce) {
  .work {
    border-top-left-radius: min(140px, 10.4vw);
    clip-path: inset(0 round min(140px, 10.4vw) 0 0 0);
    transition: none;
  }
}

.work__logo {
  display: block;
  height: 45px;
  width: auto;
  margin-left: 16.3vw;
  margin-bottom: 34px;
}

@media (min-width: 1920px) {
  .work__logo {
    margin-left: calc(50% - 647px);
  }
}

/* How We Work 본문(타이틀 + 카드 3개)만 한 화면(993 기준)을 차지한다.
   .work 섹션에는 아래에 What We Do(.work__what-wrap)도 함께 들어 있어
   섹션 자체에 높이를 주면 의미가 없다.
   Figma Section 3(1920x993): 타이틀 y=120, 카드 영역 y=320~856. */
.work__hero {
  min-height: 100svh;
  padding-top: 120px;
}

/* PC(1025px~): How We Work는 이제 pin(.pin__inner, height:100svh) 안에
   overflow:hidden으로 담긴다. 세로가 짧은 화면(노트북 등, 실사용 높이
   ~720px)에서는 콘텐츠(약 878px = padding-top 120 + 타이틀 94 + 여백 106 +
   카드 558)가 한 화면을 넘어 카드 아래쪽이 잘린다.
   대응: 연출(pin)을 끄는 대신 콘텐츠 자체를 뷰포트 높이(vh)에 비례해
   줄인다 — clamp(하한, N vh, Figma값)로, 여기서 N은 전부 "Figma값/1080*100"
   으로 통일해 세로가 줄어들수록 모든 치수가 같은 비율로 함께 작아지게 한다
   (하나만 줄고 나머지는 그대로면 비율이 깨진다). 100vh(=1080 기준)에서는
   정확히 Figma 원래 값이 나온다. */
@media (min-width: 1025px) {
  .work__hero {
    padding-top: clamp(60px, 11.1vh, 120px);   /* 120/1080*100 ≈ 11.1 */
  }
}

.work__title {
  text-align: center;
  font-weight: 600;
  font-size: clamp(32px, 4.17vw, 80px);
  line-height: 1.17;
  color: #1b1b1b;
  /* Figma: 타이틀 하단 214 → 카드 영역 시작 320 = 106px */
  margin-bottom: 106px;
}

/* .work__title은 How We Work/What We Do 공용 클래스라 여기서 바로
   margin-bottom을 vh로 바꾸면 두 섹션 다 영향을 받는다. pin 잘림 대응은
   How We Work 쪽에만 필요하므로 .work__hero로 스코프를 좁힌다
   (위 .work__hero 옆 주석 참고, 계수 산출 방식 동일). */
@media (min-width: 1025px) {
  .work__hero .work__title {
    margin-bottom: clamp(50px, 9.8vh, 106px);  /* 106/1080*100 ≈ 9.8 */
  }
}

/* How We Work(.work, 별도 pin)와 What We Do(.work-do)는 이제 body 직계
   형제 섹션이다 — What We Do가 How We Work를 덮어 올라온다.
   Figma Section 4(1920x2091): 타이틀 y=120, row1 y=320 → 상단 120px /
   타이틀 하단 여백 106px(Section 3와 동일 리듬). padding-bottom 137px은
   마지막 row(Server & Cloud) 하단(1954)부터 섹션 끝(2091)까지의 여백. */
.work__what-wrap {
  background: #f6f6f6;
  padding: 120px 0 137px;
}

.work__cards {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 30px;
  max-width: 1500px;
  margin: 0 auto;
  padding: 0 24px;
}

.work__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 30px;
  width: auto;
  max-width: 100%;
  padding: 40px 30px 30px;
  border-radius: 160px;
  text-align: center;
  transition: box-shadow 0.3s ease;
}

/* vh 스케일링 — 위 .work__hero 옆 주석 참고. 좌우 padding(30px)은 폭 기준이라
   그대로 두고, 세로 요소(gap, 상하 padding)만 축소한다. */
@media (min-width: 1025px) {
  .work__card {
    gap: clamp(16px, 2.8vh, 30px);   /* 30/1080*100 ≈ 2.8 */
    padding: clamp(20px, 3.7vh, 40px) 30px clamp(16px, 2.8vh, 30px);
  }
}

/* 카드 순차 상승(PC 전용, 시간 기반): initWorkEnter가 화면 진입 시 카드별로
   시간차를 두고 --cp를 0→1로 바꾼다. opacity/transform 자체에 transition을
   걸어야 그 변화가 애니메이션으로 보인다(커스텀 프로퍼티 --cp 자체는
   @property 등록 없이는 transition이 안 먹는다). --cp가 1에 도달한 뒤
   (.is-settled)엔 transform을 걷어내고 별도 transition으로 바꿔줘야 기존
   :hover translateY(-6px)가 다시 정상 동작한다. */
@media (min-width: 1025px) {
  /* 기본값 0: JS(initWorkEnter)가 화면 진입을 감지해 1로 올려야 등장
     애니메이션이 보인다. JS가 아예 실행 안 되는 극단적 상황(스크립트 차단
     등) 대비 폴백은 없다 — 이 사이트의 다른 스크럽 효과들도 전부 JS
     의존적이라 동일한 전제를 공유한다. */
  .work__card {
    --cp: 0;
    opacity: var(--cp);
    transform: translate3d(0, calc((1 - var(--cp)) * 440px), 0);
    transition: opacity 0.9s cubic-bezier(0.22, 0.61, 0.36, 1),
      transform 0.9s cubic-bezier(0.22, 0.61, 0.36, 1);
  }

  .work__card.is-settled {
    transform: none;
    transition: transform 0.3s ease, box-shadow 0.3s ease;
  }
}

@media (max-width: 1024px) {
  .work__card {
    opacity: 1;
    transform: none;
  }
}

@media (min-width: 1025px) and (prefers-reduced-motion: reduce) {
  .work__card {
    --cp: 1;
    opacity: 1;
    transform: none;
  }
}

.work__card-text {
  display: contents;
}

.work__card-icon {
  width: 180px;
  height: 180px;
  border-radius: 50%;
  background: #f3f3f3;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* vh 스케일링 — 위 .work__hero 옆 주석 참고. */
@media (min-width: 1025px) {
  .work__card-icon {
    width: clamp(90px, 16.7vh, 180px);   /* 180/1080*100 ≈ 16.7 */
    height: clamp(90px, 16.7vh, 180px);
  }
}

.work__card-icon img {
  width: 82%;
  height: auto;
}

.work__card h3 {
  font-weight: 700;
  font-size: 32px;
  color: #293553;
}

.work__card-rule {
  width: 100px;
  height: 2px;
  background: #82acbe;
}

.work__card p {
  font-size: 22px;
  line-height: 1.4;
  color: #1b1b1b;
  white-space: nowrap;
}

.work__card--strategy p {
  letter-spacing: -0.05em;
}

.work__card--design p {
  letter-spacing: -0.02em;
}

.work__card--tech p {
  letter-spacing: -0.03em;
}

/* Figma Section 4: row는 x=360 w=1200 h=438, row 간격 160px.
   텍스트 718 : 이미지 482 비율로 나뉜다. */
.work__row {
  display: flex;
  /* Figma에서 텍스트 프레임(Tech-normal)은 이미지와 같은 h=438 박스이고
     내부 요소가 y=0(제목)부터 위에서 아래로 쌓인다 — 즉 제목 윗선이 이미지
     윗선과 같다. center로 두면 텍스트 덩어리(356px)가 438 안에서 세로
     가운데로 내려와 이미지보다 41px 낮게 시작한다. */
  align-items: flex-start;
  justify-content: center;
  gap: 0;
  /* padding을 폭 안에 포함시켜 콘텐츠 폭이 Figma 1200을 유지하게 한다.
     좌우 24px 여백은 장식 카드가 20px 바깥으로 나가는 것을 흡수한다. */
  box-sizing: content-box;
  max-width: 1200px;
  margin: 0 auto 160px;
  padding: 0 24px;
}

/* 세 row(EDU/Web Service/Server & Cloud)는 이제 .work__what-wrap 안의
   평범한 형제라 base margin-bottom(160px, 위 규칙)이 row1→row2, row2→row3
   간격을 그대로 만든다. 마지막 row(Server & Cloud)만 아래 여백을 갖지
   않는다 — 그 아래 137px은 .work__what-wrap의 padding-bottom이 담당한다.
   :last-child를 쓰면 안 된다: row3 뒤에 .work__carousel(PC에서는
   display:none이지만 DOM에는 존재)이 있어서 :last-child가 캐러셀에 걸리고
   row3에는 안 걸린다. row 구성이 고정이므로 클래스로 직접 지정한다. */
.work__row--server-row {
  margin-bottom: 0;
}

/* 개편 전에는 row별로 장식 카드가 삐져나오는 정도가 달라(::before의 top/height
   오프셋 차이) margin을 row마다 다르게 보정했었다. 지금은 카드가 전부 동일한
   크기·오프셋이라 .work__row의 균일한 margin-bottom(160px, Figma row 간격)
   하나로 충분하다. */

.work__row--left,
.work__row--right {
  flex-direction: row;
}

/* Figma: 텍스트 718 / 이미지 482 비율. 텍스트는 좌우 배치와 무관하게
   항상 왼쪽 정렬이다(개편 전에는 --right일 때 오른쪽 정렬이었다). */
.work__row-text {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
}

/* Figma: Tech-normal 프레임 718px 안에 40px 안쪽 여백(pr-40/pl-40)이 있어
   실제 텍스트 박스는 678px다. 이 678px이 본문 줄바꿈 위치를 결정하므로
   폭을 정확히 맞춰야 Figma와 같은 줄에서 끊긴다. */
.work__row--right .work__row-text {
  padding-right: 40px;
}

.work__row--left .work__row-text {
  padding-left: 40px;
}

/* Figma: Noto Sans Black 32px, #293553.
   자간 -1.28px(= -0.04em)은 EDU/Web만 걸려 있고 Server 제목(26:4968)에는
   자간 지정이 없다 — 아래 --server 오버라이드 참고. */
.work__row-text h3 {
  font-weight: 900;
  font-size: 32px;
  line-height: 1.2;
  letter-spacing: -0.04em;
  color: #293553;
}

.work__row-text--server h3 {
  letter-spacing: normal;
}

/* Figma: 80x2, #6b6b6b. 제목(y=0,h=38) 아래 y=68 → 위 여백 30px */
.work__row-rule {
  display: block;
  width: 80px;
  height: 2px;
  background: #6b6b6b;
  margin: 30px 0;
}

/* Figma: 22px, #6b6b6b, line-height 1.37.
   자간은 row마다 다르다 — EDU/Server는 -0.44px, Web은 -0.66px(실측 노드
   26:4992 / 26:4970 / 26:4984). 22px 기준 -0.44px = -0.02em, -0.66px = -0.03em.
   줄바꿈: EDU/Server는 Figma에서도 자동 줄바꿈이라 678px 폭에 맡기고,
   Web만 <br> 4개가 명시돼 있어 마크업에서 고정한다. */
.work__row-text p {
  font-size: 22px;
  line-height: 1.37;
  letter-spacing: -0.02em;
  color: #6b6b6b;
  margin-bottom: 30px;
}

.work__row-text--web p {
  letter-spacing: -0.03em;
}

@media (max-width: 900px) {
  .work__row-text--edu p,
  .work__row-text--server p,
  .work__row-text--web p {
    font-size: 16px;
    white-space: normal;
  }

  .work__card p {
    white-space: normal;
  }
}

/* 태블릿(641~900px): 카드 3개를 2열 그리드로 배치 (모바일 640px 이하는 별도 가로형 카드 레이아웃 사용) */
@media (min-width: 641px) and (max-width: 900px) {
  .work__cards {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    justify-items: center;
    gap: 50px 24px;
  }

  .work__card {
    width: 100%;
    max-width: 340px;
  }

  .work__card p {
    white-space: normal;
    font-size: 22px;
  }
}

.work__row-link {
  display: inline-flex;
  align-items: center;
  padding: 4px 23px;
  border: 2px solid #2c80e6;
  border-radius: 25px;
  font-size: 28px;
  letter-spacing: -0.03em;
  color: #2c80e6;
  transition: background 0.25s ease, color 0.25s ease;
}

.work__row-link:hover {
  background: #2c80e6;
  color: #fff;
}

/* Figma Group 509는 482x438이고, 그 안에 462x438 이미지와 흰 카드가 20px
   어긋나 겹쳐 있다(= 482 = 462 + 20px 카드 오버행). 즉 카드가 삐져나오는 20px는
   레이아웃 폭 안에 포함돼 있어 텍스트 영역을 침범하지 않는다.
   여기서는 .work__row-photo가 그 482 슬롯이고, 이미지(img)가 그 안에서 462다. */
.work__row-photo {
  flex: 0 0 auto;
  width: 482px;
  max-width: 40.17%;
  aspect-ratio: 482 / 438;
  position: relative;
}

/* row 이미지 드리프트(PC 전용, 스크럽): initWorkRows가 row가 화면을
   진입~이탈하는 전체 구간의 진행률을 --row-drift(-0.5~0.5, row 화면 중앙
   통과 시 0)로 매 프레임 기록한다. 아래로 스크롤할수록 값이 커져 이미지이
   위로 드리프트하고, 위로 스크롤하면 반대로 아래로 내려간다(사용자 확정:
   "아래로 스크롤 하면 해당 구역에서 위로 드리프팅되며 살짝 올라가야해.
   반대로 위로 스크롤 하면 아래로" — godaylight.com 참고). 텍스트에는
   걸지 않는다(사용자 확정: 텍스트는 고정).

   ⚠️ 마스크드 패럴랙스 방식(사용자 확정): "이미지가 표 안에 있다고
   생각해봐. 스크롤 할때 그 표를 벗어나서 위로 이미지가 올라가면 올라간
   만큼 위쪽 이미지가 표때문에 숨는거고 아래쪽 이미지는 안보였던 부분이
   올라와서 보이게 되는 그런 효과". 즉 틀(.work__row-photo)은 고정된 채
   overflow:hidden으로 창 역할만 하고, 그 안의 img만 크게 움직이며 틀
   밖으로 나가는 부분은 잘린다. 그래서 transform은 틀이 아니라 img에
   걸어야 한다(이전 버전 주석과 반대) — 틀에 걸면 틀 자체가 움직여
   버려서 "고정된 창 안에서 사진만 움직이는" 효과가 성립하지 않는다.
   img는 미리 세로로 240px 더 크게 잡고(top:-120px로 중앙 유지) 최대
   ±100px 이동해도 틀 상하단에 빈틈이 생기지 않게 여유를 둔다
   (120px 여유 - 100px 이동 = 20px 버퍼). ::before(흰 장식카드)는 틀에
   고정된 채 그대로 두어 창의 프레임처럼 안 움직인다. */
/* border-radius를 틀 자신에도 줘야 한다 — img가 위아래로 240px 오버사이즈
   라(드리프트용) img 자신의 모서리(border-radius:20px)는 항상 틀 밖에
   있어 화면에 아예 안 나타난다. 실제로 보이는 둥근 모서리는 이
   overflow:hidden 클리핑 경계가 만든다. */
.work__row-photo {
  overflow: hidden;
  border-radius: 20px;
}

@media (max-width: 640px) {
  .work__row-photo {
    width: 100%;
    max-width: 480px;
  }
}

/* 사진 뒤에 깔리는 장식 카드 — 개편된 Figma(Group 509)에서는 파란색이 아니라
   흰색 카드(Rectangle 160, 462x438)가 사진과 같은 크기로 깔린다.
   Figma 실좌표(26:4975/4979/4997) 기준: 어긋남은 가로 20px뿐이고 세로 오프셋은
   0이다. 방향은 항상 "이미지 기준 텍스트 쪽"으로, 즉 이미지가 오른쪽에 있는
   row(--right)는 카드가 왼쪽으로, 이미지가 왼쪽에 있는 row(--left)는 카드가
   오른쪽으로 나간다 — 세 row 모두 카드가 안쪽(텍스트 방향)을 향한다. */
/* 462 / 482 = 95.85%. --right row(이미지 오른쪽): 카드 x=0, 이미지 x=20
   --left row(이미지 왼쪽):   카드 x=20, 이미지 x=0  (20/482 = 4.15%) */
.work__row-photo::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 95.85%;
  height: 100%;
  background: #fff;
  border-radius: 20px;
  z-index: 1;
}

.work__row--left .work__row-photo::before {
  left: 4.15%;
}

.work__row-photo img {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 4.15%;
  width: 95.85%;
  height: 100%;
  object-fit: cover;
  border-radius: 20px;
  display: block;
}

.work__row--left .work__row-photo img {
  left: 0;
}

/* 드리프트(PC 전용): 위 base .work__row-photo img 규칙(top:0, height:100%)
   보다 뒤에 와야 이긴다 — 같은 specificity라 소스 순서가 정한다.
   top/height를 오버사이즈로 덮어써 이미지가 ±40px 움직여도 항상 틀을
   꽉 채운다(50px 여유 - 40px 이동 = 10px 버퍼).

   ⚠️ 오버사이즈 값은 잘림과 직결된다. 사진(1516x1440, 비율 1.053)과 틀
   (462x438, 비율 1.055)은 비율이 거의 같아서 드리프트가 없으면 cover로도
   잘림이 0이다. 그런데 세로로 키운 만큼 틀 비율이 세로로 길어지고,
   cover가 그 상자를 채우려 좌우를 잘라낸다. 예전 값(+240px)은 틀 비율을
   0.681까지 떨어뜨려 좌우가 크게 잘려 "줌된 것처럼" 보였다. +100px이면
   0.858로 올라가 잘림이 크게 줄면서 드리프트 연출은 유지된다. */
@media (min-width: 1025px) {
  .work__row-photo img {
    --row-drift: 0;
    top: -50px;
    height: calc(100% + 100px);
    transform: translate3d(0, calc(var(--row-drift) * -80px), 0);
  }
}

/* 위 드리프트 규칙보다 반드시 뒤에 와야 한다 — 둘 다 min-width:1025px를
   포함하는 미디어쿼리라 reduced-motion 환경에서는 두 쿼리가 동시에
   매치되고, 같은 specificity(.work__row-photo img)라 소스 순서로
   승패가 갈린다. 앞에 두면 이 규칙이 드리프트 규칙에 덮여 무시된다. */
@media (min-width: 1025px) and (prefers-reduced-motion: reduce) {
  .work__row-photo img,
  .work__row-text {
    transform: none;
  }
}

@media (max-width: 640px) {
  .work__row,
  .work__row--right {
    flex-direction: column-reverse;
    /* 세로 배치라 align-items가 가로 정렬을 담당한다 — PC의 flex-start
       (텍스트를 이미지 윗선에 맞추는 용도)를 그대로 두면 요소가 왼쪽으로
       붙으므로, 모바일은 기존대로 가로 가운데 정렬을 유지한다. */
    align-items: center;
  }
  .work__row--right .work__row-text,
  .work__row--right .work__row-rule {
    text-align: center;
    margin-left: 0;
  }
  .work__row-text {
    text-align: center !important;
  }
  .work__card p {
    white-space: normal;
  }
}

@media (max-width: 640px) {
  .work {
    padding: 0 0 100px;
  }

  /* 모바일에서는 한 화면을 강제로 채우지 않는다(콘텐츠가 세로로 길어져
     빈 공간만 생긴다). */
  .work__hero {
    min-height: 0;
    padding-top: 126px;
  }

  .work__logo {
    margin-left: 24px;
    height: 32px;
  }

  .work__title {
    text-align: left;
    margin-left: 24px;
    font-size: 30px;
    margin-bottom: 40px;
  }

  .work__cards {
    flex-direction: column;
    align-items: stretch;
    gap: 36px;
    padding: 0 24px;
    margin-bottom: 90px;
  }

  .work__card {
    flex-direction: row;
    align-items: flex-start;
    gap: 18px;
    padding: 0;
    text-align: left;
  }

  .work__card-icon {
    flex: 0 0 auto;
    width: 80px;
    height: 80px;
    background: #fff;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
  }

  .work__card-text {
    display: block;
    flex: 1 1 auto;
    min-width: 0;
  }

  .work__card h3 {
    font-size: 21px;
  }

  .work__card-rule {
    margin: 10px 0;
  }

  .work__card p {
    font-size: 14px;
    line-height: 1.65;
    white-space: normal !important;
    word-break: keep-all;
  }


  .work__row {
    margin-bottom: 70px;
    padding: 0 24px;
    gap: 24px;
  }

  .work__row-text,
  .work__row--right .work__row-text {
    text-align: left !important;
  }

  .work__row-rule,
  .work__row--right .work__row-rule {
    margin: 16px 0 !important;
  }

  .work__row-text h3 {
    font-size: 28px;
  }

  .work__row-text p {
    font-size: 15px;
    line-height: 1.6;
    margin-bottom: 20px;
    word-break: keep-all;
  }


  .work__row-photo {
    max-width: 100%;
  }
}

/* 모바일 전용 롤링 캐러셀 (이미지 위 텍스트 오버레이) */
.work__carousel {
  display: none;
}

@media (max-width: 640px) {
  /* Server & Cloud row(.work__row--server-row)도 이 규칙에 걸려 함께
     숨겨진다 — 이제 평범한 .work__row라 별도 처리가 필요 없다(과거에는
     work-tail pin 껍데기를 따로 숨겨야 했음). 같은 내용은 아래
     .work__carousel이 대신 보여준다. */
  .work__row {
    display: none;
  }

  .work__carousel {
    display: block;
    margin-bottom: 0;
  }

  .work__carousel-track {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -ms-overflow-style: none;
    padding: 0 5% 24px;
    gap: 14px;
  }

  .work__carousel-track::-webkit-scrollbar {
    display: none;
  }

  .work__carousel-slide {
    position: relative;
    flex: 0 0 90%;
    scroll-snap-align: center;
    border-radius: 24px;
    overflow: hidden;
    aspect-ratio: 3 / 4;
  }

  .work__carousel-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .work__carousel-overlay {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 28px 24px 32px;
    color: #fff;
    background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.55) 22%, rgba(0, 0, 0, 0.85) 100%);
  }

  .work__carousel-overlay h3 {
    font-weight: 800;
    font-size: 21px;
    letter-spacing: -0.02em;
  }

  .work__carousel-overlay .work__row-rule {
    background: #fff;
    margin: 12px 0;
  }

  .work__carousel-overlay p {
    font-size: 13px;
    line-height: 1.55;
    margin-bottom: 18px;
    word-break: keep-all;
  }

  .work__carousel-overlay .work__row-link {
    border: none;
    border-radius: 40px;
    background: rgba(255, 255, 255, 0.49);
    backdrop-filter: blur(5px);
    color: #fff;
    font-size: 14px;
    letter-spacing: -0.03em;
    padding: 8px 20px;
  }

  .work__carousel-overlay .work__row-link:hover {
    background: rgba(255, 255, 255, 0.7);
    color: #fff;
  }

  .work__carousel-dots {
    display: flex;
    justify-content: center;
    gap: 8px;
  }

  .work__carousel-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(41, 53, 83, 0.25);
    transition: background 0.25s ease, width 0.25s ease;
  }

  .work__carousel-dot.is-active {
    width: 20px;
    border-radius: 4px;
    background: #2c80e6;
  }
}

/* ==========================================================================
   Section: Our Works
   ========================================================================== */
.works {
  position: relative;
  width: 100%;
  background: #e7ecf4;
  border-top-right-radius: min(140px, 10.4vw);
  padding: 149px 0 100px;
  /* overflow:hidden 대신 clip-path 사용 — .works__logos를 sticky로 만들어
     Contact Us로 전환되는 여유 구간(padding-bottom, PC 전용) 동안 로고그리드가
     화면에 붙어 있게 할 건데, overflow:hidden 조상은 자식의 position:sticky를
     조용히 죽인다(.work에서 이미 겪은 문제와 동일). clip-path는 sticky에
     영향을 주지 않으면서 모서리 라운딩은 그대로 유지한다. */
  clip-path: inset(0 round 0 min(140px, 10.4vw) 0 0);
}

.works__logo {
  display: block;
  height: 45px;
  width: auto;
  margin-left: 16.3vw;
  margin-bottom: 34px;
}

@media (min-width: 1920px) {
  .works__logo {
    margin-left: calc(50% - 647px);
  }
}

/* Figma: 타이틀 y=120 h=94 → 하단 214, 카드 영역(Frame 504) y=300 = 여백 86px */
.works__title {
  text-align: center;
  font-weight: 600;
  font-size: clamp(32px, 4.17vw, 80px);
  line-height: 1.17;
  color: #293553;
  margin-bottom: 86px;
}

/* Figma Frame 504(26:4893): x=360 w=1200, 3열 각 400px.
   세로 구분선(Line 22/23)이 x=400, 800 — 즉 컬럼 경계에 정확히 놓이므로
   컬럼 사이 gap은 0이다(구분선은 폭 없는 선). */
.works__stats {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0;
  max-width: 1200px;
  /* 카드 영역 하단(638) → 로고 그리드(color icon, y=724) = 여백 86px */
  margin: 0 auto 86px;
  padding: 0 24px;
  box-sizing: content-box;
  /* 아이콘 3개는 항상 한 줄. 좁은 화면 레이아웃은 아래 미디어쿼리
     (900px 이하 2열, 640px 이하 세로 리스트)에서 따로 정의한다. */
  flex-wrap: nowrap;
}

/* Figma Frame 496(26:4894): 400x338(=1200/3), padding 40px 112px 30px, gap 30.
   폭을 400px로 고정하면 3열(1200) + 세로 구분선 2개(각 2px) = 1204px가 되어
   컨테이너(1200)를 4px 넘겨 마지막 컬럼이 다음 줄로 밀린다. flex:1로 남는
   폭을 균등 분배하면(각 398.67px) 줄바꿈이 구조적으로 불가능하고 Figma의
   400px과는 1.33px 차이뿐이라 육안으로 구분되지 않는다.
   좌우 패딩 112px은 내부 콘텐츠를 가운데 두기 위한 값이라, 폭만 맞추면
   최소 패딩으로도 같은 결과가 나온다. */
.works__stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 30px;
  flex: 1 1 0;
  min-width: 0;
  max-width: 400px;
  padding: 40px 24px 30px;
  text-align: center;
}

/* Figma는 세 아이콘의 "높이"를 100px로 통일하고 폭은 원본 비율대로 둔다
   (101.40 / 104.96 / 101.31). 폭을 100px로 고정하면 아이콘마다 높이가
   달라져 아래 구분선·제목의 세로 위치가 서로 어긋난다. */
.works__stat img {
  height: 100px;
  width: auto;
}

/* Figma Line 24(26:4904/4921): w=100, stroke 2px (inset -2px 0 0 0) */
.works__stat-rule {
  width: 100px;
  height: 2px;
  background: rgba(41, 53, 83, 0.33);
}

/* 세 번째 컬럼(Web & App Dev)만 구분선이 60px이다(26:4936, x=170 w=60) —
   앞 두 개(100px)와 다르지만 Figma 실측값 그대로 반영한다. */
.works__stat--web .works__stat-rule {
  width: 60px;
}

/* Figma 26:4905: 32px, #293553, line-height none(=1), 자간 지정 없음 */
.works__stat h3 {
  font-weight: 400;
  font-size: 32px;
  line-height: 1;
  color: #293553;
}

.works__stat-link {
  display: inline-flex;
  align-items: center;
  padding: 10px 20px;
  background: #2c80e6;
  border-radius: 60px;
  color: #fff;
  font-size: 22px;
  transition: background 0.25s ease;
}

.works__stat-link:hover {
  background: #1f66bd;
}

.works__stat-divider {
  width: 2px;
  flex: 0 0 auto;
  height: 100px;
  background: rgba(49, 61, 99, 0.3);
}

@media (max-width: 900px) {
  .works__stat-divider {
    display: none;
  }
}

@media (min-width: 641px) and (max-width: 900px) {
  .works__stats {
    gap: 16px 20px;
    /* 이 구간은 2열로 접는다 — PC의 nowrap/flex:1을 되돌린다. */
    flex-wrap: wrap;
  }

  .works__stat {
    flex: 0 0 auto;
    width: calc(50% - 10px);
    max-width: none;
    padding: 24px 16px;
  }
}

.works__logos {
  position: relative;
  width: 100%;
  max-width: 1166px;
  aspect-ratio: 1166 / 151;
  margin: 0 auto;
}


.works__logo-item {
  position: absolute;
  height: auto;
  object-fit: contain;
  opacity: 0.85;
  transition: opacity 0.25s ease;
}

.works__logo-item:hover {
  opacity: 1;
}

.works__logo-item--woongjin { left: 0.6%; top: 0%; width: 10.8%; }
.works__logo-item--visang   { left: 27.1%; top: 3.3%; width: 13.8%; }
.works__logo-item--chunjae1 { left: 56.6%; top: 11.3%; width: 13.0%; }
.works__logo-item--chunjae2 { left: 85.2%; top: 7.9%; width: 14.8%; }
.works__logo-item--mirae    { left: 0%; top: 60.3%; width: 13.9%; }
.works__logo-item--jihak    { left: 26.8%; top: 60.3%; width: 13.3%; }
.works__logo-item--iscream  { left: 55.5%; top: 53.6%; width: 16.8%; }
.works__logo-item--handok   { left: 86.7%; top: 49.0%; width: 11.6%; }

@media (max-width: 900px) {
  .works__logos {
    position: static;
    max-width: 480px;
    aspect-ratio: auto;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 24px 32px;
    padding: 0 24px;
  }
  .works__logo-item {
    position: static;
    width: auto !important;
    height: 32px;
  }
}

@media (max-width: 640px) {
  .works {
    padding: 126px 0 80px;
  }

  .works__logo {
    margin-left: 24px;
    height: 32px;
  }

  .works__title {
    text-align: left;
    margin-left: 24px;
    font-size: 30px;
    margin-bottom: 50px;
  }

  .works__stats {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    max-width: 100%;
    padding: 0;
    margin-bottom: 60px;
    border-top: 1px solid rgba(41, 53, 83, 0.15);
  }

  .works__stat {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 20px;
    /* 세로 리스트라 PC의 flex:1(가로 균등분배)을 되돌린다 —
       그대로 두면 항목이 세로로 늘어난다. */
    flex: 0 0 auto;
    width: 100%;
    max-width: 100%;
    padding: 24px;
    text-align: left;
    border-bottom: 1px solid rgba(41, 53, 83, 0.15);
  }

  .works__stat img {
    /* PC와 같은 이유로 높이 기준(가로형 카드라 세로 정렬이 더 중요) */
    height: 60px;
    width: auto;
    flex: 0 0 auto;
  }

  .works__stat-rule {
    display: none;
  }

  .works__stat h3 {
    font-size: 20px;
    flex: 1 1 auto;
  }

  .works__stat-link {
    flex: 0 0 auto;
    font-size: 15px;
    padding: 8px 16px;
  }

  .works__logos {
    max-width: 340px;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    justify-items: center;
    align-items: center;
    gap: 36px 20px;
    padding: 0;
  }

  .works__logo-item {
    height: 28px;
  }

  .works__logo-item--woongjin { order: 1; }
  .works__logo-item--visang   { order: 2; }
  .works__logo-item--chunjae1 { order: 3; }
  .works__logo-item--chunjae2 { order: 4; }
  .works__logo-item--mirae    { order: 5; }
  .works__logo-item--jihak    { order: 6; }
  .works__logo-item--iscream  { order: 7; }
  .works__logo-item--handok   { order: 8; }
}

/* ==========================================================================
   Footer / CTA
   ========================================================================== */
.site-footer {
  position: relative;
  width: 100%;
  background: #e7ecf4;
}

/* Figma(8:4286): 배경 바가 1840px / 뷰포트 1920px = 좌우 40px씩 여백,
   상단 라운드 140px. 여백 바깥으로는 .site-footer의 #e7ecf4가 드러난다. */
.site-footer__hero {
  position: relative;
  width: calc(100% - min(80px, 4.17vw));
  margin: 0 auto;
  border-radius: min(140px, 7.3vw) min(140px, 7.3vw) 0 0;
  background:
    linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)),
    radial-gradient(circle at 3% 10%, rgba(22, 71, 140, 0.6) 0%, rgba(4, 20, 78, 0.6) 100%);
  padding: 90px 24px 110px;
  text-align: center;
}

.site-footer__lead {
  font-size: clamp(18px, 1.56vw, 30px);
  line-height: 1.29;
  letter-spacing: -0.04em;
  color: #fff;
  margin-bottom: 40px;
}

.site-footer__cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 22px 15px 34px;
  border: 1px solid #fff;
  border-radius: 60px;
  background: transparent;
  color: #fff;
  font-family: inherit;
  font-size: clamp(18px, 1.77vw, 34px);
  cursor: pointer;
  transition: background 0.25s ease, color 0.25s ease;
}

.site-footer__cta img {
  width: 40px;
  height: 40px;
}

.site-footer__cta:hover {
  background: #fff;
  color: #142b4f;
}

/* Figma(8:4269): 로고는 x=200(1920 기준 10.42%)에 좌측 배치, 정보 텍스트는
   오른쪽 끝 x=1720까지 우측 정렬 — 세로 쌓기가 아니라 가로 한 줄이다. */
.site-footer__bottom {
  position: relative;
  background: rgba(0, 0, 0, 0.64);
  padding: 45px max(24px, 10.42%);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  text-align: left;
}

.site-footer__logo {
  height: 45px;
  width: auto;
  margin: 0;
  flex: 0 0 auto;
}

/* Figma에서 이 블록은 1017px 고정폭(1920 기준 53%)으로 2줄에 떨어진다.
   flex 기본값(shrink)에 맡기면 폭이 모자라 "대표 제규/창"처럼 단어
   중간에서 끊기므로 최소폭을 확보하고 단어 단위로만 줄바꿈시킨다. */
.site-footer__info {
  font-size: clamp(11px, 1.15vw, 22px);
  line-height: 1.4;
  color: #fff;
  text-align: right;
  flex: 0 1 auto;
  min-width: 0;
  word-break: keep-all;
}

/* Figma는 이 블록을 정확히 2줄로 떨어뜨린다(주소+우편번호+사업자번호 /
   메일+대표+TEL+저작권). 자연 줄바꿈에 맡기면 폭에 따라 "대표 / 제규창"
   처럼 어색하게 끊기므로 명시적 <br>로 끊는다. */
.site-footer__info-break {
  display: inline;
}

@media (max-width: 768px) {
  .site-footer__hero {
    padding: 60px 24px 70px;
  }
  .site-footer__bottom {
    padding: 30px 24px;
  }
}

@media (max-width: 640px) {
  .site-footer__hero {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    min-height: 54.7vw;
    padding: 40px 24px;
  }

  .site-footer__lead {
    font-size: 4.3vw;
  }

  .site-footer__cta {
    padding: 1.4vw 2vw 1.4vw 3.1vw;
    font-size: 3.1vw;
  }

  .site-footer__cta img {
    width: 7.4vw;
    height: 7.4vw;
    max-width: 32px;
    max-height: 32px;
  }

  /* PC에서 가로 한 줄(flex row)이므로 모바일은 세로 쌓기로 되돌린다. */
  .site-footer__bottom {
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    text-align: left;
    padding: 8.2vw 6.4vw 10vw;
  }

  .site-footer__logo {
    margin: 0 0 20px;
  }

  .site-footer__info {
    text-align: left;
    font-size: 3.37vw;
    white-space: normal;
  }

  .site-footer__info-break {
    display: block;
  }

  .site-footer__info-indent {
    display: none;
  }
}

/* Contact 메일 서비스 선택 모달 */
.contact-modal {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1000;
  display: none;
}

.contact-modal.is-open {
  display: block;
}

.contact-modal__dim {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(10, 16, 30, 0.6);
  backdrop-filter: blur(2px);
  opacity: 0;
  transition: opacity 0.25s ease;
}

.contact-modal.is-open .contact-modal__dim {
  opacity: 1;
}

.contact-modal__box {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -46%);
  width: min(650px, calc(100vw - 40px));
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.contact-modal.is-open .contact-modal__box {
  opacity: 1;
  transform: translate(-50%, -50%);
}

.contact-modal__envelope {
  display: block;
  width: 32.6%;
  height: auto;
  aspect-ratio: 425 / 443;
  margin: 0 auto -60px;
  position: relative;
  z-index: 2;
  pointer-events: none;
}

.contact-modal__panel {
  position: relative;
  border-radius: 56px;
  background: linear-gradient(180deg, #fff 0%, #d7efff 100%);
  padding: 98px 40px 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  box-shadow: 0 24px 60px rgba(10, 16, 30, 0.35);
}

.contact-modal__title {
  font-size: 32px;
  font-weight: 900;
  color: #293553;
  letter-spacing: -1.28px;
  line-height: 1.2;
  text-align: center;
}

.contact-modal__desc {
  font-size: 22px;
  line-height: 1.37;
  color: #6b6b6b;
  letter-spacing: -0.66px;
  text-align: center;
}

.contact-modal__grid {
  display: flex;
  gap: 18px;
  justify-content: center;
}

/* 아이콘 PNG 자체에 흰 라운드 배경 + 테두리 + 그림자가 이미 그려져 있다
   (Figma에서도 74px 프레임이 84px로 렌더될 만큼 그림자가 밖으로 번진다).
   그래서 버튼 쪽에 테두리/라운드/그림자를 또 주면 두 겹으로 보인다 —
   장식은 전부 이미지에 맡기고 버튼은 히트영역 역할만 한다. */
.contact-modal__item {
  position: relative;
  width: 74px;
  height: 74px;
  flex: 0 0 auto;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  transition: transform 0.18s ease, filter 0.18s ease;
}

.contact-modal__item img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 22px;
  transition: box-shadow 0.18s ease;
}

/* 브랜드 로고(구글/카카오 등 고유 색상)를 어두운 오버레이로 덮으면
   색이 뭉개져 부자연스럽다 — 살짝 떠오르며 그림자가 진해지는
   카드형 호버로 대체, 로고 색은 그대로 유지한다. */
.contact-modal__item:hover {
  transform: translateY(-3px);
}

.contact-modal__item:hover img {
  box-shadow: 0 8px 16px rgba(41, 53, 83, 0.22);
}

/* 커스텀 툴팁 (기본 브라우저 title 툴팁 대체). 말풍선 본체는 ::before,
   꼬리는 실제 span(.contact-modal__tooltip-arrow)으로 그린다
   (::after는 이미 hover 딤 오버레이 전용이라 재사용 불가). */
.contact-modal__item[data-tooltip] {
  overflow: visible;
}

.contact-modal__item[data-tooltip]::before {
  content: attr(data-tooltip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 14px);
  transform: translate(-50%, 6px);
  padding: 8px 14px;
  border-radius: 10px;
  background: #293553;
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.26px;
  white-space: nowrap;
  box-shadow: 0 6px 16px rgba(10, 16, 30, 0.28);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: 5;
}

.contact-modal__tooltip-arrow {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  transform: translate(-50%, 6px);
  width: 10px;
  height: 6px;
  background: #293553;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: 5;
}

.contact-modal__item[data-tooltip]:hover::before,
.contact-modal__item[data-tooltip]:hover .contact-modal__tooltip-arrow {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

.contact-modal__close {
  display: block;
  width: 100px;
  height: 100px;
  margin: 20px auto 0;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  transition: opacity 0.2s ease;
}

.contact-modal__close img {
  display: block;
  width: 100%;
  height: 100%;
}

.contact-modal__close:hover {
  opacity: 0.8;
}

@media (max-width: 620px) {
  .contact-modal__panel {
    border-radius: 36px;
    padding: 70px 24px 32px;
    gap: 28px;
  }
  .contact-modal__envelope {
    width: 150px;
    margin-bottom: -44px;
  }
  .contact-modal__title {
    font-size: 24px;
    letter-spacing: -0.96px;
  }
  .contact-modal__grid {
    flex-wrap: wrap;
  }
  .contact-modal__desc {
    font-size: 16px;
    letter-spacing: -0.48px;
  }
  .contact-modal__close {
    width: 72px;
    height: 72px;
    margin-top: 12px;
  }
}

/* ==========================================================================
   전역 고정 로고 (PC + 모바일 공통)
   스크롤 위치·화면 크기와 무관하게 항상 같은 화면 좌표에 떠 있고, 색상만
   (흰색/어두운색) 크로스페이드로 전환된다. 배경·테두리·그림자 없음.
   ========================================================================== */
:root {
  --logo-left: 24px;
  --logo-top: 24px;
  --logo-h: 32px;
}

@media (min-width: 1025px) {
  :root {
    /* Figma 상단바: padding 0 200px, 로고 136x31.75 (1920 기준).
       200/1920 = 10.42vw. */
    --logo-left: 10.42vw;
    --logo-top: 24px;
    --logo-h: 31.75px;
  }
}

@media (min-width: 1920px) {
  :root {
    /* 1920px보다 넓은 화면(예: 2560px)에서는 콘텐츠 영역(.hero__content 등,
       max-width:1920px; margin:0 auto)이 중앙 정렬되며 좌측에 여백이 생긴다.
       로고가 항상 "1920px 화면에서 보이던 그 위치"(콘텐츠 영역 기준 200px)에
       있도록, 화면이 1920px보다 넓은 만큼 생기는 여백의 절반을 더해준다. */
    --logo-left: calc(max(0px, (100vw - 1920px) / 2) + 200px);
  }
}

.global-logo {
  display: block;
  position: fixed;
  top: var(--logo-top);
  left: var(--logo-left);
  z-index: 90;
  height: var(--logo-h);
  width: auto;
  line-height: 0;
  pointer-events: none;
}

/* 로고 스크롤 아웃(PC 전용): How We Work가 완전히 덮은 뒤부터는 일반 스크롤로
   전환되며, 로고도 콘텐츠와 함께 위로 사라진다. position:fixed는 그대로 두고
   transform+opacity만 쓴다 — fixed에서 absolute로 전환하면 뷰포트 좌표와 문서
   좌표를 동시에 바꿔야 해서 1프레임만 어긋나도 점프가 보인다. --logo-exit(0~1)는
   순수 함수라 위로 되감으면 대칭으로 다시 나타난다. */
@media (min-width: 1025px) {
  .global-logo {
    --logo-exit: 0;
    transform: translate3d(0, calc(var(--logo-exit) * -1 * (var(--logo-top) + var(--logo-h) + 24px)), 0);
    opacity: calc(1 - var(--logo-exit));
  }
}

@media (min-width: 1025px) and (prefers-reduced-motion: reduce) {
  .global-logo {
    --logo-exit: 0;
    transform: none;
    opacity: 1;
  }
}

.global-logo__img--dark {
  position: relative;
  height: 100%;
  width: auto;
}

.global-logo__img--light {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: auto;
}

.global-logo__img {
  opacity: 0;
  transition: opacity 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}

.global-logo:not(.is-dark) .global-logo__img--dark {
  opacity: 1;
}

.global-logo.is-dark .global-logo__img--light {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .global-logo__img {
    transition: none;
  }
}

/* 섹션 자체 로고는 전역 고정 로고로 완전히 대체된다 (PC + 모바일 공통). */
.hero__header,
.viewer__logo,
.work__logo,
.works__logo {
  display: none;
}

/* ==========================================================================
   pin 프리미티브 (PC 전용): Hero -> Multi Viewer
   .pin은 --pin-len(추가 체류 길이, 뷰포트 배수)만큼의 여분 높이를 갖고,
   그 안의 .pin__inner가 position:sticky로 화면에 고정된 채 다음 섹션이
   그 위를 덮으며 스크롤되어 올라온다.
   구조 규칙: .pin은 반드시 <body> 직계 자식이어야 한다 — overflow:hidden
   조상 안에 들어가면 sticky가 조용히 죽는다.
   ========================================================================== */
@media (min-width: 1025px) {
  .pin {
    position: relative;
    height: 100vh;
    height: calc(100svh * (1 + var(--pin-len, 0)));
  }

  .pin__inner {
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100svh;
    min-height: 700px;
    overflow: hidden;
    will-change: transform;
  }

  .pin[data-pin="hero"] .pin__inner {
    z-index: 1;
    /* 드리프트로 히어로 콘텐츠가 위로 밀려나면 .pin__inner 하단에 여백이
       생긴다. 그 순간 뒤에 아직 다음 막(뷰어)이 안 올라와 있어도 이 배경색이
       비치므로 흰 여백이 노출되지 않는다. 히어로 그라디언트와 동일 톤. */
    background: linear-gradient(148deg, #267c96 23%, #142b4f 74%);
  }

  .pin[data-pin="hero"] .pin__inner > .hero {
    height: 100%;
  }

  /* 뷰어가 히어로(sticky) pin 위로 덮으며 올라오도록: 히어로 --pin-len에 더해둔
     여분 100svh 트랙을 이 margin-top이 상쇄한다(문서 전체 높이 순증 없음).
     그 100svh 구간 동안 히어로 pin__inner는 sticky로 화면에 그대로 붙어 있고,
     뷰어 pin이 그 위로 겹쳐 올라온다 — .work가 뷰어를 덮는 것과 완전히 동일한
     구조다(그쪽은 .work의 margin-top:-100svh). 이 margin-top이 없으면 히어로
     트랙이 다 끝난 뒤에야 뷰어가 자기 자리에서 시작하므로, 겹치지 않고 그냥
     둘이 이어서 스크롤되는 것처럼 보인다. */
  .pin[data-pin="viewer"] {
    margin-top: -100svh;
  }

  .pin[data-pin="viewer"] .pin__inner {
    z-index: 2;
    background: #f0f0f0;
  }

  .pin[data-pin="viewer"] .pin__inner > .viewer {
    height: 100%;
  }

  /* 뷰어가 히어로를 완전히 덮도록 불투명 배경 보장 (기존 #f0f0f0 유지) */
  .pin[data-pin="viewer"] .viewer__stage {
    aspect-ratio: auto;
    width: 100%;
    height: 100%;
    max-width: 1920px;
  }

  /* How We Work는 이제 독립 pin이다(히어로/뷰어와 동일한 프리미티브).
     margin-top은 뷰어 --pin-len:1이 만든 여분 100svh 트랙을 상쇄한다
     (문서 전체 높이 순증 없음) — 그 100svh 구간 동안 이 pin이 뷰어 위로
     겹쳐 올라온다. 예전에는 이 역할을 .work 자신이 했지만, What We Do가
     How We Work를 덮어 올라와야 해서 .work를 pin으로 분리했다
     (아래 .work-do 참고). */
  .pin[data-pin="work"] {
    margin-top: -100svh;
  }

  .pin[data-pin="work"] .pin__inner {
    z-index: 3;
    background: #fff;
  }

  .pin[data-pin="work"] .pin__inner > .work {
    height: 100%;
  }

  /* What We Do가 How We Work(sticky) 위로 덮어 올라온다 — .work pin의
     --pin-len:1이 만든 여분 100svh 트랙을 이 margin-top이 상쇄한다.
     padding-bottom:100svh는 반대로 Our Works가 잠식할 트랙을 만든다
     (문서 높이 순증은 여기서도 0 — 아래 .works 참고). */
  /* What We Do는 다른 세 막과 정확히 같은 pin 구조다 — 다만 콘텐츠가
     한 화면이 아니라 롱폼(3개 row)이라 .pin__inner(고정 100svh +
     overflow:hidden)를 그대로 쓸 수 없어, 같은 원리를 콘텐츠 높이에
     맞춰 편 형태다.

       .work-do        = .pin       (트랙: 콘텐츠 전체 + 덮이는 1화면)
       .work__what-wrap = .pin__inner (sticky로 고정되는 실제 콘텐츠)

     차이는 sticky 기준점 하나뿐이다. .pin__inner는 콘텐츠가 딱 한
     화면이라 top:0에 붙지만, 여기 콘텐츠는 화면보다 길어서 top:0으로
     붙이면 아래쪽이 영영 안 보인다. bottom:0으로 붙이면 콘텐츠가 위로
     다 흘러 마지막 줄이 화면 하단에 닿는 순간부터 고정되므로, 롱폼을
     끝까지 읽은 뒤 마지막 프레임에서 멈춘다 — 그 정지 상태 위로
     .works가 margin-top:-100svh로 덮어 올라온다.

     트랙 높이 = 콘텐츠 높이 + 100svh. 뒤의 100svh가 "고정된 채 덮이는"
     구간이고, .works의 margin-top:-100svh가 정확히 이 구간을 상쇄한다
     (문서 높이 순증 0) — 다른 경계와 동일한 산술. */
  .work-do {
    position: relative;
    z-index: 4;
    margin-top: -100svh;
    background: #f6f6f6;
  }

  /* 콘텐츠가 화면보다 길어서 top:0으로는 아래쪽이 영영 안 보이고,
     bottom:0은 "박스가 스크롤포트보다 작을 때"만 동작해서(이 wrap은
     2000px대라 해당 없음) 아예 고정이 안 걸린다. 그래서 콘텐츠 하단이
     화면 하단에 닿는 지점을 top으로 직접 지정한다 —
     top = 100svh - 콘텐츠높이. 그 지점부터 wrap이 고정되고, 그 위로
     .works가 덮어 올라온다. 콘텐츠 높이는 폰트/줄바꿈에 따라 달라지므로
     JS(initWorkDoPin)가 실측해 --what-h로 넣어준다. */
  .work-do > .work__what-wrap {
    position: sticky;
    top: calc(100svh - var(--what-h, 100svh));
  }

  /* 트랙의 여분 1화면. padding이 아니라 ::after로 만든다 — padding은
     sticky 요소(.work__what-wrap)의 스크롤 가능 범위에 포함돼 버려
     콘텐츠가 화면 밖으로 밀려난 뒤에야 고정이 시작된다. 형제 블록으로
     두면 sticky 컨테이닝 블록의 높이만 늘려 의도한 만큼 정확히
     고정 구간이 생긴다. */
  .work-do::after {
    content: "";
    display: block;
    height: 100svh;
  }

  /* Our Works가 What We Do(.work-do) 위로 덮어 올라온다 — .work-do의
     padding-bottom:100svh가 만든 트랙을 이 margin-top이 상쇄한다
     (문서 높이 순증 0). z-index는 사다리상 work-do(4)보다 위. */
  .works {
    position: relative;
    z-index: 5;
    margin-top: -100svh;
  }

  /* footer는 margin-top 없이 .works 뒤에 정상적인 문서 흐름으로 이어진다.
     margin-top 오버레이 트릭은 경계마다 한 겹만 쌓아야 안전하다 — 여기 또
     걸면 .works보다 먼저 화면에 나타나는 역전이 생긴다(과거 실측 확인 사례,
     "Our Works 카드가 사라졌다" 버그의 원인). */
  .site-footer {
    position: relative;
    z-index: 6;
  }
}

/* 모바일/태블릿: pin 전체 무력화 — 네이티브 스크롤 흐름 그대로 */
@media (max-width: 1024px) {
  .pin {
    height: auto;
  }

  .pin__inner {
    position: static;
    height: auto;
    min-height: 0;
    overflow: visible;
    will-change: auto;
  }
}

/* ==========================================================================
   드리프트 프리미티브 (PC 전용): 다음 막이 덮어 올라오는 동안, 깔린 막이
   완전히 멈춰있지 않고 스크롤 속도의 일부(--drift)만큼 함께 위로 이동한다.
   --cover-p(0~1)는 JS(initCoverDrift)가 매 프레임 기록한다.

   반드시 transform은 .pin__inner "자신"이 아니라 그 자식(section)에 건다.
   sticky 요소 자체에 transform을 걸면 그 요소가 자기 자손의 containing
   block이 되어버려 sticky 동작 자체가 흐트러질 수 있다.
   ========================================================================== */
@media (min-width: 1025px) {
  .pin__inner {
    --cover-p: 0;
    --drift: 0.18;
  }

  .pin__inner > section {
    transform: translate3d(0, calc(var(--cover-p) * var(--drift) * -100svh), 0);
  }

  .pin__inner > section.is-covering {
    will-change: transform;
  }

  /* What We Do → Our Works 경계(initWorkDoDrift, js/main.js).
     .work-do도 이제 다른 막과 같은 pin 구조(.work__what-wrap이 sticky)라
     드리프트도 같은 방식이다 — --cover-p는 sticky 요소의 부모(.work-do)에
     걸고 transform은 sticky 요소 자신이 아니라 그 자식(.work__row)들에
     건다. sticky 요소에 직접 transform을 걸면 그게 자손의 containing
     block이 되어 sticky가 흐트러진다(위 경고 참고). */
  .work-do {
    --cover-p: 0;
  }

  .work-do > .work__what-wrap > .work__row {
    transform: translate3d(0, calc(var(--cover-p) * var(--drift, 0.18) * -100svh), 0);
  }
}

@media (min-width: 1025px) and (prefers-reduced-motion: reduce) {
  .pin__inner > section {
    transform: none !important;
  }

  .work-do > .work__what-wrap > .work__row {
    transform: none !important;
  }

  .work > *:not(.work__endcap) {
    transform: none !important;
  }
}
