/*
 * 서체
 *
 * 라틴 문자를 먼저 두고 한글을 뒤에 둔다. 브라우저는 글자마다 스택을 훑어
 * 그 글자를 가진 첫 폰트를 쓰므로, 이 순서면 알파벳과 숫자는 EB Garamond 로,
 * 한글은 나눔명조로 그려진다.
 *
 * 이전 스택은 "Iowan Old Style", "Apple Garamond", Georgia, "Noto Serif KR", serif
 * 였는데, 앞의 셋에 한글이 없고 Noto Serif KR 은 맥에 기본 설치가 아니다.
 * 결국 마지막 serif 를 거쳐 시스템 기본 한글 폰트(고딕)로 떨어져서,
 * 본문 한글 전체가 고딕으로 그려지고 있었다. 콘텐츠의 대부분이 한글인데
 * 세리프를 쓰려던 의도가 닿지 않았다.
 *
 * 다른 명조로 바꾸려면 --serif-ko 와 layout.html 의 Google Fonts 링크만 고치면 된다.
 */
:root {
    --serif-latin: "EB Garamond";
    --serif-ko: "Nanum Myeongjo";
    --serif: var(--serif-latin), var(--serif-ko), Georgia, serif;
    --sans: -apple-system, BlinkMacSystemFont, "Pretendard", "Apple SD Gothic Neo", "Noto Sans KR", sans-serif;

    /* 둥근 모서리는 현대 앱의 언어다. 앤틱 쪽으로 가려면 거의 각져야 한다.
       0 은 너무 날카로워 2px 만 남긴다. */
    --radius: 2px;
}

/*
 * 색
 *
 * 핵심은 색을 더하는 것이 아니라 검정을 빼는 것이다. 본문을 순흑(#1c1a17)에서
 * 갈색 잉크(#2e2419)로 옮기고 배경을 흰색에서 샌드로 옮기면, 브라운 계열을
 * 따로 칠하지 않아도 화면 전체가 따뜻해진다.
 *
 * 모든 조합이 WCAG AA(4.5:1)를 넘는다. 가장 빠듯한 것이 muted 와 accent 로
 * 라이트에서 각각 5.39, 5.66 이다.
 *
 * 두 벌의 색값은 여기 한 번만 적는다. 아래쪽은 그 중 어느 벌을 쓸지
 * 고르기만 한다. 라이트/다크를 각각 따로 적어 두면 한쪽만 고치고
 * 다른 쪽을 잊는 일이 반드시 생긴다.
 */
:root {
    --light-bg: #f7f2e8;          /* 세월 든 종이 */
    --light-surface: #fffdf8;
    --light-text: #2e2419;        /* 검정이 아니라 갈색 잉크 */
    --light-text-muted: #6e6152;
    --light-border: #e0d6c4;
    --light-accent: #875427;
    --light-accent-soft: #efe6d6;
    --light-danger: #9d3b26;

    /* 밤에 램프 아래 놓인 낡은 책 쪽으로. 순검정으로 가면 낮 화면의
       따뜻함이 밤에 사라진다. */
    --dark-bg: #1a1511;
    --dark-surface: #221c16;
    --dark-text: #e8ddc9;
    --dark-text-muted: #a2927c;
    --dark-border: #383025;
    --dark-accent: #d8a866;
    --dark-accent-soft: #2b2419;
    --dark-danger: #e0806e;

    /*
     * 질감.
     *
     * 입자는 라이트에서 multiply 다. 밝은 바탕 위의 어두운 반점.
     *
     * 다크에서는 어두운 점을 곱해 봐야 보이지 않으므로 screen 으로 뒤집어
     * 밝은 반점을 얹는다. soft-light 와 overlay 도 재 봤는데 거의 검은
     * 바탕에서는 둘 다 눌려서, 농도를 세 배로 올려도 진폭이 6/255 까지밖에
     * 안 올라갔다(multiply 0.085 의 라이트가 10/255 다).
     *
     * 대신 screen 은 검정을 들어 올린다. 바탕이 #1a1511 에서 대략 #1d1915
     * 정도로 뜬다. 순검정을 피하자는 원래 방향과 어긋나지 않아 그대로 둔다.
     * 농도를 더 올리면 뿌옇게 들뜨므로 0.05 에서 멈춘다.
     *
     * 비네트는 가장자리를 미세하게 어둡게 해 톤을 고르지 않게 만든다.
     * "종이답다" 는 인상은 입자보다 이쪽이 더 많이 만든다. 다크에서는
     * 램프 아래 책 쪽으로 가라고 조금 더 세게 준다.
     */
    --light-texture-opacity: 0.085;
    --light-texture-blend: multiply;
    --light-vignette: rgba(92, 68, 38, 0.07);

    --dark-texture-opacity: 0.05;
    --dark-texture-blend: screen;
    --dark-vignette: rgba(0, 0, 0, 0.3);
}

