/* 허브·메뉴 공용. 값은 tokens.css가 정한다 — 이 파일에 색·글씨 크기를 직접
   적지 않는다. 놀이 화면(pongpong/css/app.css)도 같은 토큰을 읽는다. */
* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  background: var(--bg-sheet);
  background-attachment: fixed;
  color: var(--ink);
  font-family: var(--font-stack);
  -webkit-text-size-adjust: 100%;
}

.sheet {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
  /* 홈 화면 앱은 상태바 뒤까지 깔리므로(black-translucent, _app_meta.html) 위에도 인셋을
     더한다 — 내용이 가운데 오는 허브는 평소 여유가 있지만, 글씨를 키워 넘치면 제목이
     노치·상태바 밑에서 시작한다 (#128). */
  padding: calc(32px + env(safe-area-inset-top)) 20px calc(32px + env(safe-area-inset-bottom));
  text-align: center;
}

/* justify-content: center는 내용이 넘치면 위쪽을 화면 밖으로 밀어내고, 그 부분은
   스크롤로도 닿지 않는다. auto 마진은 여유가 있을 때만 벌어지므로 같은 가운데
   정렬을 주면서 넘칠 때 잘리지 않는다. 놀이가 늘어나면 실제로 넘친다. */
.sheet > :first-child { margin-top: auto; }
.sheet > :last-child { margin-bottom: auto; }

.sheet-title {
  font-size: var(--fs-display);
  font-weight: 800;
  letter-spacing: -0.02em;
}

.sheet-subtitle {
  color: var(--ink-muted);
  font-size: var(--fs-body);
}

/* ---- 허브 카드 ----
   허브(/)는 놀이·사진첩처럼 "무엇을 할까"를 고르는 문서형 화면이다. 놀이 목록은
   책장(아래)으로 갔지만 여기는 책이 아니므로 가로형 카드로 남는다.

   가로형인 이유는 "크다"가 정사각형이 아니라 면적이기 때문이다. 세로 2열
   카드는 아이폰에서 약 180×170이었는데, 1열 가로형은 약 390×140으로 면적이
   1.8배다. 메뉴의 표지(약 158×186)는 이 논거보다 작다 — 표지는 글줄이 아니라
   그림 한 장을 파는 것이라 세로로 서야 하고, 면적으로 잃은 것을 전면 착색과
   친구로 메운다. 그 예외의 근거는 설계 문서 7절에 있다. */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
  width: 100%;
  max-width: 560px;
}

.card {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 16px;
  min-height: var(--tap-child);
  padding: 16px 20px;
  border-radius: 28px;
  background: var(--bg-raised);
  border: 1px solid var(--border-raised);
  color: inherit;
  text-align: left;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.card:active { background: var(--bg-raised-active); }
.card:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; }

/* 이모지가 원반 위에 앉는다. 원반 색은 tokens.css의 기본값(--ink-muted)이다 —
   대표 색은 놀이의 것이고 허브 카드는 놀이가 아니다.

   isolation으로 쌓임 맥락을 만들어야 원반(z-index: -1)이 이모지 뒤로 가면서도
   카드 배경보다는 앞에 남는다. 맥락이 없으면 원반이 카드 배경 뒤로 숨어 아예
   보이지 않는다. 이걸 빼면 원반이 이모지 위를 덮어 색이 탁해진다. */
.card-emoji {
  position: relative;
  isolation: isolate;
  display: grid;
  place-items: center;
  width: clamp(72px, 20vw, 88px);
  height: clamp(72px, 20vw, 88px);
  border-radius: 50%;
  font-size: clamp(36px, 10vw, 46px);
  line-height: 1;
}
.card-emoji::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 50%;
  background: var(--accent-band);
  opacity: 0.22;
}

.card-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.card-title { font-size: var(--fs-title); font-weight: 700; }
.card-description {
  color: var(--ink-muted);
  font-size: var(--fs-body);
  line-height: 1.5;
  word-break: var(--wrap-ko);
}

