/* ══════════════════════════════════════════════════════════════════════════
   banner.css — 화면 맨 위의 **띠 한 장**. 홈(`/`)과 목록(`/links/`)이 같이 쓴다.

   ── 왜 셸에 있나 ──
   처음에는 두 화면이 각자 자기 CSS 에 배너를 갖고 있었다. 값은 «같아야 한다» 고 정해 놓고
   복사해 둔 것이라, 한쪽만 고치는 순간 갈렸다 — 실제로 폭이 80px 어긋난 채로 배포 직전까지
   갔다(`margin-inline` 계산을 한쪽에서만 고쳤다). 두 화면이 **같아야 하는 것**은 한 곳에
   있어야 한다. 그 자리가 셸이다(나브·단추·서랍·꼬리와 같은 층).

   ── 무엇이 여기 있고 무엇이 화면에 남나 ──
   여기: 띠의 기하(전면 흘림·높이·여백) · 바탕(막 + 사진) · 글 블록(눈썹·제목·리드).
   화면: 그 띠 **안의 배치**. 홈은 12단 격자에 터미널을 함께 놓고(`home.css`), 목록은
         글 블록만 세운다(`links.css`). 내용(문구)도 각 화면의 것이다.

   ── 쓰는 법 ──
       <section class="cover band">   ← 홈: 띠 + 자기 격자
       <header  class="banner band">  ← 목록: 띠만

   사진은 서버가 요청마다 한 장 골라 인라인 변수로 실어 준다
   (`links/views.py` 의 `pick_banner_photo` 가 `--banner-photo` 에 사진 주소를 넣는다).

   ⚠️ **CSS 주석에 «url 함수 + 경로» 꼴을 쓰지 말 것.** prod 의 `ManifestStaticFilesStorage`
   는 CSS 를 정규식으로 훑어 그 꼴을 전부 «실제 참조» 로 보고 파일을 찾는다 — 주석 안이어도
   마찬가지다. 여기 있던 예시 문구가 `css/shell/` 아래의 없는 파일을 가리켜 `collectstatic`
   이 `ValueError: The file … could not be found` 로 멈췄다(최초 운영 배포에서 실측).
   설명이 필요하면 지금처럼 **함수 이름을 쓰지 않고** 풀어 적는다.
   ══════════════════════════════════════════════════════════════════════════ */

/* 띠가 지면의 첫 구획이면 **머리에 붙고**, 그 아래로 지면의 여백을 옮겨 준다.
   띠는 본문이 아니라 머리 쪽 층이라 머리와의 사이가 벌어지면 떠 보인다. 그래서 지면이 내는
   위 여백(`--gap-shell`)을 상쇄하고, 같은 값을 아래에 다시 놓는다 — 상쇄만 하면 띠와 첫
   구획이 0px 으로 붙는다(실측). 결과는 어느 화면이든 «머리 0 · 띠 아래 40 · 꼬리 위 40». */
#main > .band:first-child {
	margin-top: calc(-1 * var(--gap-shell));
	margin-bottom: var(--gap-shell);
}