/*
 * 어느 벌을 쓸지.
 *
 * 세 가지 경우가 있다.
 *   data-theme 없음        — 운영체제 설정을 따른다(아래 @media)
 *   data-theme="light"     — 사용자가 밝은 쪽을 골랐다
 *   data-theme="dark"      — 사용자가 어두운 쪽을 골랐다
 *
 * data-theme 은 layout.html 의 머리말 스크립트가 그려지기 전에 붙인다.
 * 본문이 뜬 뒤에 붙이면 밝은 화면이 한 번 번쩍이고 어두워진다.
 *
 * color-scheme 은 스크롤바·입력창·select 드롭다운처럼 브라우저가 직접
 * 그리는 부분을 같이 바꾼다. 이게 없으면 본문만 어둡고 스크롤바는 희다.
 */
:root,
:root[data-theme="light"] {
    color-scheme: light;

    --bg: var(--light-bg);
    --surface: var(--light-surface);
    --text: var(--light-text);
    --text-muted: var(--light-text-muted);
    --border: var(--light-border);
    --accent: var(--light-accent);
    --accent-soft: var(--light-accent-soft);
    --danger: var(--light-danger);
    --texture-opacity: var(--light-texture-opacity);
    --texture-blend: var(--light-texture-blend);
    --vignette: var(--light-vignette);
}

/* 스크립트가 막힌 환경을 위한 바탕. 스크립트가 돌면 :root 에 data-theme 이
   붙어 아래 규칙으로 넘어간다. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme]) {
        color-scheme: dark;

        --bg: var(--dark-bg);
        --surface: var(--dark-surface);
        --text: var(--dark-text);
        --text-muted: var(--dark-text-muted);
        --border: var(--dark-border);
        --accent: var(--dark-accent);
        --accent-soft: var(--dark-accent-soft);
        --danger: var(--dark-danger);
        --texture-opacity: var(--dark-texture-opacity);
        --texture-blend: var(--dark-texture-blend);
        --vignette: var(--dark-vignette);
    }
}

:root[data-theme="dark"] {
    color-scheme: dark;

    --bg: var(--dark-bg);
    --surface: var(--dark-surface);
    --text: var(--dark-text);
    --text-muted: var(--dark-text-muted);
    --border: var(--dark-border);
    --accent: var(--dark-accent);
    --accent-soft: var(--dark-accent-soft);
    --danger: var(--dark-danger);
    --texture-opacity: var(--dark-texture-opacity);
    --texture-blend: var(--dark-texture-blend);
    --vignette: var(--dark-vignette);
}

* { box-sizing: border-box; }

/* 바탕색을 body 가 아니라 html 에 둔다.
   질감 두 겹이 body::before / ::after 로 z-index: -1 에 깔리는데, body 에
   배경이 있으면 그 뒤로 숨는다. 색을 html 로 올리면 캔버스에 칠해져
   가장 아래가 되고, 질감은 그 위, 글은 그 위가 된다. */
html { background-color: var(--bg); }

body {
    margin: 0;
    color: var(--text);
    font-family: var(--sans);
    line-height: 1.7;
    -webkit-font-smoothing: antialiased;
}

/*
 * 질감 두 겹.
 *
 * 둘 다 position: fixed 다. 스크롤을 따라 다시 그리지 않으므로 싸고,
 * 결이 글을 따라 움직이지 않는 것은 실제로 거의 눈에 띄지 않는다.
 *
 * pointer-events: none 이 빠지면 화면 전체를 덮은 투명한 판이 생겨
 * 링크도 버튼도 눌리지 않는다. 이 줄은 장식이 아니다.
 *
 * 표면(카드, 상자)마다 따로 깔지 않는 이유는, 작은 상자에서는 타일의
 * 반복 주기가 그대로 드러나고 모서리마다 이음매가 보이기 때문이다.
 * 화면 전체에 한 겹이어야 한다.
 */
body::before,
body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
}

/*
 * 입자.
 *
 * 종이 스캔 이미지를 쓰지 않고 feTurbulence 로 브라우저가 직접 그린다.
 * 파일이 없으니 용량도 없고, 무엇보다 출처를 따질 일이 없다. 악곡은
 * 퍼블릭 도메인만 쓴다면서 배경 이미지 출처가 애매하면 앞뒤가 안 맞는다.
 *
 * stitchTiles="stitch" 가 핵심이다. 이게 없으면 타일 경계에서 결이
 * 끊겨 180px 격자가 눈에 보인다.
 *
 * feColorMatrix saturate=0 도 필요하다. feTurbulence 는 R·G·B 를 각각
 * 따로 흔들어서 그냥 쓰면 컬러 노이즈, 그러니까 TV 모래폭풍이 된다.
 *
 * baseFrequency 가 입자 굵기다. 처음에 0.8/4옥타브로 뒀는데 거의 1픽셀
 * 노이즈라 보는 거리에서 평평해져 버렸다 — 통계로는 분명히 있는데 눈에는
 * 없었다. 0.35/2옥타브가 종이의 결처럼 읽힌다. 더 낮추면(0.14 쯤) 결이
 * 아니라 얼룩으로 보이고, 타일 주기도 눈에 띄기 시작한다.
 */