/* ---- 책장 (메뉴) ----
   놀이를 고르는 순간을 책을 고르는 순간으로 만든다. 아이가 그림책과 사운드북을
   좋아하는 데서 왔다.

   **표지가 앞을 본다.** 책등만 보이는 진짜 책장은 아이에게 닫힌 목록이다 —
   글자를 못 읽으면 등에 적힌 이름을 읽을 수 없고, 색 띠 넉 장은 서로 너무
   닮았다. 표지를 앞으로 돌리면 그 놀이의 친구가 그대로 보인다.

   선반은 요소가 아니라 격자 배경의 그러데이션이다. 요소로 만들면 줄마다 하나씩
   필요한데, 격자가 몇 줄로 접힐지는 화면 폭이 정하므로 마크업이 미리 알 수 없다.
   배경이면 놀이가 다섯이 되어 줄이 하나 늘어도 판이 저절로 따라온다. */
.shelf {
  --book-gap: 14px;
  --shelf-thickness: 12px;
  /* 표지 높이. max()가 --tap-child(아이용 최소 높이)를 바닥으로 깔고, 그 위에서
     화면 높이를 따라 자란다. 아래 숫자는 .shelf 자신의 좌우 여백까지 뺀 실측이다 —
     아이폰 세로(390×844)에서 2열 약 158×186, 폭이 다 자란 아이패드에서 3열 약
     171×190이다. */
  --book-height: max(var(--tap-child), clamp(150px, 22vh, 190px));

  display: grid;
  /* auto-fit이 아니라 auto-fill이다 — 마지막 줄에 한 권만 남아도 그 한 권이
     줄 전체로 늘어나지 않고 왼쪽부터 꽂힌 채로 있다. 책장은 그렇게 생겼다.
     줄 수를 적지 않으므로 놀이가 몇이든 아래로 접힌다.

     칸의 하한은 150px이되 좁은 화면에서는 45%까지 양보한다. 하한만 두면 폭
     320px 기기에서 한 칸이 되어 책이 아니라 가로로 누운 판이 되고, 비율만 두면
     넓은 화면에서 네 칸으로 쪼개져 책이 얇아진다. */
  grid-template-columns: repeat(auto-fill, minmax(min(150px, 45%), 1fr));
  grid-auto-rows: var(--book-height);
  column-gap: var(--book-gap);
  row-gap: var(--shelf-thickness);
  width: 100%;
  max-width: 560px;
  /* 마지막 줄 아래에도 판이 있어야 한다 — 줄 사이 간격만으로는 마지막 줄의
     책이 허공에 뜬다. 좌우 여백은 판을 책보다 조금 넓게 내민다. */
  padding: 0 10px var(--shelf-thickness);
  /* 한 주기가 "표지 한 줄 + 판 하나"다. 위 2px은 판의 앞모서리에 걸리는 빛이고
     나머지가 판의 두께다. */
  background: repeating-linear-gradient(
    to bottom,
    transparent 0 var(--book-height),
    var(--shelf-edge) var(--book-height) calc(var(--book-height) + 2px),
    var(--shelf-face) calc(var(--book-height) + 2px)
      calc(var(--book-height) + var(--shelf-thickness))
  );
}

/* 표지 한 장. 대표 색이 통째로 덮고 그 위에 친구와 제목이 얹힌다.

   isolation으로 쌓임 맥락을 만들어야 대표 색 층(z-index: -1)이 표지 바탕 앞,
   내용 뒤에 선다. 맥락이 없으면 그 층이 바탕 뒤로 숨어 표지가 통째로 검게 뜬다. */
.book {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  overflow: hidden;
  /* 왼쪽이 넓은 것은 책등 자리를 비우기 때문이다. */
  padding: 12px 12px 14px 20px;
  border-radius: 6px 20px 20px 6px;
  /* 바탕은 --bg-sheet가 아니라 --bg다 — 표지 합성색이 화면 위치에 따라 달라지면
     제목 대비를 계산할 수 없다 (tokens.css의 --cover-tint 주석). */
  background: var(--bg);
  border: 2px solid var(--cover-edge);
  color: var(--ink);
  text-align: center;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.book::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--accent-band);
  opacity: var(--cover-tint);
}
/* 책등. 표지가 앞을 봐도 왼쪽에 등이 조금 접혀 보인다 — 그 한 줄이 카드를
   책으로 읽히게 한다. */
.book::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 8px;
  background: var(--bg);
  opacity: 0.28;
  pointer-events: none;
}
.book:active { transform: scale(0.97); }
.book:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; }

/* 표지 그림 자리. 제목이 먼저 자리를 잡고 남는 높이를 그림이 가져간다 —
   제목이 두 줄이 되어도 잘리지 않게 하려는 것이다. */
