/*
  서비스 소개 페이지의 스타일 — 한국어 `service.html`과 영어 `service_en.html`이 **함께** 쓴다.

  한 벌로 두는 이유: 두 페이지에 같은 CSS를 복사해 두면 반드시 갈라진다. 이 저장소가 목업과
  앱 사이에서 이미 여러 번 겪은 일이고(web/build.mjs 주석), 여기서는 더 조용히 갈라진다 —
  한쪽만 고쳐도 둘 다 멀쩡히 서 있어서 알아챌 자리가 없다.
*/
/*
    토스의 서비스 소개 페이지(toss.im/service/…) 짜임이다. 랜딩 히어로와 다른 물건이라는 것이
    요점이다 — 히어로는 **붙잡는** 자리고 여기는 **읽는** 자리다. 그래서 카드도 상자도 없이
    구분선만 두고, 한 화면에 한 가지만 말한다.

    본 것 그대로: 작은 회색 라벨 → 아주 큰 제목(왼쪽 정렬) → 큰 그림 → 그 아래로
    [작은 태그 칩 + 굵은 제목 + 회색 설명 두어 줄 + 구분선]의 반복.
  */
  :root {
    --primary: #0B6CF2;
    --ink: #191F28;
    --muted: #6B7684;
    --bg: #FFFFFF;
    --line: #E5E8EB;
    --chip: #F2F4F6;
    --card: #FFFFFF;
    --shadow: 17, 24, 39;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --ink: #F2F4F6; --muted: #A3ADB8; --bg: #16191D; --line: #2A2F36; --chip: #1D2228;
      --card: #2A2F36; --shadow: 0, 0, 0;
    }
  }

  * { box-sizing: border-box; }

  /*
    **스냅은 걷었다**(사용자 지적: "공유 페이지 스크롤 내렸을 때 마우스포인터가 강제로 위로
    안 올라가면 더 좋겠다").

    한동안 `scroll-snap-type: y proximity`로 섹션마다 턱을 걸었다. `mandatory`가 아니라
    `proximity`니까 중간에서 손을 떼면 그 자리에 선다고 봤는데, 실제로 읽어 보면 그렇지가
    않다 — 섹션 머리 **가까이에서** 조금만 움직여도 도로 끌려 올라가고, 그건 읽던 사람에게
    고장으로 읽힌다. 읽는 페이지에서 스크롤은 손이 놓은 자리에 서야 한다.

    `scroll-margin-top`은 남겨 둔다. 스냅이 없어도 앵커로 들어온 자리가 sticky 머리줄
    아래로 숨는 것은 그대로라, 그 몫은 계속 필요하다.

    **값은 사용자가 기기에서 직접 맞춰 놓은 자리다.** 34 → 56 → 69px로 왔다. 34px일 때는
    머리줄(43px) 밑으로 섹션 제목이 9px 들어갔고, 56px은 숨지는 않았지만 붙어 보였다.
    69px에서 칩·제목·그림·설명·받기 버튼이 한 화면에 들어오면서 머리줄과도 벌어진다
    (사용자 지시: "내가 지금 맞추놓은 정도에 걸리게 해달라는거야" — 그때 잰 값이 69다).

    **이 값은 상자가 아니라 알맹이까지의 거리다.** 섹션은 위에 52px 패딩을 갖고 있어서
    (첫 섹션만 0) 상자 윗변을 맞추면 섹션마다 칩이 다른 자리에 선다 — 기기에서 첫 섹션은
    69px, 나머지는 121px이었다. 아래 스크립트가 이 값에서 패딩을 빼고 잰다(service.html).
    숫자를 양쪽에 적어 두면 반드시 갈라지므로, 서는 자리를 정하는 곳은 여기 하나다.
  */
  section { scroll-margin-top: 69px; }

  /*
    **다시 걸되, 올릴 때만 건다**(사용자 지적: "공유페이지 올릴 때, 지금처럼 턱턱 걸리게
    할 수 있음?").

    아침에 스냅을 통째로 걷은 것은 반만 맞았다. 성가셨던 것은 **내릴 때 도로 끌려 올라가는
    것**이고, 올릴 때 섹션 머리에 턱 서는 것은 오히려 원하던 바다 — 위로 올리는 사람은
    방금 지나온 섹션의 처음으로 돌아가려는 것이지 그 중간을 보려는 게 아니다.

    **CSS 스냅은 안 쓴다.** 처음엔 `scroll-snap-type`을 방향에 따라 붙였다 뗐다 했는데
    안 걸렸다(사용자 지적: "아직 안걸리는데?"). `proximity`는 **언제 걸지를 브라우저가**
    정하고, 손짓 도중에 값이 바뀌면 그 판단이 이미 끝난 뒤일 수 있다 — 우리가 방향을 알게
    되는 시점이 바로 그 도중이라, 구조적으로 늦는다.

    그래서 서는 자리는 service.html의 스크립트가 직접 정한다. 여기 남은 것은 그 자리를
    재는 자(`scroll-margin-top`)뿐이다.
  */
  body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont,
                 "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
    -webkit-font-smoothing: antialiased;
  }
  .wrap { max-width: 640px; margin: 0 auto; padding: 0 32px 120px; }

  /*
    **머리줄은 떠 있는다**(사용자 지시) — 토스의 서비스 페이지도 스크롤 내내 로고가 따라온다.
    긴 글을 읽다 보면 여기가 어느 회사 페이지인지 잊는데, 그때 다시 알려 주는 것이 이 줄이다.
    반투명 배경에 blur를 깔아 글이 밑으로 지나가는 것이 보이게 둔다.
  */
  .top {
    position: sticky; top: 0; z-index: 20;
    /* 로고와 글자 사이 8px — 앱 `NotiFoldWordmark`의 `spacedBy(8.dp)`와 같은 값이다. */
    display: flex; align-items: center; gap: 8px;
    /* 위아래는 14px에서 줄였다(사용자 지적: "제일 위 플로팅 영역... 너무 넓은 듯"). 이 띠는
       늘 떠 있어서 첫 화면에서 한 번만 자리를 먹는 게 아니라 **끝까지 따라다닌다** — 로고
       28px에 위아래 14px이면 56px이라, 읽는 내내 화면 위 6~8%를 물고 있었다. 10px이면 48px.
       로고는 그대로 두었다: 띠가 얇아진 만큼 로고가 오히려 또렷하게 선다. */
    margin: 0 -32px; padding: 10px 32px;
    background: color-mix(in srgb, var(--bg) 82%, transparent);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
  }
  /*
    **앱의 워드마크와 같은 값이다**(사용자 지적: "우리 앱에 있는 글씨크기+로고랑 다를껄").
    웹은 아이콘 28px에 글자 17px이었는데 앱(`NotiFoldWordmark`)은 아이콘 23dp에 글자 20sp라,
    둘이 정반대였다 — 웹은 아이콘이 크고 글자가 작아 그림표처럼, 앱은 글자가 커서 이름처럼
    읽혔다. 같은 로고가 두 얼굴이면 어느 쪽도 기억에 안 남는다.

      아이콘 23px / 모서리 6.5px / 사이 8px / 글자 20px — 앱의 dp·sp를 그대로 px으로 옮겼다.

    자간(-0.9sp)과 Noti–Fold 사이(1.65dp)도 앱 값이다. 뒤엣것은 "붙어 보인다"고 벌렸다가
    "두 낱말로 읽힌다"고 절반으로 되돌린 값이라(사용자 지시), 여기서 다시 정하지 않는다.

    **굵기만 앱과 다르게 700이다**(사용자 지적: "보통 앱 이름 글씨를 저렇게 굵게하나?").
    앱 코드는 780이라 적혀 있지만 Pretendard를 정적 다섯 벌로만 싣기 때문에 780짜리 낯이
    없고, 안드로이드가 위쪽으로 붙여 **실제로는 800(ExtraBold)으로 그려진다.** 20px짜리
    이름에 ExtraBold는 소리를 지르는 쪽이고, 이 로고는 이미 색이 Noti와 Fold를 갈라 주고
    있어서 굵기까지 일할 자리가 없다. 앱도 같이 700으로 내렸다.
  */
  .top img { width: 23px; height: 23px; border-radius: 6.5px; }
  .top b { font-size: 20px; font-weight: 700; letter-spacing: -0.045em; }
  .top b span { color: var(--primary); margin-left: 0.0825em; }
  /*
    워드마크가 소개 페이지로 돌아가는 길이다. 이 페이지는 거기 머리글의 '자세히 보기'로
    들어오는 자리라, 되돌아갈 문이 없으면 뒤로가기 말고는 나갈 데가 없다. 별도 링크를
    한 줄 더 두는 대신 로고에 맡긴다 — 로고를 누르면 처음으로 간다는 것은 이미 아는 규칙이다.
  */
  .home { display: flex; align-items: center; gap: 10px; color: inherit; text-decoration: none; }
  .home:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; border-radius: 8px; }

  /*
    토스는 이 자리에 전체 메뉴(햄버거)를 둔다. 우리는 페이지가 이것 하나뿐이라 메뉴를 열 곳이
    없고, 대신 **공유**가 그 자리를 받는다(사용자 지시) — 이 페이지가 하는 일이 결국 남에게
    보여 주는 것이라, 오른쪽 위에서 가장 쓸모 있는 버튼이다.
  */
  /*
    **아이콘이 그림의 오른쪽 선에 붙는다**(사용자 지시: "샘플이미지 오른쪽에서 올라간 가상의
    선이 공유 아이콘에 붙도록"). 상자를 맞추는 것과 눈에 보이는 것을 맞추는 것은 다르다 —
    버튼은 40px 원인데 그 안의 아이콘은 22px이고, 그리는 점은 그보다 더 안쪽이다. 기기에서
    재 보니 버튼의 오른쪽 끝은 328px로 그림과 같은데 **보이는 획은 317px에서 끝났다.**
    그 11px이 어긋나 보이던 값이다. 상자를 그만큼 밖으로 물려 획을 선에 붙인다 — 누르는
    자리는 그대로 40px이다.
  */
  .share {
    margin-left: auto;
    margin-right: -11px;
    display: grid; place-items: center;
    width: 40px; height: 40px;
    border: 0; border-radius: 50%;
    background: transparent; color: var(--ink);
    cursor: pointer;
  }
  .share svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
  .share:active { background: var(--chip); }

  /*
    **받기는 넓은 화면에서만 머리줄에 선다**(사용자 지시). 폰에서는 바닥에 붙은 바가 그 일을
    하고 있고(엄지가 거기 있다), 마우스로 보는 화면에서는 그 바가 1440px을 가로지르는 흰 띠가
    되어 자리만 먹는다. 늘 떠 있는 머리줄이 그 몫을 대신 받는다.
  */
  /*
    제목 위 작은 라벨('알림 정리')은 뺐다(사용자 지시) — 바로 아래 제목이 같은 말을 더 크게
    하고 있어서, 라벨이 한 줄 먼저 읽히는 만큼 제목이 늦게 읽혔다. 라벨이 갖고 있던 위 여백은
    제목이 그대로 받는다.
  */
  h1 {
    /* 아래 여백은 40px에서 줄였다(사용자 지적: "아래 그림 사이 간격 조금만 줄여줘").
       제목과 그림이 한 장면이라 사이가 뜨면 둘이 따로 읽힌다.

       셋째 줄이 제목 안으로 들어왔으므로 아래 여백은 다시 여기서 낸다.

       위 여백은 26px에서 줄였다(사용자 지적: "쏟아지는 알림 ~ 노티폴드 아이콘 간 간격
       줄여줘. 너무 넓다"). 머리줄이 이미 아래로 14px을 내므로 로고와 제목 사이가 40px이었다 —
       라벨을 뺄 때 그 여백까지 제목이 물려받은 것이 여기서 겹쳤다.

       한 번 14px까지 내렸다가 20px로 되돌렸는데, 그건 **잘못 되돌린 것이었다.** "너무 짤랐다"는
       말을 이 여백 얘기로 읽었지만 실은 상자가 그림을 자르고 있다는 말이었고, 20px로 올려
       놓으니 사용자가 폰에서 이 자리를 노랗게 칠해 보냈다. 그래서 12px이다 — 머리줄이 아래로
       10px을 내므로 로고와 제목 사이는 22px이고, 눈으로 보이는 것은 글줄 여유까지 26px쯤이다.
       화면에서 잰 이전 값은 38px이었다. 12px에서 8px로 한 번 더 내렸다(같은 지적) — 로고를
       키운 것과 한 벌이다. 띠 아래는 18px이 남고, 로고가 커진 만큼 빈 자리로 안 읽힌다. */
    margin: 8px 0 28px;
    /* 바닥만 30px에서 낮췄다. 320px 같은 좁은 폰에서 30px이 걸리면 셋째 줄
       (`NotiFold로 정리하세요`)이 넘어가 **세 줄이 네 줄이 된다.** 360px 이상에서는
       8.2vw가 이미 24px보다 크므로 아무것도 달라지지 않는다. */
    font-size: clamp(24px, 8.2vw, 46px);
    font-weight: 800;
    line-height: 1.34;
    letter-spacing: -0.035em;
  }

  /*
    **제목은 세 줄이다**(사용자 지시: "이거 3줄로 해줘"). 셋째 줄은 따로 선 문단이 아니라
    제목의 마지막 줄이다 — 앞의 두 줄이 겪는 일을 말하고 이 줄이 그래서 무엇을 하면 되는지를
    말하므로, 한 문장으로 이어져야 그 전환이 읽힌다. 그래서 마침표도 없다.
    (한때 작은 회색 문단이었는데, 그러면 제목이 끝난 뒤에 덧붙인 설명으로 읽혔다.)

    **색은 앞 두 줄과 같다**(사용자 지시: "검은색 글자로"). 한때 파랑이었는데, 그러면 셋이
    한 덩이로 서지 못하고 마지막 줄만 버튼처럼 도드라졌다. 전환은 색이 아니라 **줄 사이의
    숨**으로 말한다 — 그래서 이 줄만 위를 조금 더 띄운다(사용자 지시: "않게하고 노티폴드
    사이에 줄 살~~짝만 더 띄자"). `<br>` 대신 블록으로 세우는 이유가 그것이다: 인라인
    줄바꿈에는 여백을 줄 자리가 없다.
  */
  .hero-turn {
    /*
      **좁은 화면에서는 없다**(사용자 지시: "모바일 버전에서는 notifold로정리하세요. 빼자").
      폰에서는 제목 바로 아래 붙는 바가 이미 `Google Play에서 받기`라고 말한다 — 같은 말을
      두 번 하는 셈이고, 세로가 귀한 화면에서 한 줄이 그냥 위로 밀어낸다. 넓은 화면에는
      그 바가 화면 끝까지 안 보이므로 이 줄이 제 몫을 한다.
    */
    display: none;
    margin-top: 0.22em;
    /*
      셋째 줄만 살짝 작다(0.92em). 앞의 두 줄보다 **길어서** 그렇다 — 좁은 폰에서 이 줄만
      다음 줄로 넘어가면 세 줄이 네 줄이 되고, 그걸 막자고 제목 전체를 줄이면 짧은 두 줄까지
      같이 작아진다. 자간을 조금 더 조이는 것도 같은 이유다(`NotiFold`가 라틴이라 넓다).
      한 덩이로 읽히는 데는 이 정도 차이가 방해되지 않는다.
    */
    letter-spacing: -0.035em;
  }

  /*
    **가운데 정렬**(사용자 지시). 토스 원본은 왼쪽 정렬이지만 우리 제목은 두 줄이 `<br>`로
    이미 갈라져 있어서, 가운데로 세우면 두 줄이 축을 맞춰 한 덩이로 읽힌다.

    한 줄로 끝내는 이유: 태그 칩은 `inline-block`이라 이 규칙만으로 함께 가운데에 서고,
    조각(`.cut`)과 받기 버튼(`.cta`)은 폭을 꽉 채우거나 스스로 가운데라 영향을 받지 않는다.
    머리줄(`.top`)은 flex라 여기 딸려 오지 않는다 — 로고는 왼쪽, 공유는 오른쪽 그대로다.
  */
  h1, section { text-align: left; }

  /*
    큰 자리 — **알림이 쏟아지고, 한 줄로 선다.** 영상이 아니라 페이지가 그린다.

    스톡을 세 번 뒤졌지만 "쏟아지는 알림"은 없었다. 있는 것은 전부 *폰을 든 사람*이다
    (Pexels 후보 열셋을 프레임까지 확인했다). 알림이 우수수 쌓이는 그림은 화면 녹화가
    있어야 나오는데, 그러면 다시 우리 화면이고 히어로 하나 때문에 매번 폰을 꽂아야 한다.

    그래서 여기서 직접 그린다. 0MB고, 어느 해상도에서도 선명하고, 파는 이야기가 그대로
    담긴다 — **쏟아진다 → 제자리에 선다.** 남의 폰도 아니다.

    카드 여섯이 같은 타임라인을 돌되 `--i`만큼 늦게 출발한다. 그래서 쏟아지는 것도
    정리되는 것도 한 장씩 일어난다. 흩어진 자리는 `--sx/--sy/--sr`, 정리된 자리는 `--fy`다.
  */
  .shot {
    position: relative;
    /*
      **폭은 글줄과 같다.** `width`를 적지 않으면 `aspect-ratio`와 `max-height`가 만나 브라우저가
      *폭*을 줄여 버린다 — PC에서 상자가 글 기둥보다 150px 좁게 서서 오른쪽이 비었다(사용자 지적).
      폭을 못 박으면 비율만 눌리고 좌우는 제목·본문과 한 줄로 맞는다.
    */
    width: 100%;
    /* 아래 여백은 64px에서 줄였다(사용자 지적: "저 박스하고 구글 플레이에서 받기 간격도
       넓자나.. 조금 더 줄여"). 받기 바가 fixed라 이 여백의 아랫부분은 바 밑으로 들어가지만,
       바 위로 보이는 만큼은 그대로 상자와 버튼 사이의 숨이다. */
    margin: 0 0 44px;
    border-radius: 24px;
    overflow: hidden;
    background: var(--chip);
    aspect-ratio: 9 / 13;
    /*
      **첫 화면 안에 다 들어와야 한다**(사용자 지적: "주요 내용들이 한 화면에 들어가게 가능하나?
      지금 폰에서 보면 110% 정도로 넘치게 보여서").

      넘친 값의 정체: 이 상자 위로 머리줄(56px)과 제목 덩이(약 140px)가 있고, 아래에는 받기
      바(`.act`, fixed)가 110px쯤을 덮는다. 셋을 더하면 폰에서 306px이라 68vh만으로는 화면을
      넘긴다 — 게다가 사파리 주소창이 100px을 더 먹는다.

      그래서 **`svh`로 잰다.** `vh`는 주소창이 접힌 큰 화면 기준이라, 처음 열었을 때는 늘
      실제보다 크게 잡힌다. `svh`가 주소창이 펴진 작은 쪽이고, 첫 화면이 들어가야 하는 것은
      바로 그 상태다.

      `min()`인 것은 큰 화면에서 상자가 제멋대로 커지지 않게 하려는 것이다 — 68vh는 그대로 상한.

      빼는 값은 316px에서 274px로 낮췄다. 제목 위(-14px), 상자 아래(-20px), 머리줄 위아래
      (-8px)를 줄여 그만큼 상자가 아닌 자리가 줄었으므로, 같은 화면에서 상자는 그만큼 더
      설 수 있다.
    */
    max-height: min(68vh, calc(100svh - 274px));
    /*
      **그림보다 작아지면 안 된다**(사용자 지적: "너무 짤랐다"). 위 상한만 걸어 두었더니
      짧은 폰에서 상자가 그림보다 낮아져 **NotiFold 칩이 반으로 잘리고 맨 위 카드도
      잘렸다.** 안의 그림은 뷰포트를 안 따라간다 — 카드는 가운데에서 `--fy`만큼, 칩은
      `--sink`만큼 떨어진 **고정 픽셀**이라, 상자만 눌리면 `overflow: hidden`이 그대로 자른다.

      칩 아래끝이 가운데+149px, 맨 위 카드 위끝이 가운데-156px이니 그림은 305px이고, 위아래
      숨 8px씩을 더해 321px이 바닥이다. 다만 그 바닥은 [--k]만큼 같이 줄어든다 — 아래 참조.
    */
    min-height: calc(321px * var(--k));
  }

  /*
    **그림이 화면을 따라 줄어든다.**

    한동안 바닥(`min-height: 321px`)만 깔아 두었다. 잘리지는 않았지만 화면이 짧으면 상자가
    바닥값까지 버티면서 **받기 바 밑으로 들어갔고**, 그 바가 fixed라 아래 카드 한 장과 칩을
    통째로 덮었다. 실제 폰 뷰포트(412×580)로 그려 보고 알았다 — 잘린 게 아니라 가려진 것이다.

    사용자가 먼저 짚은 문제이기도 하다: "이렇게 해도 s26+ 말고 다른 데 가면 짤려 보이잖아."
    맞는 말이었다. **그림이 픽셀이고 상자가 비율인 한** 어느 화면에서는 반드시 부딪힌다.
    여백을 몇 px씩 깎는 것으로는 화면 하나를 넘길 뿐이고, 다음 폰에서 또 만난다.

    그래서 그림을 상자에 맞춘다. `.pour` 전체를 `--k`만큼 축소하면 카드도 칩도 사이 간격도
    한 벌로 줄어서, 짧은 화면에서는 **작게, 그러나 온전히** 보인다.

    값은 짐작이 아니라 계산이다. 상자가 쓸 수 있는 높이는 `100svh - 274px`이고 그림은 305px에
    위아래 숨 20px씩이 필요하므로, 각 칸의 **아래끝**에서 `k = (vh - 274 - 40) / 305`를 풀어
    한 단 낮춰 잡았다. 뷰포트 높이로 재는 것은 `svh`를 미디어 쿼리에서 못 쓰기 때문인데,
    안드로이드 크롬은 페이지를 열 때 주소창을 편 상태라 둘이 사실상 같은 값이다.

    단이 진 것(연속 함수가 아닌 것)은 CSS가 길이를 길이로 나누지 못해서다 —
    `calc(100cqh / 305px)`는 숫자가 아니라 오류다. 컨테이너 쿼리 단위를 `tan(atan2())`로
    숫자로 바꾸는 길이 있긴 하지만, 다섯 줄 짜리 사다리가 읽기도 고치기도 낫다.
  */
  .shot { --k: 1; }
  @media (max-height: 620px) { .shot { --k: 0.86; } }
  @media (max-height: 580px) { .shot { --k: 0.74; } }
  @media (max-height: 540px) { .shot { --k: 0.61; } }
  @media (max-height: 500px) { .shot { --k: 0.55; } }

  /*
    흩어지는 폭(`--sx`)은 **상자 폭을 따른다.** 카드는 좌우 7%를 비우고 서므로, 상자가 좁으면
    그 7%가 흩어짐(최대 28px)보다 작아져 카드가 모서리에서 잘린다 — 좌우가 서로 다르게 잘려
    여백이 안 맞아 보인다(사용자 지적).

    그래서 기본은 절반이고, 상자가 496~576px로 넓어지는 **가운데 폭에서만** 제 값을 쓴다.
    넓은 화면에서는 히어로가 [글 | 화면] 두 칸이 되어 상자가 도로 420px이라, 거기서도 절반이
    맞다 — 뷰포트가 아니라 **상자**를 따라가는 것이 요점이다.
  */
  .pour {
    /*
      그림 한 벌을 통째로 줄인다 — 카드 높이도, 글자도, 그 사이 간격도 같은 비율로.
      `.shot`이 정하는 [--k]에 대해서는 그쪽 주석을 볼 것.

      **그런데 가로까지 줄면 안 된다.** 그냥 `inset: 0`에 `scale`만 걸었더니 카드가 좌우로도
      줄어 넓은 회색 상자 한가운데에 작은 카드 넉 장이 떠 있었다 — 알림창이 아니라 조각상이다.

      그래서 먼저 `1/k`만큼 **키워 놓고** `k`로 줄인다. 좌상단을 축으로 잡으면 겉넓이는
      정확히 상자 그대로이고, 안에서만 좌표가 `k`배로 눌린다. 카드는 여전히 상자 폭의
      86%를 쓰고(좌우 7%씩), 줄어드는 것은 세로 간격과 글자뿐이다.
    */
    position: absolute; top: 0; left: 0;
    width: calc(100% / var(--k, 1));
    height: calc(100% / var(--k, 1));
    transform: scale(var(--k, 1));
    transform-origin: 0 0;
    --spread: 0.5;
    /*
      정리 알약이 서는 자리이자, 접히는 카드가 빨려 들어가는 자리다. 둘이 **같은 값**을 봐야
      카드가 알약 위로 정확히 접힌다 — 따로 적어 두면 한쪽만 고쳐져 어긋난다.
      200px에서 내린 이유: 폰에서 알약이 상자 바닥에 붙어 보였다(사용자 지적).

      148px에서 한 번 더 내렸다(사용자 지적: "쏟아지는 알림 하고 노티폴드 아이콘 사이 간격을
      줄여주고"). 마지막 카드 아래끝이 가운데+96px이라 알약 위끝과 35px이 떠 있었는데, 그만큼
      뜨면 알약이 카드 더미에 딸린 꼬리가 아니라 **따로 선 다른 것**으로 읽힌다. 132px이면
      19px — 카드끼리의 간격(12px)보다는 넓어서 묶음의 끝인 줄은 알아보되, 한 덩이로 붙는다.
    */
    --sink: 132px;
  }
  @media (min-width: 561px) and (max-width: 999px) { .pour { --spread: 1; } }
  .pour-card {
    position: absolute;
    left: 7%;
    right: 7%;
    top: 50%;
    margin-top: -30px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 14px;
    background: var(--card);
    box-shadow: 0 6px 20px rgba(var(--shadow), 0.13);
    animation: pour 4.4s linear infinite both;
    /*
      **고른 간격은 비가 아니라 메트로놈이다.** 예전에는 `--i * 0.095s`로 아홉 장을 똑같이
      95ms씩 떨어뜨렸는데, 그러면 또르르 흘러내리는 한 줄로 읽힌다(사용자 지적: "좀 더
      투투둑 떨어지는 느낌으로"). 지금은 카드마다 제 `--lag`을 들고 셋씩 뭉쳐 온다 —
      투툭 … 투툭 … 투투둑. 뭉치 사이가 벌어져야 각 뭉치가 **한 번의 소리**로 들린다.

      박자를 여기서 정하지 않고 카드가 들고 오는 이유는, 그 값이 흩어질 자리(`--sx/--sy`)와
      한 벌이기 때문이다 — 위쪽에 설 카드가 먼저 닿아야 쏟아지는 방향이 보인다.
    */
    animation-delay: var(--lag, 0s);
    will-change: transform, opacity;
  }
  .pour-mark {
    flex: none;
    width: 34px; height: 34px;
    border-radius: 10px;
    background: var(--mark);
    /* 로고는 제 그림이 있으므로 색은 뒤로 물러나 받침이 된다 — 투명한 가장자리가
       있는 아이콘도 카드 위에서 같은 사각형으로 선다. */
    object-fit: cover;
  }
  .pour-copy { min-width: 0; flex: 1; }
  .pour-app {
    display: block;
    font-size: 12.5px; font-weight: 700; color: var(--ink);
    letter-spacing: -0.02em;
  }
  /* 스팬끼리는 쌓이지 않는다 — block이 없으면 "카카오톡민아님이 선물을"로 붙는다. */
  .pour-text {
    display: block;
    margin-top: 2px;
    font-size: 12px; color: var(--muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .pour-time { flex: none; font-size: 11px; color: var(--muted); }

  /*
    **떨어지는 것과 정리되는 것은 다른 곡선을 쓴다.** 한 벌의 ease-out을 통째로 걸면 카드가
    도착하면서 느려져 사뿐히 내려앉는다 — 쏟아지는 것이 아니라 내려오는 것이다. 그래서
    구간마다 곡선을 갈아 끼운다(`animation-timing-function`은 그 키프레임에서 **다음**
    키프레임까지에 걸린다).

      떨어질 때  가속(ease-in)  — 중력. 끝에서 가장 빠르고, 그래서 닿는 순간이 생긴다.
      닿을 때    한 번 눌린다   — 세로로 짜부라지며 목표를 살짝 지나친다.
      튈 때      되돌아온다     — 위로 조금 넘겼다가 제자리. 이 셋이 '툭' 하나다.
      정리될 때  감속(ease-out) — 여기는 물리가 아니라 앱이 하는 일이라 곡선이 부드럽다.
  */
  @keyframes pour {
    /* 위에서 떨어진다 — 가속이라 화면 위쪽에서는 거의 안 보이고 아래에서 확 온다 */
    0%   { opacity: 0; transform: translate(0, var(--dy, -280px)) rotate(var(--sr)) scale(0.96);
           animation-timing-function: cubic-bezier(0.55, 0.09, 0.68, 0.53); }
    4%   { opacity: 1; }
    /* 닿는다 — 세로로 눌리고 6px 지나친다. 흩어짐도 아직 덜 벌어져 있다 */
    9%   { transform: translate(calc(var(--sx) * var(--spread) * 0.88), calc(var(--sy) + 6px))
                      rotate(var(--sr)) scale(1.035, 0.93);
           animation-timing-function: cubic-bezier(0.33, 0.9, 0.4, 1); }
    /* 튄다 — 5px 위로 넘겼다가 */
    14%  { transform: translate(calc(var(--sx) * var(--spread)), calc(var(--sy) - 5px))
                      rotate(var(--sr)) scale(0.99, 1.03); }
    /* 흩어진 채로 쌓인다 — 여기가 '쏟아진' 상태다 */
    20%  { transform: translate(calc(var(--sx) * var(--spread)), var(--sy)) rotate(var(--sr)) scale(1);
           animation-timing-function: linear; }
    50%  { transform: translate(calc(var(--sx) * var(--spread)), var(--sy)) rotate(var(--sr)) scale(1);
           animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1); }
    /* 제자리로 선다 */
    70%  { transform: translate(0, var(--fy)) rotate(0deg) scale(1); }
    90%  { opacity: 1; transform: translate(0, var(--fy)) rotate(0deg) scale(1); }
    /* 제자리에서 조용히 흐려진다 — 아래로 딸려 가면 이 넷도 치워진 것으로 보인다. */
    100% { opacity: 0; transform: translate(0, var(--fy)) rotate(0deg) scale(0.99); }
  }

  /*
    **몇 장은 줄에 서지 않고 NotiFold 안으로 들어간다**(사용자 지시: "몇 개 사라지고
    노티폴드로 숨겨지는 느낌"). 고른 둘은 Netflix 새 회차와 광고다 — 지금 당장 볼 일이
    아니어서 우리가 대신 받아 두는 쪽이고, 바로 아래 글이 "광고 알림만 숨길 수도 있어요"라고
    말하는 그 둘이다.

    쏟아지고 흩어지는 데까지는 나머지와 똑같이 간다 — 거기서 갈라져야 **골라낸 것**으로
    읽힌다. 처음부터 다르게 움직이면 그냥 다른 카드다.
  */
  .pour-card.tuck { animation-name: pourTuck; }

  @keyframes pourTuck {
    0%   { opacity: 0; transform: translate(0, var(--dy, -280px)) rotate(var(--sr)) scale(0.96);
           animation-timing-function: cubic-bezier(0.55, 0.09, 0.68, 0.53); }
    4%   { opacity: 1; }
    9%   { transform: translate(calc(var(--sx) * var(--spread) * 0.88), calc(var(--sy) + 6px))
                      rotate(var(--sr)) scale(1.035, 0.93);
           animation-timing-function: cubic-bezier(0.33, 0.9, 0.4, 1); }
    14%  { transform: translate(calc(var(--sx) * var(--spread)), calc(var(--sy) - 5px))
                      rotate(var(--sr)) scale(0.99, 1.03); }
    20%  { transform: translate(calc(var(--sx) * var(--spread)), var(--sy)) rotate(var(--sr)) scale(1);
           animation-timing-function: linear; }
    54%  { opacity: 1; transform: translate(calc(var(--sx) * var(--spread)), var(--sy)) rotate(var(--sr)) scale(1);
           animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1); }
    /* 줄을 서는 대신 아래 한 점으로 — 접히는 것이지 지워지는 것이 아니라서 끝까지
       작아졌다가 사라진다(툭 꺼지면 삭제로 읽힌다). */
    64%  { opacity: 0; transform: translate(0, var(--sink)) rotate(0deg) scale(0.22); }
    100% { opacity: 0; transform: translate(0, var(--sink)) rotate(0deg) scale(0.22); }
  }

  /*
    받는 자리. 카드가 그냥 사라지면 "없어졌다"로 읽힌다 — 가져가는 쪽이 화면에 있어야
    "치워 뒀다"가 된다. 두 장이 도착하는 순간에만 살짝 부푼다.
  */
  .pour-sink {
    position: absolute;
    left: 50%;
    top: calc(50% + var(--sink));
    display: flex; align-items: center; gap: 8px;
    padding: 7px 13px 7px 8px;
    border-radius: 999px;
    background: var(--card);
    box-shadow: 0 6px 18px rgba(var(--shadow), 0.16);
    white-space: nowrap;
    transform: translate(-50%, -50%);
    animation: sinkIn 4.4s cubic-bezier(0.22, 0.61, 0.36, 1) infinite both;
  }
  .pour-sink img { width: 24px; height: 24px; border-radius: 8px; }
  .pour-sink span { font-size: 12px; font-weight: 700; color: var(--muted); letter-spacing: -0.02em; }

  /*
    **떨어지는 동안에는 없다.** 두 장이 사라진 **뒤에** 나타나야 그 둘이 어디로 갔는지가
    읽힌다(사용자 지적) — 처음부터 서 있으면 그냥 배경의 한 조각이고, 카드가 사라진 것과
    이어지지 않는다. 카드가 다 접힌 68%에 맞춰 톡 튀어나왔다가 줄과 함께 사라진다.
  */
  @keyframes sinkIn {
    0%, 52% { opacity: 0; transform: translate(-50%, -50%) scale(0.86); }
    64%     { opacity: 1; transform: translate(-50%, -50%) scale(1.08); }
    72%     { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    90%     { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    100%    { opacity: 0; transform: translate(-50%, -50%) scale(1); }
  }

  /*
    움직임을 줄여 달라고 한 사람에게는 **정리된 끝 상태**를 보여준다 — 애니메이션의 결론이
    거기라, 멈춘 그림 하나로도 말이 된다.
  */
  @media (prefers-reduced-motion: reduce) {
    .pour-card {
      animation: none;
      transform: translate(0, var(--fy));
    }
    /* 끝 상태에서 이 둘은 이미 치워진 뒤다 — 남겨 두면 정리가 안 된 그림이 된다. */
    .pour-card.tuck { display: none; }
    .pour-sink { animation: none; }
  }

  /*
    섹션의 앱 화면 조각 — 토스가 하는 그대로 **카드 한두 장만 오려서 크게** 쓴다.
    화면 전체를 줄여 넣으면 글씨가 작아 무슨 앱인지 안 보인다.

    자리는 제목과 설명 **사이**다(toss.im/service/asset-management 모바일 확인:
    번호 칩 → 큰 제목 → 그림 → 설명). 그림이 제목을 받고, 설명이 그림을 풀어 준다.

    조각은 목업을 폭 420px로 띄워 뜬 것이라(그 폭이면 베젤 없이 전체 화면으로 그려진다)
    카드가 화면 폭을 꽉 채운다. 원본 1184px = 페이지에서 그려지는 592px의 두 배다.
  */
  .cut {
    /* 제목과 그림 사이가 좁았다(사용자 지적) — 제목이 그림 위에 얹힌 것처럼 붙어 보였다.
       아래보다 위를 더 벌린다: 위는 제목과 갈라서는 자리고, 아래는 설명으로 이어지는 자리다. */
    margin: 24px 0 26px;
    border: 1px solid var(--line);
    border-radius: 20px;
    overflow: hidden;
    background: var(--chip);
  }
  .cut img { display: block; width: 100%; height: auto; }

  /*
    **누르면 열린다.** 정지 조각 대신, 그 화면에서 실제로 일어나는 동작 하나를 보여준다
    (사용자 지시: "택배에선 클릭하면 배송 현황 보여주는거", "화면 전환 느낌은 예전 아이폰
    광고처럼"). 그 광고가 늘 하던 짓이 이것이다 — 손가락이 한 번 닿고, 다음 화면이 밀려 온다.

    두 장 다 **목업에서 그대로 뜬 화면**이다(mockup/_shot.html이 화면을 띄우고 눌러서 찍는다).
    손으로 그린 그림이 아니라, 앱이 바뀌면 다시 찍기만 하면 된다.

    영상이 아니라 PNG 두 장과 CSS인 것이 요점이다: 자동재생 정책도, 데이터도, 로딩도 없다.

    전환은 앱이 실제로 하는 것을 따른다 — 대화는 **옆에서 밀려 들어오고**(push), 배송 조회는
    **아래에서 올라온다**(sheet). 여기서 멋을 부려 다른 전환을 쓰면 앱을 처음 열었을 때
    "그 화면이 아닌데"가 된다.
  */
  .play {
    position: relative;
    margin: 24px 0 26px;
    border: 1px solid var(--line);
    border-radius: 20px;
    overflow: hidden;
    background: var(--chip);
    /*
      **조각을 뜬 창 크기 그대로**여야 한다 — 여기가 어긋나면 `object-fit: cover`가 남는 쪽을
      잘라내서, 마지막 카드가 글자 한복판에서 끊긴다(사용자 지적: "쇼핑/배송 이에 카드 잘리네").

      그런데 실제로 잘린 이유는 CSS가 아니라 **조각 자체가 그렇게 찍혀 있었기** 때문이다.
      420x500 창에 맞춰 뜨다 보니 아래쪽 카드가 창 높이에서 두 동강 났다. 지금은 반대로
      한다: 목록에서 **카드와 카드 사이 빈틈**을 찾아 거기서 끊고, 나온 높이를 여기에 적는다.
      그래서 화면마다 값이 다르다 — 카드 높이가 다르니 빈틈이 오는 자리도 다르다.
    */
    aspect-ratio: var(--ar, 420 / 500);
  }
  .play img {
    position: absolute; inset: 0;
    display: block; width: 100%; height: 100%;
    object-fit: cover;
    will-change: transform;
  }

  .play-base { animation: playUnder 6.4s cubic-bezier(0.32, 0.72, 0, 1) infinite both; }
  .play-over { animation: playPush 6.4s cubic-bezier(0.32, 0.72, 0, 1) infinite both; }
  /*
    밀려 들어오는 화면의 앞머리 그림자다. 대기 자리를 100%가 아니라 **120%**로 미는 이유가
    이것 때문이다 — 딱 100%면 화면은 나가 있어도 그 그림자(왼쪽으로 16+34px)가 상자 안으로
    남아, 오른쪽 가장자리가 늘 어둡게 보인다(사용자 지적).
  */
  .play.push .play-over { box-shadow: -16px 0 34px rgba(var(--shadow), 0.2); }

  /*
    시트 쪽은 **뒤 화면이 그대로 서 있는다.** 아래에서 시트가 올라오는 동안 목록까지 밀리면
    화면이 통째로 바뀐 것으로 읽힌다 — 시트는 지금 화면 위에 얹히는 것이다.

    `clip-path`가 시트만 남긴다: 찍은 그림에는 어두워진 목록이 함께 들어 있는데, 그 부분을
    잘라내고 흐림은 아래 `.play-dim`이 따로 깐다. 그래야 시트만 밀어 올릴 수 있다.
  */
  .play.sheet .play-base { animation: none; }
  /* 42.6% → 43.9%: 조각을 다시 뜨면서 상자가 500에서 512로 높아졌다. 이 값은 **시트의 윗변**이라
     조각이 바뀔 때마다 다시 재야 한다 — 어긋나면 시트 위로 목록 한 조각이 함께 밀려 올라온다. */
  .play.sheet .play-over { animation-name: playSheet; clip-path: inset(43.9% 0 0 0); }
  .play-dim {
    position: absolute; inset: 0;
    background: rgba(15, 23, 32, 0.34);
    opacity: 0;
    animation: playDim 6.4s cubic-bezier(0.32, 0.72, 0, 1) infinite both;
  }

  /* 손가락이 닿은 자리. 카드 위 어디를 눌렀는지는 `--tx/--ty`가 정한다. */
  .play-tap {
    position: absolute;
    left: var(--tx); top: var(--ty);
    width: 38px; height: 38px; margin: -19px 0 0 -19px;
    border-radius: 50%;
    background: rgba(11, 108, 242, 0.22);
    box-shadow: inset 0 0 0 2px rgba(11, 108, 242, 0.42);
    opacity: 0;
    animation: playTap 6.4s ease-out infinite both;
  }

  @keyframes playUnder {
    0%, 18%   { transform: translateX(0); }
    30%, 80%  { transform: translateX(-22%); }
    92%, 100% { transform: translateX(0); }
  }
  @keyframes playPush {
    0%, 18%   { transform: translateX(120%); }
    30%, 80%  { transform: translateX(0); }
    92%, 100% { transform: translateX(120%); }
  }
  @keyframes playSheet {
    0%, 18%   { transform: translateY(100%); }
    30%, 80%  { transform: translateY(0); }
    92%, 100% { transform: translateY(100%); }
  }
  @keyframes playDim {
    0%, 18%   { opacity: 0; }
    30%, 80%  { opacity: 1; }
    92%, 100% { opacity: 0; }
  }
  @keyframes playTap {
    0%, 8%   { opacity: 0; transform: scale(0.55); }
    13%      { opacity: 1; transform: scale(1); }
    22%      { opacity: 0; transform: scale(1.6); }
    100%     { opacity: 0; transform: scale(1.6); }
  }

  /* 움직임을 줄여 달라고 한 사람에게는 **열린 뒤**를 보여준다 — 쏟아지는 알림과 같은 규칙이다. */
  @media (prefers-reduced-motion: reduce) {
    .play-base, .play-over, .play-dim { animation: none; }
    .play-over { transform: none; }
    .play-dim { opacity: 1; }
    .play-tap { display: none; }
  }

  /*
    **줄은 없앤다**(사용자 지시). 섹션을 가르는 것은 이제 여백뿐이다 — 태그 칩과 큰 제목이
    이미 "여기서부터 다른 이야기"라고 말하고 있어서, 그 위에 선까지 그으면 말이 겹친다.
    선이 하던 몫은 위아래 여백이 받는다(40 → 52px).
  */
  section { padding: 52px 0; }
  section:first-of-type { padding-top: 0; }

  .tag {
    display: inline-block;
    margin: 0 0 18px;
    padding: 7px 14px;
    border: 1px solid var(--line);
    border-radius: 10px;
    font-size: 14px;
    font-weight: 700;
    color: var(--primary);
  }
  /* 손해/이득처럼 결이 다른 태그는 색으로 가른다. 여기서는 '보안'이 그 자리다
     (영어판은 'Privacy'). 클래스 이름 `guard`는 그대로 둔다 — 라벨만 바뀌었고,
     이름을 따라 고치면 영어판 HTML까지 함께 고쳐야 한다. */
  .tag.guard { color: #E0483E; }

  /*
    방침 카드 — 앱 화면 조각들 사이에 서지만 **이것만 진짜 글이다.** 그래서 다크 모드에서도
    따라오고(스크린샷 다섯은 못 한다), 확대해도 안 뭉갠다. 색은 전부 페이지 토큰이다.
  */
  .policy {
    margin: 24px 0 26px;
    padding: 18px 16px;
    border: 1px solid var(--line);
    border-radius: 20px;
    background: var(--chip);
  }
  .policy-head {
    display: flex; align-items: center; gap: 10px;
    margin: 0 0 12px;
    font-size: 18px; font-weight: 800; letter-spacing: -0.03em;
  }
  .policy-mark {
    flex: none; display: grid; place-items: center;
    width: 30px; height: 30px; border-radius: 10px;
    background: color-mix(in srgb, #E0483E 14%, var(--bg));
  }
  .policy-mark svg {
    width: 15px; height: 15px;
    fill: none; stroke: #E0483E; stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round;
  }
  .policy-body {
    padding: 14px 16px;
    border-radius: 16px;
    background: var(--card);
    font-size: 15px; line-height: 1.55; letter-spacing: -0.01em;
    color: var(--ink);
  }
  .policy-body b { font-weight: 700; }

  h2 { margin: 0 0 16px; font-size: clamp(22px, 5.6vw, 28px); font-weight: 800; letter-spacing: -0.03em; line-height: 1.36; }
  section p { margin: 0; color: var(--muted); font-size: clamp(16px, 4.2vw, 18px); line-height: 1.62; }
  /* 설명이 두 문단인 섹션이 있다(홈: 하는 일 / 고를 수 있는 것). 붙여 두면 한 덩이로
     읽혀 나눈 뜻이 없어지므로 한 줄만큼 띄운다. */
  section p + p { margin-top: 14px; }

  /*
    받기 버튼은 바닥에 붙는다 — 토스·카카오페이·카카오뱅크가 셋 다 그렇게 한다. 읽다가 마음이
    생기는 자리가 페이지 맨 아래라는 보장이 없다.
  */
  .act {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 10;
    padding: 20px 32px calc(20px + env(safe-area-inset-bottom));
    background: linear-gradient(180deg, transparent, var(--bg) 24px);
  }
  .cta {
    display: block; max-width: 592px; margin: 0 auto;
    padding: 16px; border-radius: 999px;
    background: var(--primary); color: #fff;
    font-size: 16px; font-weight: 800; text-align: center; text-decoration: none;
  }

  /* 폰에는 없다 — 보고 있는 그 기계에 깔면 되므로 코드를 찍을 이유가 없다. */
  .qr { display: none; }

  /*
    바닥 줄 — 방침과 문의처(사용자 지시: "홈피에도 문의하기, 개인정보처리방침 이런거").
    앱 설정의 `정보` 칸과 같은 것들이고, 그래서 순서도 같다.

    좁은 화면에서는 받기 바가 바닥에 **떠 있으므로**(`.act`가 fixed) 그 아래로 숨지 않게
    아래를 그만큼 비운다. 넓은 화면에서는 그 바가 흐름 안으로 돌아오므로 이 여백도 준다.
  */
  .foot {
    padding: 8px 32px calc(120px + env(safe-area-inset-bottom));
    text-align: center;
  }
  .foot nav {
    display: flex; justify-content: center; align-items: center; gap: 18px;
    flex-wrap: wrap;
  }
  .foot a {
    color: var(--muted);
    font-size: 14px; font-weight: 600; letter-spacing: -0.02em;
    text-decoration: none;
  }
  .foot a:hover { color: var(--ink); text-decoration: underline; }
  .foot p {
    margin: 12px 0 0;
    color: var(--muted); font-size: 12px; letter-spacing: -0.01em;
  }
  .cta:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }

  /*
    ── 넓은 화면 ────────────────────────────────────────────────────────────
    여기까지는 폰에서 본 것을 그대로 늘려 왔다. PC에서 그게 두 군데 어긋난다(사용자 지적).

    하나, 글 기둥이 576px에 묶여 1440 화면에서는 좌우 430px씩이 빈다. 둘, **420px로 뜬 앱
    화면을 576px로 늘려** 보여 주느라 스크린샷 속 앱 글씨(19px)가 페이지 본문(18px)보다
    커진다 — 작은 기기를 찍은 그림인데 글이 더 크면 그림이 그림으로 안 읽힌다. 폰에서는
    조각이 326px로 그려져 거의 1:1이라 이 일이 안 생겼고, 그래서 "모바일엔 맞는데 PC에선
    안 맞는" 것이었다.

    그래서 1000px부터 **[글 | 화면]으로 가르고 섹션마다 좌우를 번갈아** 세운다. 화면 칸을
    420px로 못 박는 것이 요점이다 — 조각을 뜬 폭 그대로라 늘어날 일이 없다.

    행 크기를 `min-content`로 잡아 두는 이유: 그림이 여러 행에 걸치는데 행이 늘어날 수 있으면
    남는 높이가 글줄 사이로 나뉘어 들어가, 태그·제목·본문이 그림 높이만큼 서로 벌어진다.
    마지막 `1fr` 행 하나가 그 남는 높이를 혼자 받아 낸다.
  */
  @media (min-width: 1000px) {
    .wrap { max-width: 1080px; padding: 0 40px 48px; }
    .top { margin: 0 -40px; padding: 16px 40px; }

    /*
      히어로만 **움직이는 쪽이 왼쪽**이다(사용자 지시). 그래야 첫 섹션(알림창, 그림 오른쪽)과
      좌우가 엇갈려 아래로 왼-오-왼-오가 끊기지 않는다 — 히어로도 오른쪽이면 화면 두 개가
      연달아 같은 자리에 서서 첫 스크롤이 한 줄로 읽힌다. 게다가 여기 것은 유일하게 저 혼자
      움직이는 그림이라, 글보다 먼저 눈이 가는 자리에 두는 편이 맞다.
    */
    .hero {
      display: grid;
      grid-template-columns: 420px minmax(0, 1fr);
      column-gap: 72px;
      /*
        아래 여백은 히어로가 혼자 낸다. 좁은 화면에서는 `.shot`의 margin-bottom 64px이 그
        자리를 만드는데, 여기서는 그 여백을 0으로 지워 두어서 첫 섹션이 상자에 붙어 버렸다
        (사용자 지적). 첫 섹션도 넓은 화면에서는 제 위 여백을 되찾는다(아래).
      */
      padding: 24px 0 32px;
    }
    /*
      둘 다 **1행에 못 박는다.** 칸만 정해 두면 자동 배치가 앞으로만 흐르는 규칙(sparse) 때문에
      뒤에 오는 그림이 다음 줄로 밀려나, 두 칸이 아니라 위아래로 쌓인다.

      제목은 가운데가 아니라 **조금 위**다(사용자 지시) — 그림이 607px이라 가운데에 두면
      제목이 화면 한복판까지 내려와, 페이지를 열었을 때 첫 줄이 늦게 읽힌다.
    */
    .hero-say { grid-column: 2; grid-row: 1; align-self: start; padding-top: 110px; }
    .hero-say h1 { margin: 0; }
    /* 여기서만 셋째 줄이 선다 — 위 `.hero-turn` 주석 참조. */
    .hero-turn { display: block; }
    /*
      상자도 **아래 조각들과 같은 크기**다(사용자 지시) — 420x500. 좁은 화면에서는 9:13으로
      길쭉하게 서지만(폰 화면을 닮은 무대), 여기서는 아래로 같은 크기의 화면이 다섯 개 더
      내려오므로 히어로만 100px 더 큰 이유가 없다. 쏟아지고 줄 서는 자리는 그 안에 다 든다.
    */
    .hero .shot { grid-column: 1; grid-row: 1; margin: 0; max-height: none; aspect-ratio: 420 / 500; }

    section:first-of-type { padding-top: 64px; }
    /*
      **글 덩어리는 그림 높이의 70% 자리에 선다**(사용자 지시: "2안으로 하되 가운데 말고 한
      70% 위치?").

      전에는 위에 붙어 있었다(맨 아래 `1fr` 한 줄이 남는 자리를 다 먹었다). 그림이 500px을
      넘는데 글은 서너 줄이라, 글 밑으로 빈 자리가 길게 남아 허전했다(사용자 지적: "PC버전
      그림 옆에 글자가 너무 적게 있으니 허전한데").

      **위쪽으로 70%다**(사용자 지적: "70%가 위쪽으로 70%였음"). 한 번 반대로 잡아서 글이
      가운데보다 더 내려갔고, 그러면 위가 텅 빈다(사용자 지적: "너무 위에가 텅텅빔").
      위 `3fr` : 아래 `7fr` — 남는 자리의 3할만 위에 두므로 글이 그림의 위쪽에 붙어 선다.

      행을 하나하나 못 박는 이유가 있다: 자동 배치는 1행부터 채우므로, 안 적으면 본문이
      칩 위로 올라간다.
    */
    section {
      display: grid;
      grid-template-columns: minmax(0, 1fr) 420px;
      grid-template-rows: 3fr repeat(4, min-content) 7fr;
      column-gap: 72px;
      padding: 64px 0;
    }
    section > .tag, section > h2, section > p { grid-column: 1; }
    section > .tag { grid-row: 2; }
    section > h2 { grid-row: 3; }
    section > p:nth-of-type(1) { grid-row: 4; }
    section > p:nth-of-type(2) { grid-row: 5; }
    /* 칩은 제 글자만큼만 — 그리드 항목은 기본이 stretch라, 두면 칸 폭만큼 늘어난 막대가 된다. */
    section > .tag { justify-self: start; }
    section > figure { grid-column: 2; grid-row: 1 / -1; align-self: center; margin: 0; }

    /* 짝수 섹션은 좌우가 바뀐다 — 같은 자리에 같은 것이 계속 서면 스크롤이 한 줄로 읽힌다. */
    section:nth-of-type(even) { grid-template-columns: 420px minmax(0, 1fr); }
    section:nth-of-type(even) > .tag,
    section:nth-of-type(even) > h2,
    section:nth-of-type(even) > p { grid-column: 2; }
    section:nth-of-type(even) > figure { grid-column: 1; }

    /* 바닥에 붙어 있던 바는 풀어서 페이지 끝에 한 번만 선다. */
    /*
      받기 버튼과 코드가 **한 줄에 나란히** 선다. 버튼만 두면 PC에서 누를 곳이 막다른 길이고,
      코드만 두면 폰으로 옮겨 갈 생각이 없는 사람에게 문이 없다. 둘 다 둔다.
    */
    .act {
      position: static; padding: 0 40px 40px; background: none;
      display: flex; align-items: center; justify-content: center; gap: 28px;
    }
    .cta { max-width: 420px; flex: 0 1 420px; margin: 0; }

    .qr {
      display: flex; align-items: center; gap: 14px;
      /* 버튼과 키를 맞춘다 — 둘의 아래끝이 어긋나면 한 줄이 아니라 두 덩이로 읽힌다. */
      padding: 10px 16px 10px 10px;
      border: 1px solid var(--line); border-radius: 18px;
      background: var(--card);
    }
    .qr img {
      width: 76px; height: 76px; display: block;
      border-radius: 8px;
    }
    .qr span {
      font-size: 13px; line-height: 1.5; font-weight: 700;
      color: var(--muted); letter-spacing: -0.02em; white-space: nowrap;
    }
    /* 떠 있던 바가 흐름 안으로 들어왔으니 그 자리를 비워 둘 이유가 없다. */
    .foot { padding: 0 40px 56px; }
  }