body::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.35' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 180px 180px;
    opacity: var(--texture-opacity);
    mix-blend-mode: var(--texture-blend);
}

/* 비네트. 가운데는 그대로 두고 가장자리만 미세하게 내린다.
   균일한 색면은 화면처럼 보이고, 톤이 고르지 않으면 물체처럼 보인다. */
body::after {
    background: radial-gradient(ellipse 110% 85% at 50% 42%,
                                transparent 45%, var(--vignette) 100%);
}

/*
 * 질감을 꺼야 하는 경우.
 *
 * 대비를 높여 달라고 설정한 사람에게 바탕에 입자를 까는 것은 정반대다.
 * 투명 효과를 줄여 달라는 설정도 같은 뜻으로 받는다.
 * 인쇄에서는 잉크만 낭비한다.
 */
@media print,
       (prefers-contrast: more),
       (prefers-reduced-transparency: reduce) {
    body::before,
    body::after { display: none; }
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.container {
    max-width: 760px;
    margin: 0 auto;
    padding: 0 16px;
}

/* 1px 실선 한 종류만 쓰면 선에 성격이 없다. 고전 인쇄물은 굵은 선과 얇은 선을
   겹쳐 쓴다. border 하나로는 두 줄을 못 그리므로 가상 요소를 덧댄다. */
.site-header {
    position: relative;
    border-bottom: 2px solid var(--border);
    padding: 20px 0;
    margin-bottom: 44px;
}

.site-header::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -4px;
    height: 1px;
    background: var(--border);
}

.site-header .container {
    display: flex;
    /* 토글 버튼이 들어오기 전에는 baseline 이었다. 글자만 있을 때는 그쪽이
       맞지만, 글자가 없는 30px 버튼이 끼면 기준선이 버튼 아래끝으로 잡혀
       줄이 어긋난다. */
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

/* 크고 굵은 제목이 아니라 책 표지에 새긴 제자(題字) 쪽으로.
   작게 쓰고 자간을 벌리면 무게가 줄면서 격식이 생긴다. */
.site-title {
    font-family: var(--serif);
    font-size: 19px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--text);
}

.site-nav { display: flex; align-items: center; gap: 18px; font-size: 14px; letter-spacing: 0.04em; }
.site-nav a { color: var(--text-muted); }

/* ---------- 라이트/다크 토글 ---------- */

/* 스크립트가 없으면 눌러도 아무 일이 없다. 그래서 기본은 숨기고,
   머리말 스크립트가 .has-js 를 붙였을 때만 보인다. */
.theme-toggle { display: none; }

.has-js .theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    margin-left: 4px;
    border: 1px solid var(--border);
    border-radius: 2px;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
}

.theme-toggle:hover { color: var(--text); border-color: var(--accent); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* 아이콘은 글리프가 아니라 CSS 로 그린다. ☾ ☀ 같은 문자는 EB Garamond 에도
   나눔명조에도 없어서 엉뚱한 서체로 떨어진다(❦ 에서 이미 겪었다).
   상자 크기는 16px 로 고정하고 안에서만 모양을 바꿔, 눌러도 옆의 링크가
   밀리지 않게 한다. */
.theme-icon {
    position: relative;
    display: block;
    width: 16px;
    height: 16px;
}

.theme-icon::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border-radius: 50%;
}

/* 지금 밝다 → 누르면 어두워진다. 초승달.
   투명한 원에 inset 그림자를 주면 border-radius 에 잘려 초승달이 된다. */
.theme-toggle[data-mode="light"] .theme-icon::before {
    width: 14px;
    height: 14px;
    box-shadow: inset -4px -1.5px 0 0 currentColor;
}

/* 지금 어둡다 → 누르면 밝아진다. 해.
   가운데 원 하나에 box-shadow 로 빛살 여덟을 찍는다. */
.theme-toggle[data-mode="dark"] .theme-icon::before {
    width: 8px;
    height: 8px;
    background: currentColor;
    box-shadow:
        0 -8px 0 -2.5px currentColor,
        0 8px 0 -2.5px currentColor,
        -8px 0 0 -2.5px currentColor,
        8px 0 0 -2.5px currentColor,
        5.5px 5.5px 0 -3px currentColor,
        -5.5px -5.5px 0 -3px currentColor,
        5.5px -5.5px 0 -3px currentColor,
        -5.5px 5.5px 0 -3px currentColor;
}

