/* 스킨-B — 고정된 좌우 틀 사이로 사진만 흐른다.
   aireaire.studio 의 틀, Canva 시안의 내용.

   `main.css` 위에 얹는 한 겹이다. 여기 없는 것은 전부 스킨-A 의 값을 그대로 쓴다 —
   그래서 문의 폼처럼 손대지 않은 화면도 같이 옷을 갈아입는다.

   임계값은 이 위쪽에 모아 둔다. 실사용하며 튜닝할 값들이다. */

/* 시안이 쓰는 글꼴. 저장소에 담아 두고 외부 CDN 을 부르지 않는다 — 첫 화면에
   걸리는 글꼴이라 남의 서버가 느린 날 우리 첫인상이 같이 느려진다.
   **스킨-B 의 틀에서만 쓴다.** 본문 글꼴은 그대로 Pretendard 다. */
/* 시안이 Canva 에서 쓴 글꼴이 Cinzel 이다. **가변 글꼴이라 한 파일에 400~700 이
   다 들어 있다** — EB Garamond 는 굵기마다 파일이 따로였고 그래서 중간 굵기를
   못 만들었다. 여기서는 브라우저가 사이 굵기를 만들어 준다. */
@font-face {
  font-family: "Cinzel Local";
  src: url("../fonts/cinzel.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

.skin-b {
  --b-ground: #fff;     /* 시안의 바탕이 순백이다 (Canva 페이지 배경 rgb(255,255,255)) */
  --b-ink: #000;        /* 시안의 글자도 순검정이다 */
  --b-soft: #8a8a8a;
  --b-faint: #d8d8d8;

  --b-gutter: clamp(1.4rem, 5vw, 4.5rem);
  --b-rail: clamp(9rem, 17vw, 15rem);   /* 좌우 틀이 차지하는 폭 */

  /* **한 화면이 한 번에 줄고 한 번에 모인다.** 시안에서 잰 값을 그대로 쓰면
     큰 화면에서 글자와 사진이 화면을 꽉 채워, 시안이 가진 여유가 사라진다.
     페이지마다 따로 줄이면 어느 화면은 줄고 어느 화면은 안 줄어서 스킨이 갈린다 —
     두 값으로 모아 두고 여기서만 만진다.

       --b-scale   글자와 사진의 배수
       --b-inset   좌우 양쪽으로 더 물리는 여백. `.bstream` 처럼 자리를 %로 잡는
                   화면은 이 여백이 기준 폭을 좁히므로, 판이 **저절로 가운데로
                   모인다** — 자리 값을 하나하나 고칠 일이 없다.

     폰에서는 둘 다 끈다 (아래 좁은 화면 절). 좁은 화면에서 더 줄이면 읽을 수
     없어지고, 더 모으면 사진이 설 폭이 없다. */
  --b-scale: 0.92;
  --b-inset: 3%;

  /* 시안에서 직접 잰 값이다. 글자 크기를 페이지 **가로 폭** 기준으로 잡는다 —
     자리도 가로 폭 기준이라 같이 움직여야 창이 커져도 시안과 같은 화면이 된다.
     창이 좁아져도 읽히는 크기 아래로는 안 내려간다.

     **시안의 글자 크기는 브라우저가 말해주는 값이 아니다.** Canva 는 페이지 전체에
     `scale` 을 걸어 놓는다(재보니 0.9283). 그래서 `getComputedStyle` 은 줄어들기 전
     크기(21.3px)를 말하는데 화면에 보이는 것은 19.8px 이다. 처음에 그 말을 그대로
     받아 적어서 글자가 한결같이 커져 있었다.
     비율은 **줄어들기 전 캔버스 폭(1365.9)** 으로 나눈다 — 그것이 두 값을 모두
     줄어들기 전 기준으로 맞추는 유일한 방법이다. */
  --b-serif: "Cinzel Local", Georgia, "Times New Roman", serif;
  --b-name: calc(clamp(1.15rem, 1.952vw, 2.1rem) * var(--b-scale));  /* MAEY, 시안 26.7px */
  --b-line: calc(clamp(0.92rem, 1.367vw, 1.5rem) * var(--b-scale));  /* 이름 아래 한 줄, 시안 18.7px */
  --b-nav:  calc(clamp(1rem, 1.562vw, 1.7rem) * var(--b-scale));     /* 목차 3줄, 시안 21.3px */

  /* 목차의 검정은 이름의 검정보다 한 겹 묽다. 순검정으로 두면 세 줄이 이름과 같은
     무게로 서서, 어느 것이 이 화면의 이름이고 어느 것이 갈 곳인지가 안 갈린다.
     회색이 아니다 — 회색으로 내리면 '꺼진 링크'로 읽힌다. 검정에서 색만 뺀 값이다. */
  --b-nav-ink: #2b2b2b;

  /* 헤더를 뺀 화면 전체가 시안보다 한 단 위에 붙어 있었다. 목차·본문·사진을
     각각 내리면 페이지마다 어긋나므로 **한 값으로 모아 두고 같이 내린다.**
     한 단은 이 화면의 한 줄 — 목차 글자 크기의 줄 높이(1.355배)다.
     이름(`.bframe__mark`)은 바닥에 걸려 있어서 여기 걸지 않는다. 그쪽은 아래에서
     6.06% 자리로 이미 시안과 맞아 있고, 같이 내리면 바닥에 붙는다.

     **두 줄이다.** 한 줄만 내렸을 때 화면에서 여전히 시안보다 위에 붙어 있었다.
     한 줄씩 재보는 값이라 곱하는 수만 고친다. */
  --b-drop: calc(var(--b-nav) * 1.355 * 2);

  /* 모션은 느리다. 사진을 보러 온 화면이라 움직임이 먼저 눈에 띄면 안 되고,
     느린 것이 급한 것보다 비싸 보인다. 한 곳에서 조절한다. */
  --b-ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* 마우스에 반응하는 것. **들어오는 것보다 훨씬 빠르다.**
     사람이 보고 있는 동안은 느려도 되지만, 사람이 한 행동에 대한 답은 빨라야 한다 —
     1.1초로 뒀더니 우아한 것이 아니라 안 눌리는 것으로 읽혔다. */
  --b-slow: 350ms;
  --b-enter: 2600ms;   /* 이름이 들어오는 것 */
  /* **목차는 이름이 끝나기 직전에 시작한다.**
     사이가 뜨면 화면이 멈춘 것으로 읽히고, 처음부터 같이 들어오면 어느 쪽을 봐야
     하는지 정해지지 않은 채로 흔들린다. 이름의 마지막 한 자락에 목차가 물리는
     것이 두 줄기를 한 흐름으로 잇는다.

     **여기서 재는 것은 애니메이션의 길이가 아니라 눈에 보이는 진행이다.**
     `--b-ease` 는 앞이 급하고 뒤가 긴 곡선이라, 2.6초짜리라도 0.6초면 80% 가
     끝나 있다. 길이를 다 기다렸을 때는 뒤의 2초가 통째로 빈 시간이 되었고,
     98%·90% 로 당긴 뒤에도 여전히 늦다고 읽혔다 — 남은 몇 %는 눈에 안 보이는데
     기다리는 시간은 보인다.
     0.133 이 그 60% 지점이다. `--b-enter` 를 고치면 이 값도 같이 움직인다. */
  --b-nav-after: calc(var(--b-enter) * 0.133);
  --b-nav-in: 1900ms;
  --b-nav-step: 260ms;  /* 세 줄이 차례로 서는 간격 */

  /* 사진이 커지는 것. **`--b-enter` 와 따로 둔다** — 글이 자리를 잡는 것과 사진이
     도착하는 것은 다른 일이고, 사진 쪽만 늦추고 싶을 때가 있었다. */
  --b-photo-in: 3800ms;

  /* das Fotobuch 의 격자가 나타나는 것 (레퍼런스 aireaire.studio/studio).
     재서 근사하던 것을 그만두고 레퍼런스 스크립트의 값을 그대로 쓴다 —
     첫 화면은 칸마다 0.35s 씩 어긋나 하나씩 2s 동안, 스크롤로 만나는 것은
     어긋남 없이 1.6s 동안, 둘 다 60px 아래에서 `power3.out` 으로 올라온다. */
  --b-rise: 1600ms;
  --b-rise-step: 350ms;
  --b-rise-lift: 60px;
  /* GSAP 의 `power3.out`. 다른 모션이 쓰는 `--b-ease` 와 다른 곡선이라 따로 둔다. */
  --b-rise-ease: cubic-bezier(0.215, 0.61, 0.355, 1);
  /* 목차가 시작하는 색. 검정에서 시작하면 '들어온다'가 아니라 '켜진다'로 읽힌다. */
  --b-nav-start: #c9c9c9;

  background: var(--b-ground);
  color: var(--b-ink);
}

/* **굵은 글자는 한 단 눅인다.** 이 스킨은 글자가 적어서 굵은 것 하나가 화면 전체의
   무게를 정한다. 700 에 순검정이면 그 한 덩어리만 앞으로 튀어나와, 나머지가 흐릿한
   배경처럼 물러난다 — 시안의 인상은 그 반대다.

   `:where()` 로 감싸 특정도를 0 으로 둔다. 이 스킨에는 굵기를 일부러 400 으로 되돌린
   자리가 여럿이라(종목 번호, 틀의 이름), 특정도를 가지면 그것들을 도로 굵게 만든다.
   여기는 '아무도 정하지 않았을 때의 굵은 글자'만 맡는다. */
.skin-b :where(strong, b, th) {
  font-weight: 600;
  /* 한 번 더 눅인다(#2b2b2b → #545454). 굵기만으로도 이미 다른 글자와 갈리므로,
     색까지 짙으면 두 번 강조하는 것이 된다 — 굵은 것은 눈에 먼저 들어오면 되지
     제일 검을 이유가 없다. 내렸다가 한 단 되올린 값이다 (#2b2b2b → #545454 → #6b6b6b → #5e5e5e). */
  color: #5e5e5e;
}

/* 스킨-B 는 글자가 적다. 그만큼 하나하나가 크게 읽히므로 자간을 조인다. */
.skin-b,
.skin-b .site-header,
.skin-b .site-footer {
  letter-spacing: -0.01em;
}

/* 틀의 글자는 시안과 같은 세리프로 간다. 본문(문의 폼 등)은 건드리지 않는다.

   **한글에는 씌우지 않는다.** Cinzel 에는 한글이 없어서 씌우면 글자마다 다른
   글꼴로 떨어지고, 그 대체가 무엇일지는 기기가 정한다. 여기 적은 것은 전부
   숫자와 로마자만 서는 자리다 — 종목 번호, 연락처 세 줄. */
.bframe,
.bindex__list b,
.bdetail__title b,
.bkontakt__links { font-family: var(--b-serif); }

/* 상단 오른쪽 문의 링크는 숨긴다. 목차의 Kontakt 가 같은 곳으로 가므로
   같은 화면에서 같은 행동을 두 번 권하는 것이 된다. */
.skin-b .header-inquiry { display: none; }

/* 언어 토글과 저작권 줄을 화면에서 뺀다. 시안에 둘 다 없다.
   **마크업에서 지우지 않는다** — 스킨-A 는 그대로 쓰고, `hreflang` 과 `/en` 주소는
   손대지 않았으므로 영문 페이지는 그대로 살아 있다. 다만 스킨-B 에서는 화면에
   언어를 바꿀 손잡이가 없어진다. */
.skin-b .lang-toggle,
.skin-b .site-footer { display: none; }

/* 왼쪽 위 표식은 물러선다. 이름은 틀의 왼쪽 아래가 말하고, 이것은 홈으로 가는
   손잡이일 뿐이라 목차와 같은 농도로 서면 넷째 항목처럼 읽힌다.
   `currentColor` 로 그린 SVG 라 색 하나로 같이 옅어진다. */
.skin-b .wordmark { color: #c9c9c9; transition: color var(--b-slow) var(--b-ease); }
.skin-b .wordmark:hover,
.skin-b .wordmark:focus-visible { color: var(--b-ink); }

/* **움직이는 것은 사진뿐이다.** 헤더는 제자리에 못 박는다 — 좌우 틀만 고정하고
   위가 흘러가면 화면의 절반은 서 있고 절반은 지나가서, 고정이 의도가 아니라
   덜 만든 것처럼 보인다. */
.skin-b .site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  background: transparent;
  border: 0;
}

/* 헤더 왼쪽은 **표식만** 선다. 이름은 틀의 왼쪽이 이미 말하고 있어서, 글줄을 같이
   두면 같은 화면에서 이름을 두 번 읽게 된다. 홈에서도 뺐다 넣었다 하지 않는다 —
   좌우가 고정된 화면에서 그 한 칸만 페이지마다 달라지면 깜빡이는 것처럼 보인다. */
.skin-b .wordmark-lines { display: none; }

/* --- 틀 ------------------------------------------------------------------ */
/* 좌우가 화면에 붙어 있고 사진이 그 사이로 지나간다. 스크롤해도 이름과 목차는
   제자리에 있으므로 어느 페이지에서도 길을 잃지 않는다. */

/* 틀은 화면 전체를 덮되 글자만 잡는다. 그 사이 빈 곳으로는 사진을 눌러야 하므로
   통과시킨다. 자리는 시안(maeydemo.my.canva.site) 화면에서 직접 재서 옮겼다 —
   1456×818 기준 값을 비율로 바꾼 것이라 창 크기가 달라도 같은 자리에 선다. */
.bframe {
  position: fixed;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

.bframe__mark,
.bframe__index { position: absolute; pointer-events: auto; }

/* 이름은 왼쪽 아래. 시안(1405×768)에서 아래 줄의 왼끝이 9.87%,
   그 줄의 밑선이 페이지 바닥에서 6.06% 자리다. */
.bframe__mark {
  left: calc(9.87% + var(--b-inset));
  bottom: 6.06vh;
  display: grid;
  gap: 0;
  line-height: 1.355;
  color: var(--b-ink);
  white-space: nowrap;
}

/* 아래 줄보다 한 칸 들여 선다. 시안에서 MAEY 의 왼끝이 11.83%,
   아래 줄보다 1.96% 안쪽이다 — 27.5px, 이 글자 크기의 1.03배. */
.bframe__mark strong {
  margin-left: 1.03em;
  font-weight: 400;
  /* **아래 줄과 같은 색이다.** 굵은 글자를 눅이면서(`:where(strong, b, th)`) 이
     이름까지 옅어져, 두 줄이 한 덩어리가 아니라 흐린 이름 + 짙은 설명으로 갈렸다.
     여기의 `<strong>` 은 강조가 아니라 이름이고 굵기도 400 이다. 상자의 색을
     그대로 물려받는다 — 아래 줄이 색을 바꾸면 이 줄도 따라간다. */
  color: inherit;
  font-size: var(--b-name);
  letter-spacing: 0;
}

.bframe__mark span {
  font-size: var(--b-line);
  letter-spacing: 0;
  color: var(--b-ink);
}

/* 목차는 오른쪽 위. 세 줄이 오른끝을 서로 어긋나게 맞춰 계단을 만든다.
   시안에서 첫 줄의 윗선이 페이지 높이의 22.65% 자리이고, 세 줄은 사이를 벌리지
   않고 붙어 내려간다 — 줄 간격이 곧 글자 상자 높이(1.355배)다. */
.bframe__index {
  right: calc(7.44% + var(--b-inset));
  /* **한 줄 위로 올린다.** `--b-drop` 은 화면 전체를 두 줄 내리는 값인데, 목차는
     그 두 줄을 다 받으면 화면 세로 한가운데에 가깝게 내려앉아 '위쪽 모서리에
     걸린 것'이 아니라 '떠 있는 것'으로 읽힌다. 한 줄만 받는다 — 빼는 값이
     `--b-nav` 의 줄 상자라, 글자 크기를 고치면 이 자리도 같이 따라온다. */
  top: calc(22.65vh + var(--b-drop) - var(--b-nav) * 1.355);
  display: grid;
  gap: 0;
  line-height: 1.355;
  text-align: right;
  font-size: var(--b-nav);
  letter-spacing: 0;
  white-space: nowrap;
}

/* 두 벌(보통·굵게)을 같은 자리에 겹쳐 두고 **서로 교대시킨다.** 보통 굵기가
   물러나는 만큼 굵은 것이 올라온다.

   Cinzel 은 가변 글꼴이라 굵기를 그냥 바꿔도 되지만, 그러면 마우스를 올릴 때마다
   글자가 넓어지며 목차가 좌우로 흔들린다. 두 사본 모두 흐름 밖(절대 배치)이라
   굵어져도 상자가 안 넓어지고, 오른끝을 붙잡고 있으므로 왼쪽으로만 자란다.

   글자 자체는 투명하게 두고 자리만 잡게 한다. 눈에 보이는 것은 두 사본이고,
   실제 글자는 화면 낭독기와 글자 선택을 위해 그대로 있다. */
.bframe__index a {
  position: relative;
  text-decoration: none;
  color: transparent;
}

.bframe__index a::before,
.bframe__index a::after {
  content: attr(data-label);
  position: absolute;
  top: 0;
  right: 0;                /* 오른끝을 붙잡는다. 굵어지며 넓어지는 만큼 왼쪽으로 자란다 */
  white-space: nowrap;
  color: var(--b-nav-ink);
  transition: opacity var(--b-slow) var(--b-ease);
  pointer-events: none;
}

.bframe__index a::before { font-weight: 400; opacity: 1; }
/* 지금 페이지는 700 이 아니라 600 이다. 굵기의 차이는 그대로 읽히면서, 세 줄 중
   하나만 검게 튀지 않는다 — 목차는 어디인지 말하는 자리지 외치는 자리가 아니다. */
.bframe__index a::after  { font-weight: 600; color: #5e5e5e; opacity: 0; }

/* 지금 페이지 표시는 기기와 무관하다. 마우스 반응만 마우스가 있는 기기로 한정한다 —
   터치에서는 탭이 hover 를 켜고 그 상태가 손을 뗀 뒤에도 남는다. */
.bframe__index a:focus-visible::before,
.bframe__index a[aria-current="page"]::before { opacity: 0; }

.bframe__index a:focus-visible::after,
.bframe__index a[aria-current="page"]::after { opacity: 1; }

@media (hover: hover) and (pointer: fine) {
  .bframe__index a:hover::before { opacity: 0; }
  .bframe__index a:hover::after { opacity: 1; }
}

/* --- 종목 상세의 틀 ------------------------------------------------------- */
/* 이 화면만 틀이 다르게 선다 (`_frame.html` 의 `frame_mode`).

   **큰 화면에서만 그렇다.** 폰에서는 이름이 위, 목차가 아래인 두 줄기가 화면의
   유일한 길잡이라 걷을 것이 없다 — 좌우 표식도 없고 돌아갈 손잡이가 그것뿐이다. */
@media (min-width: 861px) {
  /* 목차를 걷는다. 종목 하나를 읽는 화면에서 오른쪽 위에 세 갈래가 서 있으면,
     읽던 것을 그만두고 다른 데로 가라는 말이 된다. */
  .bframe--detail .bframe__index { display: none; }

  /* 이름은 첫 화면에서 내려 둔다. 첫 화면은 번호와 값만 말하고, 거기 이름이 같이
     서면 큰 글자 둘이 화면 양쪽에서 서로를 붙잡는다.

     **들어오는 애니메이션도 같이 끈다.** 켜 둔 채로 투명도만 0 으로 눌러도
     애니메이션이 끝나며 `opacity: 1` 을 되돌려 놓아, 첫 화면에서 한 번 깜빡이고
     사라진다 (`b-slide-in` 은 `both` 라 끝 값을 붙잡는다).

     **`is-cued` 는 자바스크립트가 붙인다** (`skin-b.js`). 여기서 무조건 내려 두면
     스크립트가 막힌 방문자에게 이름이 어느 화면에서도 안 나온다. 안 붙으면
     이름은 늘 제자리에 서 있고, 그것이 이 화면에서 잃을 것이 가장 적은 모습이다. */
  .bframe--detail.is-cued .bframe__mark {
    animation: none;
    opacity: 0;
    transition: opacity var(--b-nav-in) var(--b-ease);
  }

  /* 한 화면을 넘기면 제자리(왼쪽 아래)에 선다. `is-past` 는 첫 화면 높이를 재는
     자(`.bframe__cue`)가 화면에서 나갈 때 붙는다. */
  .bframe--detail.is-cued.is-past .bframe__mark { opacity: 1; }
}

/* 첫 화면의 높이를 재는 자. 보이지 않고 아무것도 막지 않는다.
   `.bdetail` 이 기준이라 글이 시작하는 자리에서부터 한 화면을 센다. */
.bframe__cue {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 100vh;
  pointer-events: none;
  visibility: hidden;
}

/* 계단은 `margin` 으로 만들지 않는다. 이 상자는 내용 폭으로 잡히므로 여백을 주면
   글자가 왼쪽으로 넘칠 뿐 오른끝이 움직이지 않는다 — 실제로 그렇게 나왔다.
   자리를 옮기는 것이 목적이니 옮기는 속성을 쓴다. 창 폭에 비례해야 어느 크기에서도
   같은 계단이 되므로 `vw` 로 잡는다 (시안 1456px 기준 110 · 159px). */
.bframe__index a:nth-child(1) { position: relative; right: 7.36vw; }
.bframe__index a:nth-child(2) { position: relative; right: 10.83vw; }

/* 폭을 따로 잡아 둘 필요가 없다. 두 사본이 모두 흐름 밖(절대 배치)이라 굵어져도
   상자가 넓어지지 않고, 오른끝을 붙잡고 있으므로 왼쪽으로만 자란다. */



/* --- 사진 ---------------------------------------------------------------- */
/* 판마다 자기 자리·크기·앞 판과의 간격을 갖는다 (`app/skins.py` 의 PLACEMENTS).
   **간격이 음수인 판은 앞 판이 끝나기 전에 시작한다** — 그래서 한 화면에 두 장이
   나란히 선다. 한 줄로 내려가는 열로는 만들 수 없는 것이다.

   셋 다 화면 가로 폭 기준이다. 판의 높이가 폭에서 나오므로, 간격만 세로 기준으로
   재면 창 모양이 바뀔 때 사진은 그대로인데 사이만 벌어진다. */

/* 판의 `x` 와 `w` 는 시안에서 페이지 **전체 폭** 기준으로 잰 값이라, 여기에 좌우
   여백이 있으면 그 안쪽 폭이 기준이 되어 사진이 안으로 밀리고 좁아진다 — 재보니
   24.7% 로 적은 판이 22.0% 로 나왔다. 그래서 오래 0 으로 두었다.

   **지금은 그 성질을 일부러 쓴다** (`--b-inset`). 큰 화면에서 시안 값 그대로면
   사진이 양 끝에 붙어 여유가 사라지는데, 여백을 넣으면 자리와 크기가 **같은
   비율로** 함께 안으로 모인다. 판 하나하나의 값을 고치는 것과 달리 시안이 잡아
   놓은 구성은 그대로 남는다. */
.bstream {
  position: relative;
  z-index: 1;
  /* 첫 사진 위와 마지막 사진 아래도 시안에서 잰 값이다 (페이지 위에서 100px,
     아래로 137px, 페이지 폭 1268 기준). 세로 여백을 %로 주면 가로 폭에 대해
     풀리므로 사진과 같은 비율로 함께 자란다. */
  padding: calc(7.89% + var(--b-drop)) var(--b-inset) 10.8%;
}

.bplate {
  margin: 0;
  width: calc(var(--w, 22) * 1%);
  margin-inline: calc(var(--x, 39) * 1%) 0;
  /* **세로 여백인데 단위가 %다.** CSS 는 세로 여백의 %도 containing block 의
     **가로 폭**으로 푼다. 보통은 함정으로 불리는 성질인데 여기서는 정확히 그것이
     필요하다 — 판의 높이가 폭에서 나오므로 간격도 폭을 따라야 한다.
     `vw` 로 두면 스크롤바 폭만큼 어긋난다 (x·w 는 칸 기준, vw 는 창 기준). */
  margin-top: calc(var(--gap, 6) * 1%);
}

/* 첫 판의 간격은 쓰지 않는다. 위쪽 여백은 `.bstream` 이 잡는다. */
.bstream .bplate:first-child { margin-top: 0; }

.bplate img {
  display: block;
  width: 100%;
  height: auto;
  background: rgba(28, 28, 28, 0.04);
}

/* 아직 안 채운 자리. 빈 칸이 아니라 **무엇을 넣어야 하는지 말하는 칸**이다.
   파일을 `static/skins/b/photos/` 에 넣으면 그 자리가 사진으로 바뀐다. */
.bplate.is-empty {
  aspect-ratio: 3 / 4;
  display: grid;
  place-content: center;
  border: 1px dashed var(--b-faint);
  background: rgba(28, 28, 28, 0.015);
}

.bplate__name {
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--b-soft);
  word-break: break-all;
  padding: 0 0.8em;
  text-align: center;
}

/* --- das Produkt 목차 ---------------------------------------------------- */

/* 시안(page-2)에서 잰 자리다. 가운데로 모으지 않는다 — 세 줄이 화면 한가운데가
   아니라 오른쪽으로 밀려 서 있고, 그 치우침이 왼쪽 아래의 이름과 균형을 만든다. */
/* `grid` 로 둔다. 보통 흐름이면 안쪽의 위 여백이 이 상자의 여백과 **합쳐져**
   밖으로 빠져나가고, 목차가 화면 맨 위에 붙는다 — 실제로 그렇게 나왔다. */
.bindex {
  position: relative;
  z-index: 1;
  min-height: 100dvh;
  display: grid;
  align-content: start;
  padding: var(--b-drop) var(--b-inset) 0;
}

/* 가운데 제목은 화면에서 뺀다. 오른쪽 목차가 지금 어느 화면인지 이미 굵게
   말하고 있어서, 같은 말을 가운데에 한 번 더 두면 사진이 설 자리만 줄어든다.

   **마크업에서 지우지는 않는다.** 지우면 이 페이지에 제목이 하나도 없게 되고,
   스크린리더와 검색엔진은 무엇에 관한 화면인지 알 방법을 잃는다. 눈에만 안 보인다. */
.bindex__head,
.bbook__head {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* 시안에서 번호 상자의 왼끝이 42.14% · 첫 줄의 윗선이 20.03% 이고, 줄 간격이 5.57% 다.
   왼끝을 글자가 아니라 **상자**로 잡는다 — 시안에서 세 번호는 같은 폭(9.22%)의 상자
   안에 가운데로 서 있고, 그래서 001 도 000·002 와 같은 자리를 차지한다. */
.bindex__list {
  display: grid;
  gap: 0;
  margin-left: 42.14%;
  margin-top: 20.03%;
  width: 25%;
}

/* 줄 간격은 `gap` 으로 주지 않는다. 격자의 `row-gap` 은 %가 세로 크기를 기준으로
   푸는데 이 상자는 높이가 내용에 따라 정해져서 0 으로 풀린다 (`.bspread` 와 같다).
   시안에서 줄 사이가 5.566% (76.03px) 이고 번호 상자 하나가 4.383% (59.87px) 라
   1.183% 가 남는데, 이 칸(25%) 기준으로는 4.73% 다.
   **줄 높이를 시안에 맞춘 뒤 다시 잰 값이다** — 예전에는 번호 상자를 글자 크기와
   같게(줄 높이 1) 두고 재서 6% 였다. 상자가 커진 만큼 사이를 줄여야 줄 간격이
   그대로 남는다. */
.bindex__list a + a { margin-top: 4.73%; }

/* 번호와 이름이 나란히 선다. 이름의 왼끝은 51.36% 로 **세 줄이 같다** — 번호 상자가
   9.22% 폭으로 고정이고 이름이 그 오른쪽에 바로 붙기 때문이다(42.14 + 9.22 = 51.36).
   이 칸(25%) 안에서 9.22% 는 36.88% 다. */
/* **옅은 데서 짙은 데로 간다.** 손이 닿은 것이 짙어져야 '고르는 중'으로 읽힌다 —
   검정에서 옅어지게 뒀더니 고른 것이 물러나는 것으로 보였다.
   번호와 이름이 함께 짙어진다. 둘 중 하나만 반응하면 한 줄이 아니라 두 조각이
   된다. 크기는 시안 그대로다. */
/* **쉬는 진하기를 변수로 둔다.** 올라오는 모션이 `opacity` 를 쓰는데, 도착한
   상태를 1 로 적어 두면 세 줄이 새까맣게 선다 — 여기의 0.38 은 꾸밈이 아니라
   '아직 안 고른 것'의 색이고, 손이 닿을 때만 짙어져야 한다.
   변수로 두면 모션 규칙(`.b-rise.is-in`)이 이 값을 그대로 도착점으로 쓰고,
   hover 는 특정도 싸움 없이 변수만 바꿔 이긴다. */
.bindex__list a {
  --b-idx-op: 0.38;
  display: grid;
  grid-template-columns: 36.88% auto;
  align-items: start;
  text-decoration: none;
  color: var(--b-ink);
  opacity: var(--b-idx-op);
  transition: opacity var(--b-slow) var(--b-ease);
}

/* **시안은 세 번호를 자간으로 같은 폭에 맞춘다.** 상자 폭이 셋 다 125.97 인데
   1 이 0 보다 좁아서, 001 만 자간을 23/1000 에서 116/1000 으로 벌려 놓았다.
   가운데 정렬로 흉내내 봤지만 그것과는 다르다 — 가운데로 모으면 001 이 짧은 채로
   가운데에 뜨고, 시안은 001 이 **벌어져서** 세 줄이 같은 폭으로 선다.
   줄 높이도 시안의 글자 상자 비율(59.87 / 50.667)을 그대로 쓴다. 이름의 세로
   자리를 이 상자의 윗선에서 재기 때문에, 여기가 다르면 이름만 어긋난다. */
.bindex__list b {
  font-size: calc(clamp(1.9rem, 3.709vw, 4rem) * var(--b-scale));   /* 시안 50.7px */
  font-weight: 400;
  letter-spacing: 0.023em;
  line-height: 1.181;
  color: var(--b-ink);
}

/* 가운데 줄만 벌어진다. 마크업의 순서(000·001·002)가 곧 이 자리라, 번호를 늘리면
   여기도 같이 봐야 한다 — 자간은 글자 모양의 문제라 표(`PLACEMENTS`)에 없다. */
.bindex__list a:nth-child(2) b { letter-spacing: 0.116em; }

/* 이름은 번호의 어깨에 붙는다. 밑선을 맞추지 않는다 — 시안에서 이름의 윗선이
   번호의 윗선보다 2.42% 아래이고, 그것은 번호 높이의 절반쯤 되는 자리다. */
/* 이름도 시안에서는 번호와 **같은 글꼴**(Cinzel)로 지정되어 있다. 다만 Cinzel 에는
   한글이 없어서, 시안의 한글 이름도 실제로는 대체 글꼴로 떨어져 있다. 그래서 여기서도
   Cinzel 을 앞에 세우되 뒤를 본문 글꼴로 받는다 — 로마자(/en)는 시안 그대로 서고,
   한글은 지금과 같은 Pretendard 로 남는다. 세리프로 받으면 한글만 다른 글꼴이 된다. */
.bindex__list em {
  font-family: "Cinzel Local", var(--font);
  font-style: normal;
  font-size: calc(clamp(0.78rem, 0.976vw, 1.1rem) * var(--b-scale));   /* 시안 13.3px */
  line-height: 1.15;                            /* 시안의 글자 상자 15.33 / 13.33 */
  /* 시안에서 이름 상자의 윗선이 번호 상자보다 29.93px 아래다(307.97 - 278.03).
     번호 글자의 0.5907 배이고, 이 글자 크기로는 2.245 배다 — 제 크기로 재두면
     창이 좁아져 글자가 작아질 때 같이 따라온다.
     **두 상자의 줄 높이를 시안과 같게 맞춰 두었기 때문에** 이 값이 그대로
     시안의 자리가 된다. 줄 높이를 안 맞추면 같은 숫자를 넣어도 어긋난다. */
  margin-top: 2.245em;
}

/* **모션이 돌 화면에서는 처음부터 없다.** `b-rise` 는 `defer` 스크립트가 붙이는데
   그것은 첫 그림보다 늦어서, 세 줄이 한 번 다 보였다가 사라진 뒤 하나씩 다시 나왔다 —
   "없다가 생긴다"가 아니라 "있다가 깜빡인다"다.
   `b-js` 는 head 에서 붙는다(`base.html`). 모션을 끄기로 했거나 관찰기가 없는
   브라우저에는 안 붙으므로, 그때 목차는 그냥 처음부터 서 있다. */
.b-js .bindex__list a { opacity: 0; }

/* 다 올라온 줄. 스크립트가 모션 옷을 벗기면서 이것을 붙인다 — 안 붙이면 위의
   감춤으로 되돌아가 도착하자마자 사라진다. */
.b-js .bindex__list a.is-set {
  opacity: var(--b-idx-op);
  transition: opacity var(--b-slow) var(--b-ease);
}

.bindex__list a:focus-visible { --b-idx-op: 1; }

@media (hover: hover) and (pointer: fine) {
  .bindex__list a:hover { --b-idx-op: 1; }
}

/* --- 종목 상세 ------------------------------------------------------------ */
/* 시안(Canva page-3·4·5)은 **두 화면**이고 셋의 자리가 완전히 같다. 다른 것은 글뿐이다.
   첫 화면 왼쪽에 무엇을 주는지와 얼마인지, 둘째 화면 오른쪽에 추가 옵션.
   사진 넷은 그 두 화면에 걸쳐 한 줄기로 내려간다.

   **글과 사진을 한 흐름에 세우지 않는다.** 사진 줄기가 글보다 훨씬 길어서, 하나의
   칸에 세로로 늘어놓으면 글이 사진을 밀어내 시안의 자리가 안 나온다. 같은 칸에
   겹쳐 놓고 각자 자기 자리를 잡게 한다 — 글은 왼쪽, 사진은 가운데, 옵션은 오른쪽이라
   가로로 겹치지 않는다.

   세로 자리는 전부 페이지 **가로 폭** 기준의 %다. 세로 여백의 %를 CSS 가 가로 폭으로
   푸는 성질을 쓴다 (`.bplate` 와 같다). 그래야 창이 커져도 사진과 글이 같이 자란다. */

.bdetail {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr;
  padding-top: var(--b-drop);
  padding-bottom: 8%;
  padding-inline: var(--b-inset);

  /* **이 화면만 한 단 더 작다.** 시안(page-3·4·5)을 1425px 에서 재보면 번호 50.7px ·
     값 18.7px · 본문 13.3px 이고 우리는 그보다 이미 조금 작았는데(48.6 · 17.9 · 12.8),
     화면에서는 여전히 시안보다 크게 읽힌다. 글자 크기가 아니라 **글이 앉은 폭**이
     달라서다 — 시안의 글 칸은 화면의 25% 라 긴 줄이 한 줄로 서는데, 우리 칸은
     30.8% 라 같은 글이 더 넓게 퍼진다. 폭을 좁히면 줄이 접혀서 층이 달라지므로,
     여기서는 크기를 한 단 더 내려 같은 인상을 만든다.

     `--b-scale` 은 이 상자 안에서만 다시 정의된다. 틀(`.bframe`)은 형제라 안 따라온다 —
     이름과 목차는 어느 화면에서나 같은 크기여야 한다.

       --b-photo  사진 줄기의 폭 배수. 자리(`x`)는 그대로 두고 폭만 줄인다. */
  --b-scale: 0.85;
  --b-photo: 0.9;
}

/* 넷 다 같은 칸에 놓는다. 높이는 가장 긴 것(사진 줄기)이 정한다. */
.bdetail > * { grid-area: 1 / 1; }

/* 글은 자기 칸 안에서 가운데로 모인다. 왼끝을 맞추면 줄 길이가 제각각인 것이
   그대로 드러나서, 값을 말하는 화면이 서식 없는 목록처럼 보인다.
   시안에서 이 칸은 9% 자리에서 시작해 폭 32.78%, 윗선이 5.3% 다. */
.bdetail__copy {
  margin-left: 9%;
  margin-top: 5.3%;
  width: 32.78%;
  text-align: center;
  display: grid;
  /* 칸 사이는 저마다 다르다. 하나로 묶으면 시안의 층이 사라진다 — 제목과 이끄는
     줄은 붙어 있고, 이끄는 줄과 본문 사이가 벌어지고, 값 앞이 가장 크게 빈다.
     아래에서 칸마다 따로 준다. */
  gap: 0;
  align-content: start;
  align-self: start;
}

.bdetail__title {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.6em;
  margin: 0;
  font-weight: 400;
}

/* 글자 크기는 전부 시안에서 잰 값이다 (페이지 폭 1268 기준).
   번호가 이 화면에서 가장 큰 글자다. 이름은 그 옆에 작게 붙어 무엇인지만 말한다 —
   시안에서 이름은 본문과 같은 크기이고, 큰 것은 번호 하나뿐이다. */
/* **머리글은 순검정이다.** 굵은 글자를 눅이면서(`:where(strong, b, th)`) 이 번호도
   함께 옅어졌는데, 여기의 `<b>` 는 강조가 아니라 종목 번호이고 굵기도 400 이다 —
   눅일 이유가 애초에 없는 자리다. 화면 이름이 흐리면 그 화면이 흐려 보인다. */
.bdetail__title b,
.bdetail__title em {
  color: var(--b-ink);
}

.bdetail__title b {
  font-size: calc(clamp(1.9rem, 3.709vw, 4rem) * var(--b-scale));   /* 시안 50.7px */
  font-weight: 400;
  letter-spacing: 0.02em;
  line-height: 1;
}

.bdetail__title em {
  font-style: normal;
  font-size: calc(clamp(0.78rem, 0.976vw, 1.15rem) * var(--b-scale));  /* 시안 13.3px */
  color: var(--b-ink);
}

/* 제목 바로 아래. 시안에서 제목 밑선 10.28% · 이끄는 줄 윗선 11.16% (0.88%). */
.bdetail__lede { display: grid; gap: 1.16em; margin-top: 5.7%; }

.bdetail__lede p {
  margin: 0;
  font-size: calc(clamp(0.95rem, 1.367vw, 1.55rem) * var(--b-scale));  /* 시안 18.7px */
  line-height: 1.4;
}

/* 이끄는 줄의 둘째 줄은 한 단계 작다 ("식 90분 전부터 …", 시안 16px). */
.bdetail__lede p + p { font-size: calc(clamp(0.86rem, 1.171vw, 1.35rem) * var(--b-scale)); }

/* 이끄는 줄과 본문 사이가 이 칸에서 두 번째로 크게 빈다.
   시안에서 이끄는 줄 밑선 15.65% · 본문 윗선 19.00% (3.35%). */
.bdetail__body {
  display: grid;
  gap: 2.6em;
  margin-top: 7.8%;
  font-size: calc(clamp(0.78rem, 0.976vw, 1.1rem) * var(--b-scale));   /* 시안 13.3px */
  line-height: 1.65;
}

.bdetail__body p { margin: 0; }
.bdetail__body b { font-weight: 400; }
.bdetail__body span,
.bdetail__body .is-quiet { display: block; }

.bdetail__body dl {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.4em 2em;
  margin: 0;
  text-align: left;
}
.bdetail__body dd { margin: 0; }

/* 값은 이끄는 줄과 같은 크기다. 크게 키우면 이 화면이 값부터 말하는 화면이 된다 —
   시안은 그러지 않는다. 시안에서 값의 윗선이 39.56%, 글 칸의 윗선이 5.3% 라
   그 사이 34.26% 를 글이 채우고 남는 만큼이 여기 여백이다. */
.bdetail__price {
  /* 값 위의 빈자리. 시안에서 값의 윗선이 39.6~41.6% 인데 그 위를 채우는 것이
     글이라 **문구를 고치면 이 자리도 따라 움직인다.** 지금 문구로 그 높이에
     서도록 잡은 값이고, 정확히 못 박을 수 있는 종류가 아니다. */
  margin: 14.3% 0 0;
  font-size: calc(clamp(0.95rem, 1.367vw, 1.55rem) * var(--b-scale));   /* 시안 18.7px */
  letter-spacing: 0.01em;
}

/* 사진 아래의 값은 폰에서만 선다 (아래 좁은 화면 절). 큰 화면에서는 값이 글 칸
   안의 제자리에 있고, 이 한 벌은 화면에도 낭독기에도 나오지 않는다. */
.bdetail__price--after { display: none; }

.bdetail__price small {
  display: block;
  margin-top: 1.2em;
  font-size: calc(clamp(0.78rem, 0.976vw, 1.1rem) * var(--b-scale));    /* 시안 13.3px */
  letter-spacing: 0;
}

/* 사진 줄기. 홈과 같은 모델이라 자리·크기·간격을 판이 스스로 갖는다.

   **첫 장을 화면 위로 걸치지 않는다.** 시안은 윗선이 -18.83% 라 첫 장의 위쪽이
   잘려 있는데, 시안은 넘길 수 없는 종이고 이것은 스크롤되는 화면이다. 페이지
   맨 위보다 위로는 올릴 수 없으니 그 잘린 부분은 **끝까지 볼 방법이 없다** —
   종이에서는 구성이던 것이 화면에서는 못 보는 사진이 된다.
   줄기 전체가 그만큼 내려오고, 판 사이의 리듬은 그대로다. */
.bdetail__photos { margin-top: 0; }

/* 사진도 한 단 작다. **자리는 그대로 두고 폭만 줄인다** — `x` 까지 건드리면 시안에서
   잰 줄기의 세로선이 옮겨 간다. 줄 사이(`gap`)는 폭에서 나오는 판 높이에 얹히므로
   폭이 줄면 사이도 같이 좁아져, 줄기의 리듬은 그대로다. */
.bdetail__photos .bplate { width: calc(var(--w, 22) * 1% * var(--b-photo, 1)); }

/* 오른쪽 칸 — 추가 옵션과 안내 한 줄. 시안에서 왼끝 76.94% · 폭 19.6%.
   윗선은 둘째 화면 안에서 15.25% 이므로 첫 화면 높이(56.22%)를 더해 71.47% 다. */
.bdetail__side {
  margin-left: 76.94%;
  margin-top: 71.47%;
  width: 19.6%;
  text-align: center;
  font-size: calc(clamp(0.78rem, 0.976vw, 1.1rem) * var(--b-scale));   /* 시안 13.3px */
  line-height: 1.65;
  align-self: start;
}

/* 옵션이 없는 종목(002)은 안내 한 줄이 **첫 화면** 오른쪽에 선다 (시안 42.06%). */
.bdetail__side.is-early { margin-top: 42.06%; }

/* --- 아직 열지 않은 종목 ---------------------------------------------------- */
/*
  사진과 글을 지우지 않고 흐린다. 빈 화면은 "없다"고 말하지만 흐린 화면은 "곧"이라고
  말한다 — 무엇을 준비하고 있는지는 보여야 한다.

  **흐림은 형제들에게만 건다.** 상자에 걸면 그 안의 글자까지 같이 흐려진다.
  누를 것도 없앤다 — 흐려진 채로 링크가 살아 있으면 그것이 고장으로 읽힌다.
*/
.bdetail.is-soon > *:not(.bsoon) {
  filter: blur(9px);
  pointer-events: none;
  user-select: none;
}

/* 화면 한가운데. `fixed` 라 두 화면짜리 이 상자를 넘겨도 따라온다 —
   흐린 것은 흘러가고 이 한 줄만 남는다. */
.bsoon {
  position: fixed;
  inset: 0;
  z-index: 2;
  margin: 0;
  display: grid;
  place-content: center;
  text-align: center;
  pointer-events: none;

  font-family: var(--b-serif);
  font-size: clamp(1.6rem, 4.2vw, 3.4rem);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.14em;
  /* 가운뎃점까지 자간이 붙어 오른쪽으로 반 칸 밀린다. 그만큼 되민다. */
  text-indent: 0.14em;
  color: var(--b-ink);
  opacity: 0.82;
}

@media (prefers-reduced-motion: no-preference) {
  /* **작은 데서 커지며 나타난다.** 자리를 잡고 켜지는 것이 아니라 다가온다 —
     '아직 아니지만 오고 있다'가 이 화면이 하는 말이다.
     `both` 로 시작 상태를 붙든다. 안 붙들면 첫 그림에 제 크기로 한 번 보인다. */
  .bsoon { animation: b-soon-in 1500ms var(--b-ease) both; }
}

@keyframes b-soon-in {
  from { opacity: 0; transform: scale(0.62); }
  to   { opacity: 0.82; transform: scale(1); }
}

/* --- 종목 상세의 큰 화면 자리 ---------------------------------------------- */
/*
  **두 화면에 묶고 사진만 안에서 굴리던 것은 되돌렸다.** `height: 200dvh` 로 상자를
  못 박고 행을 `minmax(0, 1fr)` 로 잠갔더니, 같은 칸을 나눠 쓰는 글(`.bdetail__copy`)과
  한 화면 뒤에 서는 이름(`.bframe__mark`)이 화면에서 사라졌다. 이 화면은 네 덩어리가
  한 칸에 겹쳐 있는 구조라, 그 위에 고정 높이를 얹으면 겹친 것들이 함께 무너진다.
  다시 만들 때는 상자 높이를 못 박는 대신 사진 줄기 쪽만 손봐야 한다.

  아래 둘은 그 되돌림과 무관하게 남는다 — 고정 높이에 기대지 않고 각각 제 문제를 고친다.
*/
@media (min-width: 861px) {
  /* 위아래로 내려가는 줄기는 다섯 장이다. 나머지 다섯은 폰의 띠에서만 선다 —
     여기서 다 세우면 화면이 다섯 장 여섯 장으로 늘어나고, 글은 맨 위에 한 번
     나오고 만다. 모자란 길이는 `skin-b.js` 가 같은 벌을 이어 붙여 채운다. */
  .b-wide-hide { display: none; }

  /* **아직 열지 않은 종목의 글자는 왼쪽에 선다.** 사진 줄기가 화면의 절반쯤(49%)에
     내려오므로 가운데에 두면 글자가 사진 위에 겹치고, 흐린 사진 위의 글자는
     테두리가 뭉개져 읽기 어렵다. 사진이 없는 왼쪽 — 흐려도 흰 자리 — 로 옮긴다.
     폰은 그대로 가운데다. 거기서는 사진이 폭을 다 쓰므로 비켜설 자리가 없다. */
  /* **큰 화면에서는 한 단 작다 (지금의 60%).** 폰에서는 이 글자가 화면 폭을
     가로질러 서야 하지만, 큰 화면에서는 같은 크기가 사진보다 커져 화면을 이 한 줄이
     차지한다 — 흐린 사진 위에 놓인 표시지 이 화면의 제목이 아니다. */
  .bsoon {
    place-content: center start;
    padding-left: 16vw;
    font-size: clamp(0.96rem, 2.52vw, 2.04rem);
  }

  /* 오른쪽 칸의 윗자리(71.47%)는 가로 폭 기준이라 넓고 낮은 창에서는 시안이 말하는
     '둘째 화면 안'보다 훨씬 아래로 내려간다. 두 화면 안에 머물게 상한을 둔다.

     **둘째 화면에 도착하면 거기 남는다** (`sticky`). 이 칸은 둘째 화면의 글이지
     줄기를 따라 흐르는 것이 아니다 — 스크롤과 함께 위로 빠져나가면 옵션을 다 읽기
     전에 사라지고, 사진만 남은 화면이 이어진다. 제자리에 닿을 때까지는 보통대로
     흐르고, 닿은 뒤에 멎는다. */
  .bdetail__side {
    margin-top: min(71.47%, 118dvh);
    position: sticky;
    top: 22dvh;
  }
  .bdetail__side.is-early { margin-top: min(42.06%, 70dvh); }
}

.bdetail__side p { margin: 0; }

/* **두 열로 세우지 않는다.** 이름과 값을 좌우로 벌리면 이름이 길어서 두세 줄로
   접히고, 그러면 값이 어느 이름에 붙는지가 줄 끝의 점선 없이는 안 읽힌다.
   시안(page-4)은 이름을 가운데에 한 줄로 두고 값을 그 **바로 아래**에 놓는다 —
   한 덩어리가 위아래로 서고, 덩어리 사이의 빈 자리가 항목을 가른다. */
.bdetail__addons dl {
  display: block;
  margin: 0;
  text-align: center;
}
.bdetail__addons dt { margin: 0; }
/* 값과 이름 사이는 붙이고(줄 간격 그대로), 항목 사이만 벌린다. */
.bdetail__addons dd { margin: 0 0 1.9em; }
.bdetail__addons dd:last-child { margin-bottom: 0; }

/* 맨 위의 `+` 도 한 항목만큼 떨어진다. 붙어 있으면 첫 항목의 머리처럼 읽힌다. */
.bdetail__addons p { margin: 0 0 1.5em; }

.bdetail__foot { margin-top: 2.4em; }

/* **안내 두 줄은 한 덩어리가 아니다.** 위는 안 찍는 것에 대한 단서고, 아래는
   값에 대한 말이다. 시안에서 둘 사이가 한 화면 가까이 비어 있고 아래 줄이 조금
   크다 — 그 빈 자리가 "여기서 이야기가 바뀐다"를 대신한다. */
.bdetail__foot p + p {
  margin-top: 6.4em;
  font-size: 1.18em;
}

/* --- das Fotobuch -------------------------------------------------------- */

/* 레퍼런스는 aireaire.studio/studio 다. 그쪽 값을 그대로 받아 적었다 — 재서
   %로 옮기지 않고 **원래 단위 그대로** 쓴다. 레퍼런스의 `--pad` 가 1rem 이고
   격자는 그 배수로만 서 있다 (여백 `pad*5` = 5rem, 사이 `pad*4` = 4rem).
   %로 환산해 뒀더니 창 폭에 따라 사이와 여백의 비가 어긋났다. */
.bbook {
  position: relative;
  z-index: 1;
  padding: calc(5rem + var(--b-drop)) calc(5rem + var(--b-inset)) 5rem;
}

.bspread {
  /* 덧대는 천(아래 `::before`·`::after`)이 격자를 기준으로 선다. **판이 아니라 격자다** —
     상자(`.bbook`)에 걸었더니 좌우 여백(5rem)까지 26% 안에 들어가서, 가장 짙은 끝이
     빈 여백 위에 놓이고 사진 위에는 거의 남지 않았다. 물린 것이 안 보이던 이유다. */
  position: relative;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  /* 가로와 세로가 같은 거리다. 줄 간격을 칸의 위 여백으로 돌려 주던 것을
     그만둔다 — 칸에 고정 비율이 없어져서 `row-gap` 이 제대로 풀린다. */
  gap: 4rem;

  /* **가장자리는 그라데이션으로 물러난다.** 가운데가 온전하고 양옆으로 갈수록
     이어서 옅어진다.

     사진마다 값을 주는 방식(열별 opacity)으로 먼저 만들었는데, 그것은 계단이라
     열 경계에서 끊긴다 — 같은 열 안에서는 어디나 같은 농도고 옆 열로 넘어가는
     순간 값이 바뀐다. 레퍼런스(aireaire.studio/studio)의 결은 연속이다.

     **격자 전체에 한 장으로 건다.** 판마다 걸면 판이 제 상자 안에서만 옅어져서
     칸과 칸 사이 빈 자리를 건너뛰고, 그러면 결이 다시 끊긴다.

     **변화를 가장자리에 몰아 넣는다.** 0.1 에서 1 까지 격자 폭의 절반에 걸쳐
     고르게 오르는 직선으로 먼저 만들었는데, 그러면 사진 한 장을 지나는 동안
     값이 0.2 밖에 안 움직인다 — 사진 안에서는 변화가 안 보이고 장마다 농도가
     하나씩 붙은 것처럼 읽힌다. 계단을 없애려고 그라데이션으로 바꾼 것이 다시
     계단으로 보이는 셈이다.

     끝에서 32% 안에서 다 오르게 하고, 그 구간을 여러 마디로 끊어 촘촘하게 둔다.
     첫 열 한 장(격자의 0~16%)을 지나는 동안 0.06 에서 0.60 까지 움직이므로,
     **한 장 안에서 왼쪽과 오른쪽의 농도가 다르다.** 가운데 세 열은 온전하다.

     **화면이 아니라 격자 기준이다.** 화면 폭에 고정한 천(`.bveil`)으로 먼저
     만들었는데, 그것은 열의 자리가 아니라 픽셀 자리를 덮어서 창 폭이 바뀌면
     물리는 정도가 열마다 달라졌다. 여기 %는 격자 폭을 따르므로 어느 폭에서나
     같은 열이 같은 만큼 물러난다.

     이름과 목차는 `.bspread` 밖이라 이 마스크에 닿지 않는다 — 글자까지 흐려지면
     읽을 수 없는 화면이 된다. */
}

/* **마스크가 아니라 덧대는 천으로 물린다.**
   `mask-image` 를 격자에 걸어 두었더니 가장자리가 물렸다 풀렸다 했다 — 판마다
   전환(`b-rise`)이 돌 때 브라우저가 이 상자의 레이어를 다시 잡고, 그때 마스크가
   한 프레임씩 빠진다. 눈에는 '투명이 되었다 안 되었다'로 보인다.

   같은 그라데이션을 **바탕색에서 투명으로** 칠해 위에 덮는다. 결과는 같은데
   마스크와 달리 판의 전환과 무관하다 — 천은 그냥 그 자리에 그려져 있다.
   `pointer-events: none` 이라 아래의 사진을 가리지 않는다(누를 것도 없지만).
   **기준은 격자다.** 바깥 상자에 걸면 좌우 여백까지 폭에 들어가 물리는 자리가 어긋난다. */
.bspread::before,
.bspread::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 26%;
  z-index: 2;
  pointer-events: none;
}

.bspread::before {
  left: 0;
  background: linear-gradient(90deg,
      var(--b-ground) 0%,
      rgba(255, 255, 255, 0.86) 14%,
      rgba(255, 255, 255, 0.58) 30%,
      rgba(255, 255, 255, 0.28) 50%,
      rgba(255, 255, 255, 0.08) 74%,
      transparent 100%);
}

.bspread::after {
  right: 0;
  background: linear-gradient(270deg,
      var(--b-ground) 0%,
      rgba(255, 255, 255, 0.86) 14%,
      rgba(255, 255, 255, 0.58) 30%,
      rgba(255, 255, 255, 0.28) 50%,
      rgba(255, 255, 255, 0.08) 74%,
      transparent 100%);
}

/* **칸의 높이는 사진이 정한다.** 3:4 액자를 씌워 두고 그 안에서 `contain` 으로
   줄이던 것을 그만둔다. 레퍼런스는 액자가 없고, 사진이 열 폭까지 늘어나되
   `max-height: 25vh` 에서 멈춘다. 그래서 줄 높이가 줄마다 다르고, 그 들쭉날쭉이
   이 격자의 인상이다 — 고른 액자에 넣으면 표가 되고 판이 아니게 된다.

   `width`/`height` 속성이 마크업에 있으므로 사진이 받아지기 전에도 자리는 잡힌다. */
.bspread .bplate {
  margin: 0;
  width: 100%;
  /* **판마다 크기가 다르다** (`--w`, `app/skins.py` 의 `FOTOBUCH_SCALE`).
     레퍼런스는 판(figure)째로 줄인다. 우리도 판에 건다 — 안쪽 사진에 걸면
     줄어든 사진과 안 줄어든 칸 사이에 빈 자리가 남아 간격이 어긋난다.
     `--s` 는 `b-rise` 가 `translateY` 와 함께 쓰므로 값만 여기서 정한다. */
  --s: calc(var(--w, 60) / 100);
  transform: scale(var(--s));
}

/* 사진은 잘리지 않는다. 사진가의 화면에서 구도를 잘라낼 이유가 없고, 레퍼런스도
   `contain` 이라 액자 안 여백이 사진마다 다르다. */
.bspread .bplate img,
.bspread .bplate .bplate__name {
  display: block;
  width: 100%;
  height: auto;
  max-height: calc(25vh * var(--b-scale));
  object-fit: contain;
  background: none;
}

/* 빈 자리도 사진이 든 칸과 같은 높이여야 한다. 3:4 액자를 그대로 두면 칸만
   `25vh` 보다 높아져서, 사진이 다 채워지기 전까지 줄 높이가 들쭉날쭉해진다. */
.bspread .bplate.is-empty {
  aspect-ratio: auto;
  border: 0;
  background: none;
}

/* 빈 자리는 사진이 없어서 높이를 못 얻는다. 3:4 로 자리만 잡아 둔다. */
.bspread .bplate .bplate__name {
  aspect-ratio: 3 / 4;
  height: 25vh;
  width: auto;
  margin-inline: auto;
  display: grid;
  place-content: center;
  border: 1px dashed var(--b-faint);
}

/* --- Kontakt ------------------------------------------------------------- */
/* 사진 한 장과 연락처 세 줄. 시안(page-7)에서 잰 자리다 — 가운데에 모으되
   화면 세로 가운데가 아니라 **위쪽**이다. 사진 윗선 5.16% · 폭 23.59%,
   연락처 첫 줄 38.69%. 셋 다 가로로는 화면 한가운데(50%)에 선다. */

.bkontakt {
  position: relative;
  z-index: 1;
  min-height: 100dvh;
  display: grid;
  justify-items: center;
  align-content: start;
  padding: calc(5.16% + var(--b-drop)) 0 0;
}

.bkontakt .bplate {
  margin: 0;
  width: 23.59%;
}

.bkontakt .bplate img { aspect-ratio: 3 / 4; object-fit: cover; }

/* 사진 밑선 36.62% · 연락처 윗선 38.69% 이므로 사이가 2.07% 다. */
.bkontakt__links {
  display: grid;
  gap: 0;
  margin-top: 2.07%;
  text-align: center;
  font-size: var(--b-nav);              /* 시안 21.3px — 목차와 같은 크기다 */
  line-height: 1.36;                    /* 시안에서 줄 간격이 2.125%, 글자의 1.36배 */
  letter-spacing: 0;
}

.bkontakt__links p { margin: 0; }

/* **밑줄을 친다.** 오래 반응(옅어졌다 짙어지는 것)만으로 두었는데, 손이 닿기 전에는
   아무 표시가 없어서 이 세 줄이 눌리는 것인지 그냥 적어 둔 것인지 알 수 없었다 —
   폰에서는 hover 자체가 없으니 표시가 통째로 없는 셈이다.

   대신 밑줄을 글자에서 떼고(0.28em) 가늘게 그어, 세리프 대문자 조판의 밑선을
   끊지 않게 한다. 반응은 그대로 남는다. */
.bkontakt__links a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.28em;
  color: var(--b-ink);
  opacity: 0.72;
  transition: opacity var(--b-slow) var(--b-ease);
}

.bkontakt__links a:focus-visible { opacity: 1; }

@media (hover: hover) and (pointer: fine) {
  .bkontakt__links a:hover { opacity: 1; }
}

@media (max-width: 860px) {
  /* 위아래를 틀만큼 비운다 (`--b-frame-top` · `--b-frame-bottom`, 아래 좁은 화면 절). */
  /* **한 화면 안에 들어와야 한다.** 틀이 위아래에 고정이라, 넘치면 스크롤된 글이
     그 밑으로 들어가 목차와 겹쳐 읽힌다 — 실제로 연락처 마지막 줄(E-mail)이
     `das Produkt` 위에 포개졌다. 위아래를 틀만큼 비우는 것만으로는 부족하다.

     비운 자리 안에서 **가운데로 모으고**, 사진이 남은 높이를 넘지 못하게 막는다.
     26rem 은 틀 위아래(9 + 8.5)와 연락처 세 줄(4.5)에, 마지막 줄과 목차 사이의
     **숨 쉴 자리 한 줄(4)** 을 더한 값이다 — 겹치지만 않으면 되는 것이 아니라,
     E-mail 이 목차에 붙어 서면 그것도 목차의 한 줄처럼 읽힌다. 폭이 아니라 높이가
     모자란 화면에서는 사진이 먼저 작아지고, 글은 언제나 제자리에 남는다.
     `0.75` 는 3:4 를 폭으로 되돌리는 값이다. */
  /* **남는 자리는 아래에 몰아 준다** (`start`, 기본값 그대로). 가운데로 모으면
     사진이 작아져 생긴 자리가 위아래로 반씩 갈리는데, 위쪽은 이미 비어 있고
     모자란 것은 아래다 — 시안도 이 화면을 세로 가운데가 아니라 위쪽에 둔다. */
  /* **폰의 Kontakt 에서는 틀을 걷는다.** 이 화면은 사진 한 장과 연락처 세 줄이
     전부인데, 거기에 틀의 이름 두 줄과 목차 세 줄이 더 서면 글자만 여덟 줄이 되어
     무엇을 하러 온 화면인지가 묻힌다. 홈으로 가는 길은 위쪽 표식이 그대로 갖고 있다.
     큰 화면은 그대로다 — 거기서는 틀이 좌우에 서므로 가운데를 비우지 않는다. */
  .b-kontakt .bframe { display: none; }

  /* 틀이 없으니 그만큼 비울 이유도 없다. 위아래를 이 화면의 여백으로 되돌린다. */
  .bkontakt { padding: 7.5rem var(--b-gutter) 4rem; }

  .bkontakt .bplate { width: min(52vw, 15rem); }

  /* --- 폰의 종목 상세 (`b-detail`) --------------------------------------- */

  /* **목차를 걷는다.** 종목 하나를 읽는 화면인데 세 갈래가 화면 아래에 늘 서 있으면,
     읽던 것을 그만두고 다른 데로 가라는 말이 된다. 큰 화면에서는 이미 걷고 있었고
     (`bframe--detail`), 폰에서만 남아 있었다. */
  .b-detail .bframe__index { display: none; }

  /* **이름은 둘째 화면 아래 한가운데에 선다.** 첫 화면은 번호와 값이 말하고,
     한 화면을 넘긴 뒤에 누가 찍는지가 아래에 남는다 — 나가는 자리의 서명이다.
     서는 때(`is-past`)는 큰 화면과 같은 자를 쓴다 (`.bframe__cue`, 100vh). */
  /* **폰에서도 이름은 둘째 화면에서 선다** (큰 화면과 같다). 첫 화면은 번호와
     설명이 말하고, 한 화면을 넘긴 뒤에 누가 찍는지가 아래에 남는다.
     서고 사라지는 값은 큰 화면 절의 것과 같고, 그 절이 `min-width: 861px` 안에
     있어서 폰에는 닿지 않았다 — 그래서 첫 화면에도 이름이 서 있었다.
     `is-cued` 는 자바스크립트가 붙인다. 안 붙으면 이름은 늘 제자리에 선다. */
  /* **자를 짧게 잡는다 (70dvh).** 폰에서 100vh 짜리 자는 `.bdetail` 의 위 여백과
     헤더만큼 아래에서 시작하므로, 그 끝이 화면 밖으로 나가려면 한 화면보다 조금 더
     굴려야 한다 — 페이지가 딱 두 화면이라 그 '조금'이 모자라서 이름이 다시 서지
     못했다. 처음에 한 번 보였다가 사라진 채로 끝나는 것이 그 모습이다.
     `vh` 가 아니라 `dvh` 로 잰다. 주소창이 접혔다 펴지는 만큼 `vh` 는 실제 화면보다
     크고, 그 차이가 바로 여기서 모자란 '조금'이 된다. */
  .b-detail .bframe__cue { height: 70dvh; }

  .b-detail .bframe--detail.is-cued .bframe__mark {
    animation: none;
    opacity: 0;
    transition: opacity var(--b-nav-in) var(--b-ease);
  }

  .b-detail .bframe--detail.is-cued.is-past .bframe__mark { opacity: 1; }

  .b-detail .bframe { align-content: end; }
  /* **홈과 같은 표식이 둘째 화면 아래 왼쪽에 선다.**
     모양도 자리도 홈의 것을 따른다 — 홈은 왼쪽 위, 여기는 왼쪽 아래다. 세로만
     뒤집힌 것이고 왼끝은 같다. 가운데로 밀어 보았더니 같은 두 줄인데 다른 덩어리로
     읽혔다: 아래 줄보다 한 칸 들여 선 이름, 그 형태가 왼끝을 기준으로 성립한다.

     `justify-self` 는 폰의 기본값(`start`)이 이미 그것이라 여기서 따로 적지 않는다.
     `.b-detail .bframe { align-content: end }` 가 아래로 내리는 일만 맡는다. */

  /* **두 화면으로 나눈다.** 첫 화면은 글, 둘째 화면은 사진과 옵션이다.
     글 칸에 한 화면을 주고 그 안에서 가운데로 모은다 — 폰에서 글이 짧아 위쪽에만
     붙어 서면, 첫 화면의 아래 절반이 통째로 비어 다음 화면이 시작된 것으로 보인다. */
  /* **위쪽 여백은 목차가 있을 때의 값이다.** 이 화면에서는 목차를 걷었으므로
     9rem 을 비워 둘 이유가 없다 — 글이 화면 한가운데까지 내려와 첫 화면의 위쪽이
     통째로 비어 있었다. 표식 아래에서 바로 시작한다. */
  .b-detail .bdetail { padding-top: 3.5rem; }

  /* **값은 사진 아래로 내려간다.** 첫 화면은 무엇을 주는지를 말하고, 값은 사진을
     다 본 뒤에 읽는다 — 그것이 이 화면에서 값을 묻는 순서다. 글 칸 안의 값은
     화면에서 뺀다(`display: none` 이라 낭독기도 한 번만 읽는다). */
  .b-detail .bdetail__copy .bdetail__price { display: none; }

  .b-detail .bdetail__price--after {
    display: block;
    margin: 0;
    text-align: center;
  }

  /* **글 칸에 한 화면을 주던 것은 걷는다.** 첫 화면을 한 화면으로 못 박아 두었더니
     마지막 줄("데이터는 … 삭제됩니다") 아래가 통째로 비고 사진이 그 밑에서 시작했다.
     두 화면이라는 것은 길이를 재서 만드는 것이 아니라 글·사진·옵션이 차례로 서면
     그만큼 되는 것이다 — 이름이 서는 때는 자(`.bframe__cue`)가 따로 재고 있다.
     사진은 글이 끝나는 자리에 바로 붙는다. */
  /* **이름 아래를 벌린다.** 번호와 이름은 이 화면의 머리고 그 아래는 내용이라,
     같은 간격으로 붙어 있으면 넷이 한 덩어리로 읽힌다. 한 줄만큼 비운다. */
  .b-detail .bdetail__lede { margin-top: 2rem; }

  /* **띠의 위아래만 더 조인다.** 덩어리 사이(row-gap)는 글·값·옵션에도 함께 걸리는
     값이라 거기까지 줄이면 글이 서로 붙는다. 띠에만 음수 여백을 줘서 그 두 자리에서만
     빼낸다 — 사진이 글에 붙고, 값이 사진에 붙는다. */
  .b-detail .bdetail__photos {
    margin-top: -1.7rem;
    margin-bottom: -1.7rem;
  }

  /* 나머지는 조인다 — 값(₩)까지가 첫 화면에 들어와야 한다. 값이 둘째 화면으로
     넘어가면 첫 화면은 무엇을 주는지만 말하고 얼마인지를 안 말하는 화면이 된다. */
  /* 본문(무엇을 주는지) 위도 조인다. 7.8% 는 가로 폭 기준이라 폰에서는 30px 가
     넘는데, 이 화면에서 그만큼은 이끄는 줄과 본문을 따로 선 두 덩어리로 만든다. */
  .b-detail .bdetail__body { margin-top: 1.2rem; }

  .b-detail .bdetail {
    row-gap: clamp(0.6rem, 2vw, 1rem);

    /* **두 화면은 있어야 한다.** 글 칸의 한 화면을 걷고 나니 내용이 한 화면 남짓으로
       줄었고, 그러면 첫 화면 높이를 재는 자(`.bframe__cue`, 100vh)가 화면 밖으로
       나갈 만큼 스크롤할 수가 없다 — 그 자가 나가야 이름이 서는데 나갈 일이 없으니
       이름이 끝내 안 나왔다. 길이는 못 박되(`min-height`) 자리는 못 박지 않는다.
       고정 높이로 상자를 잠그면 안의 것들이 무너진다 — 큰 화면에서 그렇게 만들었다가
       되돌린 적이 있다. 여기서는 최소 길이만 준다. */
    min-height: 200dvh;
  }

  /* **높이 상한은 세로로 든 화면에만 건다.** 가로로 누이면 높이가 절반으로 줄어
     같은 뺄셈이 사진을 손톱만 하게 만든다 — 폰을 눕히는 것은 사진을 크게 보려는
     동작인데 그 반대가 된다. 눕힌 화면은 넘치면 스크롤로 읽는다.

     바닥(6rem)을 둔다 — 아주 낮은 화면에서 뺄셈이 음수가 되면 폭 자체가 무효가
     되어 규칙이 통째로 버려지고, 그러면 다시 큰 사진으로 돌아간다. */
  @media (orientation: portrait) {
    /* 비워 두는 몫이 26rem 에서 15rem 으로 줄었다 — 틀이 없어진 만큼(9 + 8.5 →
       3.5 + 4) 사진이 쓸 수 있는 높이가 늘었다. 연락처 세 줄과 그 아래 숨 쉴
       자리는 그대로 남는다. */
    .bkontakt .bplate { width: min(52vw, 15rem, max(6rem, calc((100dvh - 19rem) * 0.75))); }
  }

  /* 눕힌 화면은 한 화면에 다 넣기를 포기했지만, 그렇다고 세로에서와 같은 크기로
     둘 이유도 없다 — 70vw 는 세로 폭 기준으로 잡은 값이라 눕히면 그것이 화면의
     3분의 2를 가로로 차지한다. 한 단 줄여, 스크롤을 몇 번 덜 하게 한다. */
  @media (orientation: landscape) {
    .bkontakt .bplate { width: min(31vw, 13.5rem); }
  }
  .bkontakt__links { margin-top: 2.5rem; }
}

/* --- 좁은 화면 ----------------------------------------------------------- */
/* 폰에서도 틀은 화면에 고정된다. 좌우로 벌려 세우던 것을 **위아래로** 세울 뿐이다.

   전에는 틀을 통째로 흐름으로 되돌리고 이름과 목차를 왼끝에 붙인 여섯 줄로 폈다.
   그러면 넘기는 순간 둘 다 위로 사라져서, 사진만 남은 화면에서 "여기가 어디이고
   갈 곳이 어디인지"를 잃는다 — 틀이 하는 일이 그것 하나인데 폰에서만 그 일을
   안 하고 있었다. 레퍼런스(aireairestudio.com)도 폰에서 틀을 고정한 채로
   이름을 위, 목차를 아래에 둔다.

   **안의 형태는 데스크톱 그대로다.** MAEY 는 아랫줄보다 한 칸 들여 서고, 목차
   세 줄은 오른끝을 어긋나게 맞춘 계단이다. 폰에서 그 둘을 펴 두었었는데, 편 것은
   좁아서가 아니라 흐름으로 되돌리면서 같이 풀린 것이었다. 390px 에서도 계단의
   폭(7.36 · 10.83vw = 29 · 42px)은 세 줄을 구분하기에 넉넉하다. */

@media (max-width: 860px) {
  /* 틀이 위아래에서 차지하는 높이. 사진이 이 밑으로 들어가지 않게 각 화면이
     이만큼 비운다. 390px 에서 이름 두 줄이 45px · 목차 세 줄이 65px 이고, 거기에
     틀의 여백(4.2 · 2.4rem)과 한 줄 정도의 숨 쉴 자리를 더한 값이다. */
  .skin-b {
    --b-frame-top: 9rem;
    --b-frame-bottom: 8.5rem;

    /* 큰 화면에서 줄이고 모으던 두 값을 여기서는 끈다. 좁은 화면에서 더 줄이면
       읽을 수 없어지고, 더 모으면 사진이 설 폭이 없다. */
    --b-scale: 1;
    --b-inset: 0;
  }

  /* 위아래 끝에 하나씩. 가운데는 비어 있고 그리로 사진이 지나간다. */
  .bframe {
    display: grid;
    align-content: space-between;
    gap: 0;
    padding: 4.2rem var(--b-gutter) 2.4rem;
  }

  /* 데스크톱에서는 각자 절대 좌표로 서 있다. 여기서는 격자가 자리를 정하므로
     그 좌표를 푼다 — 안 풀면 격자 안에서 다시 한 번 밀려 화면 밖으로 나간다.

     **대각선으로 갈라 세운다** — 이름은 왼쪽 위, 목차는 오른쪽 아래. 데스크톱의
     왼쪽 아래·오른쪽 위를 세로로 뒤집은 것이고, 두 덩어리가 화면의 반대 모서리를
     하나씩 잡는다는 뜻은 같다. 가운데로 모아 두었었는데, 그러면 둘이 한 줄기로
     읽혀 위아래로 늘어선 하나의 목록처럼 보인다.

     **`justify-self` 로 덩어리째 옮긴다.** 안에다 `text-align` 을 주면 MAEY 의
     들여쓰기와 목차의 계단이 풀려서 형태가 바뀐다 — 상자를 통째로 옮기면 안의
     형태는 데스크톱 그대로 남는다. */
  .bframe__mark,
  .bframe__index {
    position: static;
    inset: auto;
  }

  .bframe__mark { justify-self: start; }
  .bframe__index { justify-self: end; }

  /* **위아래는 틀이 선 만큼 비운다.** 틀이 흐름 밖이라 자리를 밀어 주지 않는다 —
     비우지 않으면 첫 사진이 이름 밑에, 마지막 사진이 목차 밑에 깔린다.

     **좌우 여백은 두지 않는다.** 판의 자리(`x`)와 크기(`w`)는 페이지 전체 폭 기준의
     %라, 여백을 넣으면 그 안쪽 폭이 기준이 되어 흩뿌린 자리가 통째로 좁아진다.
     레퍼런스도 폰에서 첫 판을 3.3% 자리에 세운다 (여백 없이). */
  .bstream {
    padding-top: var(--b-frame-top);
    padding-bottom: var(--b-frame-bottom);

    /* 가장자리가 그라데이션으로 물러난다. das Fotobuch 도 같은 결인데 그쪽은
       마스크가 깜빡여서 덧대는 천으로 바꿨고(`.bbook::before`), 여기는 판이 한
       줄에 한둘이라 마스크가 다시 잡히는 일이 드물어 그대로 둔다. 값은 눅였다 —
       저쪽은 쉰 칸이 고르게 깔려 있어 양 끝을
       세게 물려도 볼 것이 남지만, 여기는 한 줄에 판이 한둘이라 같은 세기로 물리면
       그 줄에 아무것도 안 남는 자리가 생긴다. 끝을 0.25 에서 시작한다. */
    --b-stream-fade: linear-gradient(90deg,
        rgba(0, 0, 0, 0.25) 0%,
        rgba(0, 0, 0, 0.42) 6%,
        rgba(0, 0, 0, 0.62) 12%,
        rgba(0, 0, 0, 0.82) 18%,
        #000 26%,
        #000 74%,
        rgba(0, 0, 0, 0.82) 82%,
        rgba(0, 0, 0, 0.62) 88%,
        rgba(0, 0, 0, 0.42) 94%,
        rgba(0, 0, 0, 0.25) 100%);
    -webkit-mask-image: var(--b-stream-fade);
    mask-image: var(--b-stream-fade);
  }

  /* **홈의 흩뿌리기는 폰에서도 그대로다.** 한 줄로 세워 두었었는데, 그러면 이 화면이
     하려는 말 — 사진이 놓여 있는 자리 자체가 구성이라는 것 — 이 사라지고 그냥
     사진 목록이 된다.

     **크기는 두 배다.** 시안의 %를 그대로 쓰면 폰에서 가장 작은 판이 47px 이라
     무엇이 찍혔는지 안 보인다 — 레퍼런스가 그 크기로 성립하는 것은 그쪽 사진이
     정물이기 때문이고, 우리 사진은 인물이다. 자리는 그대로 두고 폭만 키운다.

     **오른쪽으로 넘치지 않게 자리를 당긴다.** `x` 는 `x + w <= 100` 을 전제로 잰
     값이라 폭이 두 배가 되면 오른쪽에 선 판이 화면 밖으로 나간다. `min()` 으로
     오른끝에 닿는 자리를 넘지 못하게 한다 — 왼쪽에 선 판은 제 자리를 그대로 쓰고,
     오른쪽 것만 끝에 걸린다. */
  /* **간격도 폭과 같은 배수로 키운다.** 판만 두 배로 하고 `--gap` 을 그대로 두면
     사진은 두 배로 커졌는데 사이는 그대로라, 데스크톱에서 잰 '사진과 사이의 비'가
     절반이 된다 — 실제로 폰에서 위아래가 서로 붙어 한 덩어리로 보였다.
     간격은 %가 가로 폭으로 풀리므로(위 `.bplate` 주석) 곱해서 키운다. 2로 두면
     데스크톱과 같은 비인데, 폰에서는 그것도 빡빡했다 — 큰 화면은 옆으로도 여유가
     있어 판과 판이 가로로 비켜서지만 폰은 한 장이 폭의 절반이라 위아래만 남는다.
     2.6 → 3.4 로 한 번 더 올렸고, 바닥도 7% 에서 11% 로 함께 올린다.

     **음수 간격은 여기서만 걷는다.** 시안에 붙어 올라오는 판이 셋 있는데(-11.28,
     -8.75, -1.34), 데스크톱에서 그것이 겹쳐 보이지 않는 것은 두 판이 가로로 멀리
     떨어져 있기 때문이다 — 위로 당겨도 서로의 옆을 지날 뿐이다. 폰에서는 폭이 두
     배이고 오른쪽 판은 `min()` 으로 끝에 당겨 서므로 그 가로 여유가 사라져서,
     같은 음수가 그대로 **사진이 사진을 덮는** 것이 된다.
     `max()` 로 바닥을 둔다 — 아무리 당겨도 3%(폭 기준)는 벌어진다. */
  /* **가로 자리는 시안의 `x` 를 버리고 좌우로 번갈아 세운다.** 폭이 두 배가 되면서
     여덟 장 중 절반이 40~55% 자리에 몰려, 시안에서는 흩뿌려 보이던 것이 폰에서는
     가운데로 늘어선 한 줄처럼 보였다 — `x` 는 판이 폭의 1/4 일 때 성립하는 값이다.
     홀수는 왼쪽, 짝수는 오른쪽. 폭은 판마다 그대로 다르므로 한 줄로 세운 것과는
     달리 리듬이 남는다.

     바깥쪽은 3% 만 남긴다. 레퍼런스도 폰에서 첫 판을 그쯤에 세운다 — 0 으로 두면
     사진이 화면을 물고 판이 아니라 배경처럼 읽힌다. */
  .bstream .bplate {
    width: calc(var(--w, 22) * 2%);
    margin-inline: 3% auto;
    margin-top: max(11%, calc(var(--gap, 6) * 3.4%));
  }

  .bstream .bplate:nth-child(even) { margin-inline: auto 3%; }

  /* **번갈이는 바탕이고, 몇 장은 거기서 벗어난다.** 여덟 장이 예외 없이 좌·우·좌로
     서면 겹침은 사라지지만 이번에는 지그재그라는 무늬가 화면을 대신 말한다.
     시안이 흩뿌린 화면이었던 이유는 자리가 규칙이 아니라 우연으로 보여서다.

     **둘째·셋째는 위로 당긴다.** 시안에서도 이 둘은 앞 장에 붙어 오른다(-11.28,
     0.71). 좌우로 갈라 세운 지금은 서로의 옆을 지나므로 당겨도 덮이지 않는다 —
     겹침을 막으려고 둔 3% 바닥은 그 사실을 모르는 규칙이라, 아는 자리에서만 뺀다.

     **여섯째·일곱째는 가장자리에서 뗀다.** 화면 안쪽 어중간한 자리에 서면 그
     둘만으로 좌우 번갈이의 결이 흐트러져, 나머지가 다시 우연처럼 읽힌다. */
  .bstream .bplate:nth-child(2) { margin-top: -9%; }

  /* 셋째는 가운데보다 왼쪽에 선다. 좌·우·좌로 이어지던 것이 여기서 한 번 끊긴다 —
     당겨 올린 자리라 위의 오른쪽 판과 나란히 서므로, 왼쪽으로 갈수록 그 판에서
     멀어진다. 왼끝에 붙이지는 않는다 — 붙이면 다시 번갈이의 한 자리가 된다. */
  .bstream .bplate:nth-child(3) {
    /* **제 높이만큼 내려 선다.** 이 판은 폭이 24.2% 라 높이가 32% 쯤 되고, 그만큼을
       위에 비운다 — 위로 당겨 두었더니 앞 판과 한 덩어리로 읽혔다. 아래는 넷째가
       같은 만큼 비우므로 위아래가 함께 열린다. */
    margin-top: 32%;
    margin-inline: 15% auto;
  }

  /* 넷째부터 일곱째까지도 사이를 넓힌다. 이 넷은 시안의 간격이 2.9~4.5% 로 촘촘한
     자리인데, 폰에서는 판이 두 배라 그 촘촘함이 '붙어 있음'이 된다. */
  .bstream .bplate:nth-child(4),
  .bstream .bplate:nth-child(5),
  .bstream .bplate:nth-child(6),
  .bstream .bplate:nth-child(7) { margin-top: 24%; }

  .bstream .bplate:nth-child(6) { margin-inline: 46% auto; }
  .bstream .bplate:nth-child(7) { margin-inline: 14% auto; }

  /* **마지막 한 장은 아래 한가운데에 선다.** 좌·우로 번갈아 가던 것이 여기서 멎는다 —
     끝이 한쪽에 붙어 있으면 줄기가 끝난 것이 아니라 다음 장이 빠진 것으로 보인다.

     **자리는 여기가 마지막이어야 한다.** 위쪽에 적어 두었더니 여덟째가 짝수라
     `:nth-child(even)` 이 같은 특정도로 뒤에서 이겨, 이 줄이 있는데도 오른쪽에
     붙어 섰다. 같은 무게의 규칙끼리는 나중에 적힌 것이 이긴다. */
  .bstream .bplate:last-child { margin-inline: auto; }

  /* **폰의 사진은 좌우로 넘긴다.** 위아래로 세우면 다섯 장이 다섯 화면이 되어,
     글과 값이 첫 화면에 한 번 나오고 나머지는 사진만 남는다. 옆으로 넘기면 다섯
     장이 한 화면 안에 있고, 넘기는 동안에도 이 종목이 무엇인지가 곁에 남는다.

     **한 번에 세 장이 보인다.** 가운데 한 장이 온전하고 양옆은 절반쯤 잘려 걸친다 —
     옆의 것이 보이는 것 자체가 '더 있다'는 표시라, 점이나 화살표를 그리지 않아도 된다.

     좌우 여백(`padding-inline`)이 판 폭의 절반이라 첫 장과 마지막 장도 가운데에
     설 수 있다. 없으면 그 둘만 끝에 붙어 서서 양옆이 비어 보인다.
     `scroll-snap` 으로 늘 한 장이 가운데에 멎는다 — 사진이 어중간하게 걸린 채로
     멈추면 무엇을 보는 화면인지가 흐려진다. */
  .bdetail__photos {
    /* **가운데 한 장이 화면의 대부분을 쓴다** (62 → 54 → 70%). 한 번 줄였다가
       다시 키운 값이다 — 작게 두면 세 장이 고르게 늘어서서 어느 것을 보는 화면인지가
       흐려진다. 지금은 가운데가 확실히 크고 양옆은 한 뼘씩만 걸린다.

       **높이가 이 값의 상한을 정한다.** 띠의 높이는 판 폭에서 나오므로(3:4) 폭을
       키우면 띠가 그만큼 높아지고, 아래의 값이 첫 화면 밖으로 밀린다 — 70% 에서
       실제로 그렇게 됐다. 값까지가 첫 화면 안에 있어야 하므로 62% 가 이 화면에서
       쓸 수 있는 크기다. 양옆은 그래도 대부분 잘려 나간다. */
    --b-slide: 62%;
    display: flex;
    gap: clamp(0.6rem, 2.5vw, 1.1rem);
    padding-inline: calc((100% - var(--b-slide)) / 2);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }

  .bdetail__photos::-webkit-scrollbar { width: 0; height: 0; }

  .bdetail__photos .bplate {
    flex: 0 0 var(--b-slide);
    width: var(--b-slide);
    max-width: none;
    margin: 0;
    scroll-snap-align: center;
    /* 가운데에서 멀수록 옅어지고 작아진다. 값은 `skin-b.js` 가 넘길 때마다
       고쳐 쓴다 — 스크롤 자리에 따라 달라지는 것이라 CSS 에 적을 수 없다.
       자바스크립트가 막히면 다섯 장이 모두 또렷한 채로 남고, 그것이 이 화면에서
       잃을 것이 가장 적은 모습이다. */
    transition: opacity 220ms linear, transform 220ms linear;
  }

  /* 넘기는 띠에서는 '도착하며 커지는' 모션을 끈다. 가로로 잘려 있는 판은 관찰기가
     '아직 안 들어왔다'고 보아 작고 흐린 채로 남고, 그 위에 아래의 자리별 값이
     겹쳐 두 겹으로 흐려진다. */
  .bdetail__photos .bplate.b-grow img,
  .bdetail__photos .bplate.b-grow .bplate__name {
    opacity: 1;
    transform: none;
  }

  /* 종목 상세는 겹치기를 푼다. 폭이 없으면 글과 사진이 가로로 비켜설 자리가 없어
     그대로 포개진다. 위에서 아래로 읽는 한 줄기로 돌아온다. */
  .bdetail {
    padding-inline: var(--b-gutter);
    padding-top: var(--b-frame-top);
    padding-bottom: var(--b-frame-bottom);
    row-gap: clamp(3rem, 9vw, 6rem);
  }

  .bdetail > * { grid-area: auto; }

  .bdetail__copy,
  .bdetail__side,
  .bdetail__side.is-early {
    margin-left: 0;
    margin-top: 0;
    width: 100%;
    text-align: center;
  }

  .bdetail__photos { margin-top: 0; }
  .bdetail__price { margin-top: 2.5rem; }

  /* 다섯 열이 서면 읽을 수 없는 크기가 된다. 두 열로 접는다 — 옆으로 넘기는 띠로
     두면 열다섯 장을 한 장씩 넘겨야 해서, 이 화면이 하려는 '한눈에 보이는 판'이
     사라진다. */
  /* 목차의 치우친 자리는 폭이 있어야 성립한다. 43% 자리에 25% 폭이면 폰에서
     번호 한 개도 못 들어간다. 가운데로 되돌린다. */
  /* 가운데에 모으되 한 뼘 위로. 아래를 더 비우면 덩어리가 그만큼 올라간다 —
     화면의 정가운데는 목록이 서기에는 조금 낮다. 눈이 먼저 닿는 자리가 위쪽이다. */
  .bindex {
    align-content: center;
    padding: var(--b-frame-top) var(--b-gutter) calc(var(--b-frame-bottom) + 10dvh);
  }
  /* **덩어리는 가운데, 줄은 왼쪽 정렬이다.** 줄마다 따로 가운데 정렬하면 이름
     길이가 달라 번호의 왼끝이 세 줄 다 어긋난다 — 목록이 아니라 흩어진 세 줄이
     된다. 상자를 내용 폭(`max-content`)으로 줄여 통째로 가운데에 놓고, 그 안에서는
     왼끝을 맞춘다. 가장 긴 줄이 상자의 폭을 정하고 나머지가 그 왼끝에 선다. */
  .bindex__list {
    margin-inline: auto;
    width: max-content;
    max-width: 100%;
  }

  /* **한 줄이 화면 가운데에 선다.** 왼끝에 붙여 두었더니 번호가 왼쪽 여백에 갇히고
     오른쪽이 통째로 비어, 세 줄이 화면이 아니라 화면의 왼쪽 절반에만 있는 목록으로
     보였다. 폰의 틀은 이름이 왼쪽 위 · 목차가 오른쪽 아래라 그 사이가 비는데,
     그 빈 가운데가 이 목록의 자리다.

     **두 칸을 내용 폭으로 줄인다.** 둘째 칸을 `1fr` 로 두면 이름이 남은 폭을 다
     차지해서, 상자를 아무리 줄여도 줄은 화면 폭 그대로 남는다. 가운데로 미는 일은
     상자(`.bindex__list`)가 맡는다. */
  .bindex__list a {
    grid-template-columns: auto auto;
    justify-content: start;
    gap: 0 0.8em;
  }

  /* 줄 사이를 좁힌다. 셋뿐이라 넓게 두면 한 목록이 아니라 따로 선 세 줄이 된다. */
  .bindex__list a + a { margin-top: 1rem; }
  /* **이름은 번호와 가로로 나란히 선다.** 데스크톱은 이름을 번호의 어깨에 붙여
     내려 달지만(시안), 폰에서는 번호가 화면 폭의 절반을 쓰고 이름이 그 옆에
     한 줄로 서므로 밑선에 맞추면 이름만 아래로 처져 두 조각으로 읽힌다.
     번호 상자의 세로 가운데에 맞춘다 — 한 줄이 한 줄로 읽힌다. */
  .bindex__list em { margin-top: 0; align-self: center; }

  .bbook { padding: var(--b-frame-top) var(--b-gutter) var(--b-frame-bottom); }

  /* **폰에서는 다섯 열을 세우지 않는다.** 레퍼런스는 어느 폭에서나 다섯 열이지만
     그 화면의 사진은 하나같이 옅고 작아도 되는 것들이다. 우리 사진은 인물이라
     한 변이 60px 이 되면 무엇이 찍혔는지 안 보인다. 두 열로 접는다.
     **크기도 흩뜨리지 않는다** — 두 열에서 칸의 40% 만 차지하는 판은 그냥
     안 보이는 사진이 된다. 들쭉날쭉은 다섯 열의 여유가 있어야 성립한다. */
  .bspread {
    /* 사이를 넓힌다. 판이 크고 수가 적을수록 사이가 좁으면 두 장이 한 덩어리로
       읽힌다 — 다섯 열에서는 판이 작아 같은 값이 넉넉했다. */
    --b-spread-gap: clamp(1.7rem, 8vw, 3.4rem);
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--b-spread-gap);
    align-items: start;
  }

  /* **두 장 아래 한 장이 되풀이된다** (종목 상세와 같은 결이다). 두 열로만 세우면
     같은 크기가 열 줄 반복되어 격자가 아니라 표가 된다. 셋째 장마다 줄을 통째로
     쓰되 폭은 한 칸만 쓰고 가운데에 서서, 양옆의 빈 자리가 줄의 쉼표가 된다. */
  .bspread .bplate:nth-child(3n) {
    grid-column: 1 / -1;
    width: calc((100% - var(--b-spread-gap)) / 2);
    justify-self: center;
  }

  /* **크기는 살짝만 흩뜨린다.** 다섯 열에서 쓰던 0.4~1.0 을 그대로 두면 폰에서
     가장 작은 판이 안 보이는 사진이 되고, 1 로 고정하면 열 줄이 똑같은 표가 된다.
     같은 `--w` 를 좁은 띠로 옮긴다 — 판마다 다르되 무엇이 찍혔는지는 어느 판에서나
     보인다. 줄어든 만큼이 그대로 판 둘레의 빈 자리가 되므로, 띠를 넓히면 크기가
     갈리는 것과 사이가 벌어지는 것이 한꺼번에 온다.
     **셈을 한 번 틀렸다.** `--w` 는 40~100 이므로 `a + w*b` 의 `a` 는 시작값이
     아니라 절편이다 — 0.52 를 절편에 넣었더니 큰 판이 1.32 배가 되어, 칸을 넘어
     이웃을 밀고 사이가 사라졌다. 화면에서 '어떤 사진은 너무 크고 공백은 없다'로
     보이던 것이 이것이다.
     절편으로 다시 적는다: 0.44~0.88 이므로 b = (0.88-0.44)/60, a = 0.44 - 40b.
     **위 끝을 1 아래(0.88)로 둔다** — 1 이면 가장 큰 판이 제 칸을 꽉 채워, 그 줄만
     사이가 `gap` 하나로 줄어든다. 판마다 남기는 둘레가 이 화면의 여백이다. */
  .bspread .bplate {
    --s: calc(0.147 + var(--w, 60) * 0.00733);
    width: 100%;
    max-width: none;
  }

  .bspread .bplate img { max-height: none; }

  /* **가장자리를 물리는 것도 그만둔다.** 두 열뿐인 화면에서 양옆을 옅게 하면
     볼 것이 가운데 빈 자리 한 줄기만 남는다. 가운데와 가장자리가 구분되려면
     다섯 열의 여유가 있어야 한다. */
  .bspread::before,
  .bspread::after { display: none; }
}


/* --- 모션 ---------------------------------------------------------------- */
/* 두 가지만 움직인다. 더 넣지 않는다 — 사진을 보러 온 화면에서 움직이는 것이
   늘어나면 사진이 아니라 움직임을 보게 된다.

     글자   틀이 자리를 잡는 순서를 보여준다. 왼쪽에서 제자리로 한 번.
     사진   "이 사진이 지금 도착했다"를 말한다. 작게 들어와 제 크기가 된다.

   `transform` 과 `opacity` 만 건드린다. 그 둘만이 레이아웃을 다시 계산하지 않는다.
   움직임을 원하지 않는다고 말한 사람에게는 아무것도 움직이지 않는다. */

@media (prefers-reduced-motion: no-preference) {

  /* 글자 — 왼쪽에서 들어와 제자리에 선다. 한 번뿐이고 반복하지 않는다. */
  @keyframes b-slide-in {
    from { opacity: 0; transform: translateX(-2.2rem); }
    to   { opacity: 1; transform: none; }
  }

  /* 목차는 옅은 회색에서 검정으로 짙어지며 들어온다. 검정에서 시작하면 글자가
     '들어온다'가 아니라 '켜진다'로 읽힌다. 색은 사본이 들고 있으므로 사본을
     칠한다 — `a` 자신은 투명한 자리표시자다. */
  @keyframes b-nav-ink {
    from { color: var(--b-nav-start); }
    to   { color: var(--b-nav-ink); }
  }

  .bframe__mark {
    animation: b-slide-in var(--b-enter) var(--b-ease) both;
  }

  /* **이름이 다 선 다음에 목차가 나온다.** 시작점이 `--b-enter` 라 이름의 길이를
     고치면 목차도 그만큼 뒤로 밀린다 — 두 값을 따로 맞출 일이 없다.
     세 줄은 한 몸처럼 들어오지 않고 차례로 서서 계단을 눈으로 따라가게 한다. */
  .bframe__index a {
    animation: b-slide-in var(--b-nav-in) var(--b-ease) both;
    animation-delay: calc(var(--b-nav-after) + var(--i) * var(--b-nav-step));
  }

  .bframe__index a::before {
    animation: b-nav-ink var(--b-nav-in) var(--b-ease) both;
    animation-delay: calc(var(--b-nav-after) + var(--i) * var(--b-nav-step));
  }

  .bframe__index a:nth-child(1) { --i: 0; }
  .bframe__index a:nth-child(2) { --i: 1; }
  .bframe__index a:nth-child(3) { --i: 2; }

  /* 사진 — 화면에 들어오면 작게 시작해 제 크기가 된다.

     **작아지는 상태는 자바스크립트가 붙인다** (`b-grow`). CSS 에 처음부터 적어 두면
     스크립트가 막힌 방문자에게 사진이 작고 흐린 채로 남는다. 붙지 않으면 아래
     규칙들은 아무것도 고르지 못하고, 사진은 그냥 제 크기로 보인다.

     CSS 의 스크롤 구동 애니메이션으로 먼저 만들었는데 타임라인이 활성화되지 않았고
     (사파리도 아직 안 받친다), 그래서 어디서나 도는 쪽으로 바꿨다. */
  /* **판이 아니라 그 안의 그림을 키운다.** 판에 걸면 판이 이미 쓰고 있는 값을
     덮어써서 그 화면의 구성이 사라진다 — das Fotobuch 는 양 끝 판이 물러나 있는
     것(opacity 0.32 · 0.72)과 세로로 어긋난 것(translateY)이 곧 구성인데,
     판을 1.0 으로 올리고 scale 로 덮으면 둘 다 지워진다. 그래서 그 화면만
     모션에서 빼 두었었다.

     안쪽에 걸면 겹쳐진다: 판의 0.32 에 그림의 0.25 가 곱해지고, 판의 translateY
     위에서 그림만 커진다. 빼야 할 화면이 없어진다. */
  /* **작은 상태에는 전환을 걸지 않는다.** 여기에 `transition` 을 두면 작아지는
     것 자체가 2.6초짜리 전환이 되어, 30ms 뒤에 `is-in` 이 붙는 판은 작아지기도
     전에 되돌아온다 — 재보니 시작값이 0.25 가 아니라 0.97 이었다.
     시작 자리는 즉시 잡고, 전환은 돌아오는 쪽이 갖는다. */
  .bplate.b-grow img,
  .bplate.b-grow .bplate__name {
    opacity: 0.25;
    transform: scale(0.78);
    transform-origin: center 65%;
  }

  .bplate.b-grow.is-in img,
  .bplate.b-grow.is-in .bplate__name {
    opacity: 1;
    transform: none;
    transition: opacity var(--b-photo-in) var(--b-ease),
                transform var(--b-photo-in) var(--b-ease);
  }

  /* das Fotobuch 는 다른 모션을 쓴다 — 커지는 것이 아니라 **아래에서 올라온다.**
     격자는 자리가 정해져 있어서 하나하나가 커지면 칸이 들썩이는 것으로 보이고,
     쉰 칸이 그러면 화면이 끓는다. 판째로 움직이므로 안쪽이 아니라 판에 건다.

     어긋남(`--col`)은 첫 화면에서만 붙는다. 스크롤로 만나는 줄은 0 이라 한 줄이
     한 번에 올라온다 — 그것이 레퍼런스의 두 가지 결이다.

     **판이 이미 쓰고 있는 `scale(--s)` 를 지우지 않는다.** `transform: none` 으로
     되돌리면 판마다 다른 크기가 도착과 동시에 1.0 으로 튄다. 두 값을 한 줄에
     같이 쓴다 — 레퍼런스의 GSAP 도 같은 판에 scale 과 y 를 함께 얹는다.

     **목차 세 줄(das Produkt)도 같은 모션이다.** 레퍼런스의 목록 화면
     (aireairestudio.com/services)이 이것이고, 값도 같다 — 위에서부터 한 줄씩
     0.35초 어긋나 올라온다. 판이 아니라 글이지만 하는 말이 같다. */
  .bplate.b-rise,
  .bindex__list a.b-rise {
    opacity: 0;
    transform: translateY(var(--b-rise-lift)) scale(var(--s, 1));
  }

  /* **목차는 1 로 도착하지 않는다.** 도착점은 쉬는 진하기(`--b-idx-op`)다 —
     여기서 1 을 적으면 모션이 끝난 뒤 세 줄이 새까맣게 서고, 손이 닿아 짙어질
     자리가 없어진다. 사진 판은 그대로 1 이다. */
  .bplate.b-rise.is-in { opacity: 1; }
  .bindex__list a.b-rise.is-in { opacity: var(--b-idx-op); }

  .bplate.b-rise.is-in,
  .bindex__list a.b-rise.is-in {
    transform: scale(var(--s, 1));
    transition: opacity var(--b-rise) var(--b-rise-ease),
                transform var(--b-rise) var(--b-rise-ease);
    transition-delay: calc(var(--col, 0) * var(--b-rise-step));
  }

  /* 첫 화면은 한 칸씩 더 오래 들어온다 (레퍼런스 2s). */
  .bplate.b-rise.is-first.is-in { --b-rise: 2000ms; }

  /* **목차 세 줄은 사진 격자와 값이 다르다.** 격자의 2초 · 0.35초 어긋남은 쉰 칸이
     서로 겹치며 밀려 올라오는 것을 전제로 한 값이라, 세 줄에 그대로 쓰면 셋이
     거의 동시에 흐릿하게 떠올랐다 — 도착점도 0.38 이라 변화 자체가 옅다.
     한 줄이 다 서고 나서 다음 줄이 뜨도록 **어긋남을 길게, 전환을 짧게** 한다.
     0.12초 뒤 000, 0.72초 뒤 001, 1.32초 뒤 002 순으로 하나씩 선다 —
     어긋남(0.6초)이 전환(0.5초)보다 길어서 **한 줄이 다 서고 나서 다음이 뜬다.**
     한 번 늘렸다가 다시 당긴 값이다: 셋이 겹쳐 보이지 않는 선에서 가장 짧다. */
  .bindex__list a.b-rise.is-in {
    --b-rise: 500ms;
    transition-delay: calc(120ms + var(--col, 0) * 600ms);
  }
}