.band {
	/* 내용은 **세로 가운데**다. 띠가 내용보다 높으므로(하한 463px) 위로 붙이면 아래가 텅 빈다.
	   홈은 이 자리를 12단 격자로 덮어쓰지만(`home.css`) 거기서도 `align-items: center` 라
	   결과는 같다 — 기본값을 여기 두는 이유는 새 화면이 배너를 쓸 때 «가운데» 를 다시 정하지
	   않아도 되게 하기 위해서다. 컴포넌트로 뽑을 때 목록에서 이 선언이 빠져 그 화면만 위로
	   붙었다(사용자 지적). */
	display: flex;
	flex-direction: column;
	justify-content: center;

	/* ── 화면 끝까지 ── 사진은 **지면 밖으로 흘리고**, 글자는 지면 격자에 그대로 둔다.
	   `50% - 50vw` 로 지면 여백만큼 밖으로 나가고, 같은 값을 안쪽 여백으로 되돌려 준다 —
	   그래서 제목의 왼쪽 끝이 아래 본문의 왼쪽 끝과 정확히 같은 자리에 선다.

	   `calc()` 안에서 `%` 는 **자기 부모 폭**이고 `vw` 는 **뷰포트 폭**이다. 그 차이가 곧
	   지면 여백이다. 한때 `max(--gutter, (100% - --page-max)/2)` 로 계산했다가 뒤 항이 0 이
	   되어(부모가 이미 지면 폭이다) 거터 하나만큼만 나갔고, 두 배너의 폭이 갈렸다(실측 +80px).
	   `vw` 는 세로 스크롤바를 포함하므로 `html { overflow-x: clip }` 이 짝이다
	   (`shell/base.css`). */
	margin-inline: calc(50% - 50vw);
	padding-inline: calc(50vw - 50%);
	/* 띠 밖으로는 아무것도 나가지 않는다. 안에 절대 배치된 것(터미널의 막은 `::before` 로
	   좌우 21.6px 을 넘겨 그린다)이 있으면 그만큼이 지면을 넓힌다 — 좁은 화면에서 홈이
	   20~244px 가로로 넘쳤다(실측). `hidden` 이 아니라 `clip` 이다: 스크롤 컨테이너를 만들지
	   않아 안쪽의 고정 요소·앵커 이동이 그대로 산다. */
	overflow: clip;

	/* 높이는 **두 화면이 같다.** 홈의 띠는 내용이 정하고(오른쪽 터미널) 목록은 그 값을 하한으로
	   받는다. 좁은 화면(≤64rem)에서 홈은 651~699px 까지 자란다 — 터미널이 글 아래로 쌓이기
	   때문이다. 목록은 따라가지 않는다: 그 자리를 채울 것이 없어 빈 띠가 된다. */
	min-height: 28.9375rem;   /* 463px — 홈의 내용(터미널)이 만드는 높이. 실측 1100~1920px 동일.
	                             홈의 내용이 늘어 이 값을 넘으면 두 화면이 갈리므로 그때 함께
	                             고친다(그래서 숫자가 한 곳에만 있다). */
	padding-block: 2.5rem 1.875rem;

	/* ── 바탕 = 막 + 사진 ──
	   막이 없으면 대비가 «사진에 따라 움직이는 값» 이 된다(실측 1.0:1). 두꺼운 구간(near)이
	   글 밑을 덮고, 그 바깥(far)에서 사진이 드러난다.

	   `--banner-veil-stop` 은 **글이 어디까지 가느냐**로 정한다. 넓은 화면에서 글은 왼쪽
	   38% 안에 머물지만 좁아지면 더 오른쪽까지 간다 — 900px 에서 리드가 68% 지점까지 가
	   옅은 구간에 걸렸다(실측 4.48:1, AA 미달). 아래 미디어쿼리가 그 구간을 늘린다.
	   막을 두껍게 하는 것이 아니라 **구간을 늘리는** 것이다: 사진이 보이는 쪽은 그대로 둔다. */
	--banner-veil-stop: 38%;
	background-image:
		linear-gradient(100deg,
			var(--banner-veil-near) 0 var(--banner-veil-stop),
			var(--banner-veil-far) 100%),
		var(--banner-photo, none);
	background-repeat: no-repeat;
	background-position: center;
	background-size: cover;

	/* 아래 경계. 사진이 띠의 끝을 이미 보여 주지만, 사진이 흐린 쪽으로 끝나면 경계가 사라진다
	   (사진은 매번 바뀐다) — 선이 그 경우에도 «여기까지가 머리» 를 말한다.
	   홈에만 있고 목록에는 없었다: 컴포넌트로 뽑기 전에는 이 선이 `.cover` 에 있었기 때문이다
	   (사용자 지적). 두 화면이 같아야 하는 것은 여기 있어야 한다. */
	border-bottom: 1px solid var(--line-strong);
}

/* ── 막의 기하는 **뷰포트로 잰다**(컨테이너 질의로 바꾸지 않았다) ──
   이 띠는 전면 흘림이라 **자기 폭이 곧 뷰포트 폭**이다(`margin-inline: 50% - 50vw`). 컨테이너
   질의는 «자기 자신» 을 대상으로 걸 수 없으므로 감싸는 요소를 새로 만들어야 하는데, 그렇게
   얻는 값이 없다 — 뷰포트 질의가 이미 정확히 띠의 폭이다. 나머지 화면 규칙은 지면 폭으로
   옮겼지만(`#main` 컨테이너) 여기만 예외이고, 그 이유가 이것이다.

   64rem 아래에서는 글이 띠의 3분의 2까지 간다 — 두꺼운 구간을 그만큼 늘린다. */
@media (max-width: 64rem) {
	.band {
		--banner-veil-stop: 76%;
	}
}

/* 48rem 아래에서는 글이 띠 전체를 가로지른다 — 구간으로는 못 덮으므로 막 자체를 두껍게 한다.
   사진이 **매번 바뀌므로** 기준은 «이 사진» 이 아니라 «어떤 사진이 와도» 다(순검정·순백으로
   잰다). 필요한 두께는 계산으로 나온다: 리드 잉크 기준 양쪽 모두 α ≥ 0.86 → 0.90. */