.site-footer {
    margin-top: 72px;
    padding: 28px 0;
    border-top: 1px solid var(--border);
    color: var(--text-muted);
    font-size: 13px;
}

/* 이름만으로는 무엇을 하는 곳인지 알 수 없으므로 한 줄 설명이 필요하다.
   Cadenza 는 음악 용어라 바로 통했지만 Moirai 는 설명이 붙어야 한다. */
.footer-tagline {
    font-family: var(--serif);
    font-size: 14px;
    max-width: 46em;
}

h1, h2, h3 {
    font-family: var(--serif);
    line-height: 1.35;
    /* 한글 명조 제목은 기본 자간이 성글다. 살짝 조이면 덩어리로 읽힌다. */
    letter-spacing: -0.015em;
    font-weight: 700;
}

.work-list { list-style: none; padding: 0; margin: 0; }

/* 왼쪽에 글, 오른쪽에 들어보기. 좁은 화면에서는 위아래로 쌓인다. */
.work-card {
    display: flex;
    gap: 22px;
    align-items: flex-start;
    padding: 22px 0;
    border-bottom: 1px solid var(--border);
}

.work-card-body {
    flex: 1;
    min-width: 0;          /* 긴 제목이 레이아웃을 밀어내지 않게 */
}

.work-card h2 { margin: 0 0 6px; font-size: 21px; }
.work-card .meta { color: var(--text-muted); font-size: 14px; margin: 0 0 8px; }
.work-card .summary { margin: 0; color: var(--text-muted); }

.work-card .card-performer {
    margin: 10px 0 0;
    font-size: 13px;
    color: var(--text-muted);
}

.work-card-player {
    flex: 0 0 260px;
    max-width: 260px;
}

@media (max-width: 640px) {
    .work-card { flex-direction: column; gap: 14px; }
    .work-card-player { flex: 1 1 auto; max-width: 100%; width: 100%; }
}

/* 클릭 전 상태 - 썸네일과 재생 버튼.
   목록에 iframe 을 다 띄우면 페이지가 못 쓰게 되므로 클릭할 때 플레이어를 붙인다. */
.yt-facade {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 2px;
    overflow: hidden;
    background: #000;
    cursor: pointer;
}

.yt-facade img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    opacity: 0.92;
    transition: opacity 0.15s ease, transform 0.25s ease;
}

.yt-facade:hover img { opacity: 1; transform: scale(1.03); }

.yt-facade-play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 46px;
    height: 46px;
    border-radius: 50%;
    background: rgba(20, 18, 15, 0.62);
    border: 1px solid rgba(255, 255, 255, 0.5);
    transition: background 0.15s ease;
}

.yt-facade-play::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 52%;
    transform: translate(-50%, -50%);
    border-style: solid;
    border-width: 8px 0 8px 13px;
    border-color: transparent transparent transparent #fff;
}

.yt-facade:hover .yt-facade-play { background: rgba(20, 18, 15, 0.82); }

.yt-facade:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.yt-facade-error {
    display: none;
    margin: 8px 0 0;
    font-size: 13px;
    color: var(--danger);
}

/* 음원이 없는 칸의 자리채움. 목록형에서는 숨기고 격자형에서만 쓴다.
   격자에서 썸네일 없는 칸을 비우면 높이가 어긋나 깨져 보인다. */
.work-card-player.is-empty { display: none; }

.yt-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 1px dashed var(--border);
    border-radius: 2px;
    background: var(--accent-soft);
    font-family: var(--serif);
    font-size: 15px;
    color: var(--text-muted);
    text-align: center;
    padding: 0 12px;
}

/* ---------- 보기 방식 전환 ---------- */

/*
 * 간격.
 *
 * 전환 버튼은 글이 아니라 목록을 조작하는 손잡이다. 그런데 헤더에서 44px
 * 떨어져 있고 목록과는 4px 라, 목록의 머리가 아니라 허공에 뜬 것처럼
 * 보였다. 위를 줄이고 아래를 늘려 목록 쪽이 아니라 머리띠 쪽에 붙인다.
 *
 * 헤더 간격은 이 화면에서만 줄인다. 곡 상세나 이어 듣기처럼 글이 먼저
 * 오는 화면은 44px 가 맞다.
 */
.toolbar-top .site-header { margin-bottom: 22px; }

.view-toggle {
    display: flex;
    gap: 2px;
    justify-content: flex-end;
    /* 첫 카드가 위쪽에 22px 패딩을 가지고 있어, 눈에 보이는 간격은
       여기 값 + 22px 이다. */
    margin-bottom: 16px;
}

/* 작곡가 상세: 제목과 전환 버튼을 같은 줄에 둔다 */
.section-head {
    display: flex;
    /* 아이콘 버튼에는 글자가 없어 기준선이 버튼 아래끝으로 잡힌다.
       baseline 으로 두면 h2 와 줄이 어긋난다. */
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 20px;
}