.book-art {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
}
.book-art .friend {
  position: absolute;
  /* 표지 가장자리에 여백을 남긴다 — 모티프 자국이 지나갈 자리이자, 그림이
     테두리에 닿지 않아야 표지가 한 장의 그림으로 보인다. */
  inset: 4%;
  width: 92%;
  height: 92%;
}

.book-title {
  flex: 0 0 auto;
  font-size: var(--fs-title);
  font-weight: 800;
  line-height: 1.2;
  word-break: var(--wrap-ko);
}

/* 좌상단 칩이 제목과 겹치지 않게 위를 비운다. 칩은 fixed라 흐름에 없다.
   허브에는 칩이 없으므로 이 클래스를 붙이지 않는다. */
.sheet-inset {
  padding-top: calc(var(--tap-parent) + 32px + env(safe-area-inset-top));
}

/* ---- 책장 정리 (부모용, #100) ----
   부모가 읽고 고르는 화면이다. 색은 표본(swatch)에만 쓰고 나머지는 무채색으로
   둔다 — 크게 만들되 색으로 아이를 막는다. 모든 선택지가 --tap-parent 하한을 지킨다. */
.parent-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap-parent);
  padding: 0 24px;
  border-radius: 999px;
  border: 1px solid var(--border-raised);
  color: var(--ink-muted);
  font-size: var(--fs-body);
  text-decoration: none;
}
.parent-link:active { background: var(--bg-raised-active); }
.parent-link:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; }

.shelf-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
  width: 100%;
  max-width: 560px;
  text-align: left;
}

.slot {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 14px 16px 16px;
  border-radius: 20px;
  border: 1px solid var(--border-raised);
  background: var(--bg-raised);
}
.slot legend {
  padding: 0 6px;
  color: var(--ink-muted);
  font-size: var(--fs-body);
}

.slot-option {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: center;
  gap: 12px;
  min-height: var(--tap-parent);
  padding: 0 12px;
  border-radius: 14px;
  font-size: var(--fs-body);
  cursor: pointer;
}
.slot-option:has(input:checked) { background: var(--bg-raised-active); }
.slot-option input { width: 22px; height: 22px; margin: 0; accent-color: var(--accent); }

.slot-swatch {
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--accent-band);
}
/* 비워 두기는 색이 없다는 것을 빈 틀로 보여 준다. */
.slot-empty .slot-swatch {
  background: none;
  border: 2px dashed var(--border-raised);
}

.shelf-save {
  min-height: var(--tap-parent);
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: var(--bg);
  font: inherit;
  font-size: var(--fs-body);
  font-weight: 700;
}
.shelf-save:focus-visible { outline: 3px solid var(--ink); outline-offset: 4px; }


/* ---- 표지 모티프 ----
   놀이가 무엇인지 아이에게 알려주는 움직임이다. 글자를 못 읽으니 색이 이름이고
   움직임이 설명이다.

   표지 그림 자리에만 산다 — 제목 뒤로 지나가면 크림색 글자가 크림색 자국 위에
   얹혀 읽히지 않는다. 자국이 크림색인 것은 표지가 이미 대표 색이어서다. 같은
   색으로 칠하면 자국이 표지에 녹아 없는 것과 같아진다.

   크기와 이동 거리를 퍼센트로 잡는다. 자국이 돌던 곳은 88px 이모지 원반이었고
   거기서는 11px과 20여 px의 이동이 알맞았다 — 같은 값을 표지에 옮기면 자국이
   친구 뒤에서 조금 떨고 마는 것으로 보인다. 이제 자국은 표지를 가로지르고,
   친구 뒤로 들어갔다 빈자리에서 다시 나온다 (z-index: -1).

   캔버스를 표지마다 돌리면 비용이 급증하므로 CSS만 쓴다. 그리고 transform과
   opacity만 건드린다 — 이 둘은 합성 단계에서 끝나 레이아웃·페인트를 다시
   부르지 않는다. width나 top을 애니메이션하면 표지 넉 장이 매 프레임 레이아웃을
   다시 계산하게 만들고, 그 대가는 스크롤과 터치 반응으로 돌아온다.

   모양은 .motif의 ::before/::after 둘뿐이다. 셋 이상이 필요하면 그때 요소를
   늘리기보다 모션을 단순하게 만드는 쪽을 먼저 검토한다. */