@media (max-width: 48rem) {
	.band {
		--banner-veil-far: rgba(255, 255, 255, 0.9);
	}

	:root[data-theme='dark'] .band {
		--banner-veil-far: rgba(13, 17, 23, 0.9);
	}
}

@media (max-width: 48rem) and (prefers-color-scheme: dark) {
	:root:not([data-theme='light']) .band {
		--banner-veil-far: rgba(13, 17, 23, 0.9);
	}
}

/* ── 글 블록 ── 눈썹 · 제목 · 리드. 화면들이 같은 규격을 쓰고 **문구만 다르다.**

   **눈썹은 «이 화면이 무엇인가» 를 말한다** — 화면마다 다른 낱말이어야 한다:
     홈 `overview`(현황) · 목록 `link catalog` · 상세 `service entry` · 실험 `experiments`.
   한때 넷 중 셋이 `link catalog` 였다 — 그러면 눈썹이 화면을 구분하지 못하고, 사이트 이름을
   두 번 말하는 줄이 된다(앞자리가 이미 `popupstudio` 다). 상세의 `service entry` 는 본문
   레일의 「ENTRY」와 같은 말을 쓴다: 같은 것을 두 이름으로 부르지 않는다. */

.band-eyebrow {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.55rem;
	margin: 0 0 clamp(0.7rem, 1.5vh, 1rem);
	font-family: var(--font-mono);
	font-size: var(--t-micro);
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--fg-3);
}

/* 짧은 선. 가운뎃점보다 «색인» 의 인상이 강하다. **마지막 낱말 뒤에도 하나 둔다** — 사이에만
   있으면 줄이 «아직 안 끝난 목록» 처럼 보이고, 끝에 하나가 더 있어야 닫힌 표시로 읽힌다. */
.band-eyebrow i {
	width: 1.5rem;
	height: 1px;
	background: var(--line-strong);
}

/* `letter-spacing` 은 마지막 글자 **뒤에도** 공백을 붙인다 — 낱말마다 그 몫을 되돌려야
   양옆의 선 길이가 같아 보인다. */
.band-eyebrow span {
	margin-right: -0.2em;
}

/* 띠의 유일한 큰 것. 자간을 좁히는 이유는 크기가 커질수록 글자 사이가 실제보다 넓어 보이기
   때문이다(광학 보정). 줄 간격도 1 아래로 당겨 두 줄이 한 덩어리가 되게 한다. */
.band-title {
	margin: 0;
	font-size: clamp(1.6rem, 2.6vw, 2.35rem);
	font-weight: 700;
	line-height: 0.98;
	letter-spacing: -0.045em;
	color: var(--fg);
	word-break: keep-all;
}

.band-line {
	display: block;
}

/* 동사 하나만 액센트. 문장 전체를 칠하면 강조가 사라지고, 명사를 칠하면 «무엇» 이 강조되는데
   이 띠가 파는 것은 **하는 일**이다. */
.band-title em {
	font-style: normal;
	color: var(--accent);
}

/* 폭은 `ch` 가 아니라 `rem` 이다 — `ch` 는 «0» 한 글자 폭이라 한글에는 맞지 않는다
   (42ch 로 두었더니 한 줄에 들어갈 문장이 「…좁혀 / 봅니다.」로 끊겼다, 실측). */
/* 설명은 **줄 길이를 맞춰 끊는다**(`text-wrap: balance`). 브라우저 기본은 «한 줄을 끝까지
   채우고 남은 것을 다음 줄로» 라, 두 줄이 될 때 위가 꽉 차고 아래가 토막으로 남는다
   (실측 1440px: 홈 432/255 · LAB 544/152). 균형을 켜면 두 줄이 비슷해진다(354/333 · 339/360).

   낱말 단위는 `word-break: keep-all` 이 지킨다 — 한글은 기본값이 음절 사이에서도 끊어서
   「한곳에 / 둡니다」 가 아니라 「한곳에 둡니 / 다」 가 될 수 있다. 이 둘이 한 쌍이다:
   `keep-all` 이 «어디서 끊을 수 있나» 를, `balance` 가 «그중 어디서 끊나» 를 정한다.

   `<br>` 을 박지 않는 이유: 지면 폭이 셋(표지 434px · 배너 544px · 모바일 358px)이라 한 자리에
   고정하면 어느 폭에서는 반드시 어긋난다. */
.band-lede {
	max-width: 34rem;
	margin: clamp(0.9rem, 2vh, 1.3rem) 0 0;
	font-size: var(--t-base);
	line-height: 1.65;
	color: var(--fg-2);
	word-break: keep-all;
	text-wrap: balance;
}