/* 간격은 .section-head 가 한 번에 맡는다. 안쪽 요소가 따로 아래 여백을
   가지면 둘이 더해져 어느 쪽을 고쳐야 하는지 알 수 없게 된다. */
.section-head h2 { margin-bottom: 0; }
.section-head .view-toggle { margin-bottom: 0; }

/* 글자를 아이콘으로 바꿨으므로 상자 크기를 직접 준다.
   padding 으로 잡으면 아이콘 크기를 바꿀 때마다 같이 손봐야 한다. */
.view-toggle button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 28px;
    padding: 0;
    color: var(--text-muted);
    background: transparent;
    border: 1px solid var(--border);
    cursor: pointer;
}

.view-icon {
    display: block;
    width: 15px;
    height: 15px;
    fill: currentColor;   /* 눌린 상태의 강조색을 아이콘도 따라간다 */
}

.view-toggle button:first-child { border-radius: 2px 0 0 2px; }
.view-toggle button:last-child { border-radius: 0 2px 2px 0; margin-left: -1px; }
.view-toggle button:hover { color: var(--text); }
.view-toggle button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.view-toggle button[aria-pressed="true"] {
    color: var(--accent);
    background: var(--accent-soft);
    border-color: var(--accent);
    position: relative;   /* 겹친 테두리 위로 */
}

/* ---------- 격자형 ----------
   마크업은 목록형과 같다. 썸네일을 위로 올리는 것은 order 로 한다.
   (문서 순서는 body -> player 이므로 격자에서만 뒤집는다) */

/* 격자일 때만 컨테이너를 넓힌다. 760px 는 글을 읽기에 맞는 폭이지만
   격자에서는 2열밖에 나오지 않는다. 글 읽는 화면은 그대로 760px 로 둔다.
   한 줄에 3칸이 목표이므로 1120px 까지 벌릴 필요가 없다. */
.container[data-view="grid"] { max-width: 1000px; }

/* 한 줄 최대 3칸. auto-fill 로 두면 폭이 넓어질수록 칸이 계속 늘어나
   4칸, 5칸이 되면서 칸이 좁아진다. 열 수를 고정해 칸 크기를 지킨다. */
.work-list[data-view="grid"] {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 28px 22px;
}