.motif {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
.motif::before,
.motif::after {
  content: "";
  position: absolute;
  border-radius: 50%;
}

/* 소리 정원 — 두드린 자리에서 퍼지는 파문 */
[data-motif="bloom"] .motif::before,
[data-motif="bloom"] .motif::after {
  inset: 30%;
  border: 2px solid var(--ink);
  animation: motif-bloom 3.2s ease-out infinite;
}
[data-motif="bloom"] .motif::after { animation-delay: 1.6s; }

@keyframes motif-bloom {
  0%   { transform: scale(0.5); opacity: 0.85; }
  100% { transform: scale(2.9); opacity: 0; }
}

/* 풍선 톡톡 — 아래에서 천천히 떠오르는 것들 */
[data-motif="float"] .motif::before,
[data-motif="float"] .motif::after {
  bottom: 4%;
  left: 22%;
  width: 9%;
  aspect-ratio: 1;
  background: var(--ink);
  animation: motif-float 3.6s ease-in-out infinite;
}
[data-motif="float"] .motif::after {
  left: 66%;
  animation-delay: 1.8s;
}

@keyframes motif-float {
  0%   { transform: translateY(30%); opacity: 0; }
  25%  { opacity: 0.75; }
  100% { transform: translateY(-900%); opacity: 0; }
}

/* 데굴데굴 구슬 — 바닥을 좌우로 구르며 살짝 튀는 하나 */
[data-motif="roll"] .motif::before {
  bottom: 5%;
  left: 8%;
  width: 10%;
  aspect-ratio: 1;
  background: var(--ink);
  opacity: 0.8;
  animation: motif-roll 3.4s ease-in-out infinite;
}
[data-motif="roll"] .motif::after { content: none; }

@keyframes motif-roll {
  0%, 100% { transform: translate(0, 0); }
  25%      { transform: translate(310%, -70%); }
  50%      { transform: translate(620%, 0); }
  75%      { transform: translate(310%, -70%); }
}

/* 까꿍 숲 — 잎 아래서 올라왔다 다시 숨는 눈 두 개. 대부분의 시간은 숨어 있고
   짧게만 고개를 내민다 — 이 놀이가 "숨었다가 나타남"이라는 것을 그 비율로
   보여준다. */
[data-motif="peek"] .motif::before,
[data-motif="peek"] .motif::after {
  bottom: 6%;
  width: 8%;
  aspect-ratio: 1;
  background: var(--ink);
  animation: motif-peek 3.4s ease-in-out infinite;
}
/* 부엉이 몸통이 닿지 않는 두 아래 구석이다 — 가운데서 올라오면 몸 뒤에 가려
   숨은 시간과 나온 시간이 구별되지 않는다. */
[data-motif="peek"] .motif::before { left: 10%; }
[data-motif="peek"] .motif::after { left: 82%; }

@keyframes motif-peek {
  0%, 55%, 100% { transform: translateY(200%); opacity: 0; }
  70%, 85%      { transform: translateY(0%); opacity: 1; }
}

/* 모션을 줄여 달라고 한 사람에게는 멈춘 모양만 남긴다. 움직임이 정보의 전부는
   아니어야 하므로, 사라지지 않고 은은하게 보인다. */
@media (prefers-reduced-motion: reduce) {
  .motif::before,
  .motif::after {
    animation: none;
    opacity: 0.45;
  }
  /* 자국이 멈춘 자리(inset 30% — 중심에서 반지름 약 44/200)는 꽃 친구의 몸통
     안이다. 꽃술(r 42)과 꽃잎 여섯(중심에서 52 떨어진 r 34)의 합집합이 그 거리를
     통째로 덮으므로, 손대지 않으면 정원만 자국 둘 중 하나를 통째로 잃는다.
     바깥 자국은 꽃잎 끝(약 88/200) 밖으로 내보내 온전히 보이게 하고, 안쪽 자국은
     꽃잎 틈으로 비치는 자리에 남긴다 — 파문 둘의 간격이 그래야 파문으로 읽힌다.
     다른 세 놀이의 자국은 몸통이 닿지 않는 아래 구석이라 그대로 둔다. */
  [data-motif="bloom"] .motif::before { inset: 4%; }
  [data-motif="bloom"] .motif::after { inset: 16%; }
  [data-motif="float"] .motif::before { transform: translateY(-200%); }
  [data-motif="float"] .motif::after { transform: translateY(-520%); }
}