@media (max-width: 860px) {
    .work-list[data-view="grid"] { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 560px) {
    .work-list[data-view="grid"] { grid-template-columns: 1fr; }
}

.work-list[data-view="grid"] .work-card {
    flex-direction: column;
    gap: 12px;
    padding: 0;
    border-bottom: 0;
}

.work-list[data-view="grid"] .work-card-player {
    order: 1;
    flex: 0 0 auto;
    max-width: 100%;
    width: 100%;
}

.work-list[data-view="grid"] .work-card-player.is-empty { display: block; }

.work-list[data-view="grid"] .work-card-body { order: 2; }

.work-list[data-view="grid"] .work-card h2 {
    font-size: 17px;
    margin-bottom: 4px;

    /* 긴 제목이 칸을 밀어 올려 같은 행의 높이가 들쭉날쭉해지는 것을 막는다. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.work-list[data-view="grid"] .work-card .meta {
    font-size: 13px;
    margin-bottom: 6px;
}

.work-list[data-view="grid"] .work-card .summary {
    font-size: 14px;
    line-height: 1.6;

    /* 칸 높이를 고르게. 세 줄까지 보이고 넘치면 말줄임. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.work-list[data-view="grid"] .work-card .card-performer {
    margin-top: 6px;
    font-size: 12px;
}

/* 격자에서는 한 칸이 좁으므로 단일 열로 떨어지는 지점을 따로 두지 않는다.
   auto-fill 이 알아서 1열까지 줄어든다. */

/* ---------- 곡 상세 하단: 이 작곡가의 다른 곡 ---------- */

/* 섹션 구분. 선 하나보다 장식 하나가 고전 인쇄물에 가깝다.
   사이트 전체에서 여기 한 군데만 쓴다. 여러 군데 쓰면 바로 촌스러워진다.

   ❦ 같은 장식 문자를 쓰려다 물렸다. EB Garamond 와 나눔명조 모두 그 글리프가
   없어서 엉뚱한 폰트로 떨어지며 작고 깨진 모양으로 나왔다. 폰트에 기대지 않도록
   점 세 개를 CSS 로 직접 그린다. */
.related {
    margin-top: 64px;
    padding-top: 8px;
}

.related::before {
    content: "";
    display: block;
    width: 46px;
    height: 4px;
    margin: 0 0 30px;
    background: radial-gradient(circle, var(--accent) 2px, transparent 2.2px) 0 50% / 17px 4px repeat-x;
    opacity: 0.5;
}

.related h2 {
    font-size: 19px;
    margin: 0 0 18px;
}

/* 최대 3개뿐이라 auto-fill 대신 열 수를 고정한다.
   auto-fill 이면 2개일 때 칸이 어정쩡하게 늘어난다. */
.related-list[data-view="grid"] {
    grid-template-columns: repeat(3, 1fr);
    gap: 20px 18px;
}

.related-list .work-card h3 {
    font-family: var(--serif);
    font-size: 16px;
    line-height: 1.35;
    margin: 0 0 4px;

    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.related-list .work-card .meta { font-size: 12.5px; margin-bottom: 5px; }

.related-list .work-card .summary {
    font-size: 13px;
    -webkit-line-clamp: 2;     /* 하단 블록이라 본문보다 짧게 */
}

.related-more {
    margin: 20px 0 0;
    font-size: 14px;
}

/* ---------- 이어 듣기 ---------- */

.listen-page { max-width: 1120px; }

.listen-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 32px;
    align-items: start;
}

/* 플레이어를 화면에 붙여 둔다. 목록을 훑어 내려가도 영상이 보이는 자리에 남는다.
   숨기는 것이 아니라 따라다니는 것이다. 약관이 금지하는 것은 플레이어를 가리거나
   오디오만 분리하는 것이다. */
.listen-main {
    position: sticky;
    top: 24px;
}

.listen-main .player-frame {
    aspect-ratio: 16 / 9;
    border-radius: 2px;
}

.listen-notice {
    display: none;
    margin: 12px 0 0;
    padding: 10px 12px;
    background: var(--accent-soft);
    border-radius: 2px;
    font-size: 13px;
    color: var(--danger);
}

.listen-controls {
    display: flex;
    gap: 8px;
    margin-top: 14px;
}

.listen-controls button:disabled { opacity: 0.4; cursor: default; }

.now-playing { margin-top: 22px; }

.now-playing h1 {
    font-size: 25px;
    margin: 0 0 6px;
}

.now-playing .meta {
    color: var(--text-muted);
    font-size: 14px;
    margin: 0 0 10px;
}

.now-performer {
    margin: 0 0 12px;
    font-size: 13px;
    color: var(--text-muted);
}

.now-summary {
    font-family: var(--serif);
    font-size: 17px;
    line-height: 1.75;
    margin: 0 0 14px;
}

.now-link { margin: 0; font-size: 14px; }

/* 재생 목록 */

.listen-side h2 {
    font-size: 15px;
    margin: 0 0 12px;
    color: var(--text-muted);
    font-family: var(--sans);
    font-weight: 600;
}

.listen-count { font-weight: 400; }

.listen-list {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 70vh;
    overflow-y: auto;
    border-top: 1px solid var(--border);
}

.listen-list li {
    display: flex;
    gap: 12px;
    align-items: baseline;
    padding: 10px 10px 10px 8px;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
}

.listen-list li:hover { background: var(--accent-soft); }

.listen-list li.is-current {
    background: var(--accent-soft);
    box-shadow: inset 3px 0 0 var(--accent);
}

.listen-list li.is-current .listen-title { color: var(--accent); font-weight: 600; }

.listen-year {
    flex: 0 0 auto;
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.listen-track { display: flex; flex-direction: column; min-width: 0; }

.listen-title {
    font-size: 14px;
    line-height: 1.4;
}

.listen-composer {
    font-size: 12px;
    color: var(--text-muted);
    margin-top: 2px;
}

@media (max-width: 860px) {
    .listen-layout { grid-template-columns: 1fr; gap: 28px; }
    .listen-main { position: static; }
    .listen-list { max-height: none; }
}

/* 메인 격자와 같은 지점에서 접힌다. 이 블록은 위의 .work-list 규칙보다
   뒤에 있어 같은 특이도에서 이기므로 자기 breakpoint 를 따로 가져야 한다. */
@media (max-width: 860px) {
    .related-list[data-view="grid"] { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 560px) {
    .related-list[data-view="grid"] { grid-template-columns: 1fr; }
}

.work-header { margin-bottom: 28px; }
.work-header h1 { margin: 0 0 10px; font-size: 33px; }
.work-header .meta { color: var(--text-muted); font-size: 15px; margin: 0; }

/* 흰 상자 + 보더 + 패딩은 영상을 "위젯"으로 보이게 하고 글의 흐름을 끊는다.
   상자를 걷고 영상만 놓은 뒤, 출처는 아래에 작은 글씨로 단다. */
.player-shell {
    margin-bottom: 40px;
}

.player-frame {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: #000;
    border-radius: 2px;
    overflow: hidden;
}

.player-frame iframe { width: 100%; height: 100%; border: 0; }
.player-shell.audio-only .player-frame { aspect-ratio: auto; background: transparent; }

.player-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 14px;
    margin-top: 12px;
    font-size: 13px;
    color: var(--text-muted);
}

.player-error {
    display: none;
    margin-top: 12px;
    padding: 12px 14px;
    background: var(--accent-soft);
    border-radius: 2px;
    color: var(--danger);
    font-size: 14px;
}

/* 한 줄 길이.
   컨테이너 폭(760px)을 그대로 쓰면 18px 본문이 한 줄에 40자를 넘는다. 한글은
   35자 안팎에서 눈이 다음 줄을 쉽게 찾는다. 36em = 648px 로 재어 보니 한 줄
   약 36자가 들어간다.
   max-width 를 em 으로 주면 글자 크기를 바꿔도 줄당 글자 수가 유지된다.
   제목과 플레이어는 컨테이너 폭 그대로 두어, 글 단보다 넓은 도판이 되게 한다. */
.story {
    font-family: var(--serif);
    font-size: 18px;
    line-height: 1.85;
    max-width: 36em;
    /* 36em 단을 컨테이너 왼쪽에 붙여 두니 오른쪽만 비어 한쪽으로 쏠려 보였다.
       좌우를 auto 로 두면 남는 폭이 양쪽에 반씩 간다. 제목과 플레이어는
       컨테이너 폭 그대로라 본문보다 조금씩 넓게 걸친다. */
    margin-left: auto;
    margin-right: auto;
}

.story p { margin: 0 0 1.2em; }
/* 왼쪽 막대는 블로그의 관습이고, 책에서는 들여쓰기와 크기로 구분한다.
   양쪽을 들이고 조금 작게 쓰면 본문 흐름에서 한 걸음 물러난 것처럼 읽힌다. */
.story blockquote {
    margin: 1.8em 0;
    padding: 0 2.2em;
    font-size: 0.94em;
    line-height: 1.8;
    color: var(--text-muted);
}

.story blockquote p:last-child { margin-bottom: 0; }

/* 제목과 본문 사이의 짧은 장식 괘선. 가운데가 아니라 왼쪽에 둔다.
   가운데 정렬은 청첩장 쪽으로 기울고, 왼쪽은 책의 장 머리에 가깝다. */
.work-header::after {
    content: "";
    display: block;
    width: 54px;
    height: 2px;
    margin-top: 18px;
    background: var(--accent);
    opacity: 0.55;
}

/* ---------- 오류 화면 ---------- */

/* 숫자를 크게 띄우지 않는다. 404 를 거대하게 박는 건 현대 웹의 관습이고,
   이 사이트의 언어는 책에 가깝다. 작게 쓰고 자간을 벌려 머리말처럼 둔다. */
.error-page {
    max-width: 36em;
    margin: 72px auto 96px;
}

.error-code {
    margin: 0 0 14px;
    font-family: var(--serif);
    font-size: 14px;
    letter-spacing: 0.22em;
    color: var(--text-muted);
}

.error-page h1 {
    margin: 0 0 16px;
    font-size: 28px;
}

.error-lead {
    margin: 0 0 32px;
    color: var(--text-muted);
    font-size: 16px;
    line-height: 1.8;
}

.error-actions { display: flex; gap: 10px; flex-wrap: wrap; margin: 0; }

.empty {
    padding: 48px 0;
    text-align: center;
    color: var(--text-muted);
}

/* ---------- admin ---------- */

.admin-body { --serif: var(--sans); }
.admin-body .container { max-width: 900px; }

.admin-nav {
    display: flex;
    /* 글자 링크와 글자 없는 30px 버튼이 한 줄에 섞인다.
       baseline 으로 두면 버튼의 기준선이 아래끝으로 잡혀 줄이 어긋난다. */
    align-items: center;
    gap: 16px;
    font-size: 14px;
    margin-bottom: 28px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
}

/* 오른쪽 끝에 붙는 묶음. margin-left: auto 를 로그아웃 폼에 직접 주면
   토글이 그 왼쪽이 아니라 링크들 쪽에 붙는다. */
.admin-nav-end {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-left: auto;
}

/* 초안 미리보기 띠.
   경고가 아니라 상태 표시다. danger 색은 "뭔가 잘못됐다" 로 읽히므로
   강조색 계열로 두되, 왼쪽에 굵은 막대를 둬서 본문과 확실히 구분한다. */
.draft-banner {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 28px;
    padding: 12px 16px;
    background: var(--accent-soft);
    border-left: 4px solid var(--accent);
    font-size: 14px;
    color: var(--text-muted);
}

.draft-banner strong {
    color: var(--accent);
    letter-spacing: 0.04em;
}

.draft-banner a { margin-left: auto; white-space: nowrap; }

.flash {
    padding: 12px 14px;
    background: var(--accent-soft);
    border-radius: 2px;
    margin-bottom: 20px;
    font-size: 14px;
}

/* ---------- 관리 대시보드 ---------- */

.admin-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.admin-head h1 { font-size: 24px; margin: 0; }
.admin-count { color: var(--text-muted); font-size: 15px; font-weight: 400; }
.admin-sub { color: var(--text-muted); font-size: 14px; margin: 6px 0 0; }
.row-sub { color: var(--text-muted); font-size: 12px; }

/* 거르기 줄. 표 바로 위에 붙여 둘이 한 덩어리로 읽히게 한다. */
.work-filter {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin: 24px 0 14px;
}

.work-filter input[type=search] {
    width: auto;
    min-width: 240px;
    flex: 0 1 300px;
    padding: 7px 10px;
    font-size: 13px;
}

.filter-chips { display: flex; gap: 6px; flex-wrap: wrap; }

.filter-chips button {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    padding: 6px 11px;
    font: inherit;
    font-size: 13px;
    color: var(--text-muted);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 2px;
    cursor: pointer;
}

.filter-chips button span {
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    opacity: 0.75;
}

.filter-chips button:hover:not(:disabled) { color: var(--text); }

.filter-chips button[aria-pressed="true"] {
    color: var(--accent);
    background: var(--accent-soft);
    border-color: var(--accent);
}

/* 해당하는 곡이 없는 칩. 눌러 봐야 빈 표가 나오므로 비활성으로 둔다. */
.filter-chips button:disabled { opacity: 0.4; cursor: default; }

.filter-result {
    margin: 0;
    font-size: 13px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/*
 * "할 일" 칸. 빠진 것만 적힌다.
 *
 * 공개/초안 뱃지와 생김새를 갈라 놓는다. 뱃지는 테두리가 있는 라벨이고
 * 이쪽은 테두리 없는 글씨다. 한 행에 뱃지가 넷씩 늘어서면 표가 읽히지 않는다.
 */
.gap {
    display: inline-block;
    margin-right: 8px;
    font-size: 12px;
    color: var(--danger);
    white-space: nowrap;
}

/* 되돌릴 수 없는 조작. 저장 영역에서 떼어 놓고 선으로 끊어, 저장하려다
   잘못 누르는 거리를 벌린다. */
.danger-zone {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 36px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}

.danger-zone .hint { margin: 0; }

.field { margin-bottom: 16px; }
.field label { display: block; font-size: 13px; font-weight: 600; margin-bottom: 5px; }
.field .hint { font-size: 12px; color: var(--text-muted); margin-top: 4px; }

input[type=text], input[type=number], input[type=password], select, textarea {
    width: 100%;
    padding: 9px 11px;
    font: inherit;
    font-size: 14px;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 2px;
}

textarea { min-height: 220px; resize: vertical; font-family: var(--sans); }

.btn {
    display: inline-block;
    padding: 9px 16px;
    font: inherit;
    font-size: 14px;
    border: 1px solid var(--accent);
    background: var(--accent);
    color: #fff;
    border-radius: 2px;
    cursor: pointer;
}

.btn.secondary { background: transparent; color: var(--accent); }
.btn.small { padding: 5px 10px; font-size: 13px; }
.btn.danger { border-color: var(--danger); background: transparent; color: var(--danger); }

.row { display: flex; gap: 12px; flex-wrap: wrap; }
.row > * { flex: 1; min-width: 160px; }

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 10px 8px; border-bottom: 1px solid var(--border); vertical-align: top; }
th { font-size: 12px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }

/* 알약 모양 칩은 현대 앱의 표식이다. 네모지게 하고 테두리를 주면
   인쇄물의 각주 표나 도서관 라벨 쪽으로 읽힌다. 곡/작곡가 페이지에도
   "퍼블릭 도메인" 으로 나오므로 관리 화면만의 문제가 아니다. */
.badge {
    display: inline-block;
    padding: 2px 7px;
    font-size: 12px;
    letter-spacing: 0.02em;
    border: 1px solid var(--border);
    border-radius: 2px;
    background: var(--accent-soft);
    color: var(--text-muted);
}

.badge.on { color: var(--accent); font-weight: 600; }
.badge.off { color: var(--danger); }

.error { color: var(--danger); font-size: 13px; margin-top: 4px; }

/* 유튜브 영상 ID 처럼 그대로 복사해 가는 값 */
code.copyable {
    display: inline-block;
    padding: 2px 7px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    background: var(--accent-soft);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text);
    user-select: all;      /* 한 번 클릭으로 전체 선택 */
}


.section {
    margin-top: 44px;
    padding-top: 26px;
    border-top: 1px solid var(--border);
}

/* 곡 상세 하단은 .related::before 의 점 장식이 구분을 맡으므로 선을 지운다. */
.section.related { border-top: 0; }

.preview-box {
    margin-top: 12px;
    padding: 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.preview-box .warn {
    font-size: 13px;
    color: var(--danger);
    margin: 10px 0 0;
}
