/* BookTimer — 공통 스타일 (에디토리얼: 미색 종이 · 잉크 하나 · 명조 + 고딕 · 선과 여백 — 미니앱과 같은 옷) */

/* 글꼴 — 에디토리얼(2026-10, 미니앱과 같은 URL·같은 세 face): 제목·값·이니셜·시계 = 명조 Noto Serif KR 500,
   본문 = 고딕 Noto Sans KR 400·500. 기능 글자(고딕)가 기본값이고 명조는 `var(--font-serif)`로 '명시'한 자리만이다
   (상속에 기대는 자리를 두지 않는다 — 방향이 뒤집히면 지정 안 한 다음 화면이 명조로 태어난다).
   굵기는 400·500뿐이라 body에 `font-synthesis: style`(굵기 합성 끔) — 남는 700 요청도 가짜 볼드 없이 500 face로 선다.
   URL은 miniapp/src/fonts.ts의 FONT_CSS_URL과 같은 문자열이어야 한다(editorialTheme.test.ts가 대조한다).
   손글씨 '개구'(Gaegu)는 2026-09-03에 걷었고 폴백으로도 남기지 않는다 — 근거는 miniapp/src/global.css의 `html body` 주석.
   싣는 법은 이 `@import` 그대로다 — 웹은 화면마다 새 문서라 load 뒤 주입(미니앱 방식)은 매 이동마다 글자를 바꿔 그린다. */
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@500&family=Noto+Sans+KR:wght@400;500&display=swap');

/* 둘째 항목 = 독서등 밑 합쳐진 카드(낮 종이) — 밤이 된 body 안에서 라이트 토큰을 되돌린다(아래 다크 절 끝 「독서등」). */
:root, body.study-lamp .lamp-page {
    /* 브라우저 강제 다크(크롬 Auto Dark Theme) 거부. `only`가 핵심이다 — `light`만 쓰면 그건
       「라이트만 그린다」는 사실 진술이라, UA가 보기엔 여전히 「다크를 지원하지 않는 페이지」다.
       사용자가 다크를 켜면 아래 블록이 color-scheme: dark로 덮어 이 opt-out을 스스로 푼다. */
    color-scheme: only light;

    /* ── 에디토리얼 팔레트(2026-10 PR-2 — 미니앱 에디토리얼과 같은 값, 설계 §5-2) ─────────────
       토큰 **이름은 그대로, 값만** 역할 군으로 모았다(옛 세이지·파스텔 → 종이·옅은 면·가는 선·잉크·글자 3단·빨강).
       규칙 1,100여 개를 안 건드리고 색이 따라오게 하려는 것이라, 같은 값이 된 변종(`--warn-bg-2/3/4` 등)도 합치지 않는다.
       강조는 **잉크 하나**다 — 성공·주의·정보색은 잉크 + 옅은 면으로 모이고(D8=①) 뜻은 문구가 진다. 빨강(오류·삭제)만 남는다.
       종이·잉크·글자·선·잔디·빨강은 미니앱 global.css와 같아야 한다 — editorialTheme.test.ts가 그 파일을 읽어 대조한다.
       군 표(이름 → 값)는 darkTokens.test.ts가 상수로 박아 둔다 — 여기에 토큰을 더하면 그 표와 아래 다크 블록에도 짝을 넣는다. */

    /* S 면 — 종이. 카드 면 = 바탕이라 낮엔 면이 안 보인다(독서등에서만 종이 한 장이 된다). */
    --bg: #F5F0E6;
    --card-bg: #F5F0E6;
    --surface: #F5F0E6;
    --paper-1: #F5F0E6;
    --paper-1-2: #F5F0E6;
    --paper-1-3: #F5F0E6;
    --paper-4: #F5F0E6;
    --paper-4-2: #F5F0E6;

    /* F 옅은 면 — 태그·알림·읽고 싶어요 배지·고른 행. 흐린 글자 5.13 · 보조 글자 7.58. */
    --sage-soft: #ECE5D8;
    --sage-soft-2: #ECE5D8;
    --paper-2: #ECE5D8;
    --paper-3: #ECE5D8;
    --paper-2-2: #ECE5D8;
    --paper-2-3: #ECE5D8;
    --info-soft: #ECE5D8;
    --info-soft-2: #ECE5D8;
    --info-soft-3: #ECE5D8;
    --info-soft-4: #ECE5D8;
    --ok-soft: #ECE5D8;
    --ok-soft-2: #ECE5D8;
    --ok-soft-3: #ECE5D8;
    --ok-soft-4: #ECE5D8;
    --ok-soft-5: #ECE5D8;
    --warn-bg: #ECE5D8;
    --warn-bg-2: #ECE5D8;
    --warn-bg-3: #ECE5D8;
    --warn-bg-4: #ECE5D8;

    /* H 호버 면 — 잉크 6%(미니앱 --accentPill). 별칭 --nav-hover-bg는 세로 바·하단 .link-row가 공유하는 단일 출처. */
    --sage-hover: rgba(29, 27, 24, .06);
    --sage-hover-2: rgba(29, 27, 24, .06);
    --nav-hover-bg: var(--sage-hover);

    /* L 가는 선 — 장식·구분 전용. 종이 대비 1.33이라 입력칸 경계로는 못 쓴다(입력칸은 --muted). */
    --border: #D9D1C3;
    --border-2: #D9D1C3;
    --border-3: #D9D1C3;
    --border-4: #D9D1C3;
    --line-1: #D9D1C3;
    --line-1-2: #D9D1C3;
    --line-1-3: #D9D1C3;
    --line-1-4: #D9D1C3;
    --line-1-5: #D9D1C3;
    --line-1-6: #D9D1C3;
    --line-1-7: #D9D1C3;
    --line-2: #D9D1C3;
    --line-2-2: #D9D1C3;
    --sage-line: #D9D1C3;
    --sage-line-2: #D9D1C3;
    --ok-line: #D9D1C3;
    --ok-line-2: #D9D1C3;
    --ok-line-3: #D9D1C3;
    --warn-border: #D9D1C3;
    --warn-border-2: #D9D1C3;
    --warn-border-3: #D9D1C3;
    --warn-border-4: #D9D1C3;
    --nav-hover-border: #D9D1C3;
    --nav-hover-border-2: #D9D1C3;

    /* I 잉크 — 본문 글자이자 유일한 강조(종이 위 15.13). 「채움 전용」 이름(--accent-fill·--ok-fill·--accent-hover-2)은
       공부 카드(.is-study)가 강조 자리만 파란 잉크로 갈아 끼울 때 함께 따라간다. */
    --text: #1D1B18;
    --accent: #1D1B18;
    --accent-hover: #1D1B18;
    --accent-fill: #1D1B18;
    --accent-hover-2: #1D1B18;
    --ok: #1D1B18;
    --ok-fill: #1D1B18;
    --ok-ink: #1D1B18;
    --ok-ink-2: #1D1B18;
    --info-ink: #1D1B18;
    --warn-fg: #1D1B18;
    --warn-fg-2: #1D1B18;
    --warn-fg-3: #1D1B18;
    --warn-fg-4: #1D1B18;
    --warn-fg-5: #1D1B18;

    /* T 보조 글자(8.36) · M 흐린 글자(5.65 — 입력칸 경계·자리글자도 이 값) */
    --ink-2: #4A453E;
    --muted: #645E54;
    --muted-2: #645E54;
    --muted-3: #645E54;
    --neutral-3-2: #645E54;
    --neutral-3-3: #645E54;

    /* N 비글자 단계 — 막대·점·테(미니앱 --adaptiveBlue200~400). 직접 채운 잔디 칸 테 = --neutral-2. */
    --neutral-1: #B9AF9F;
    --sage-1: #B9AF9F;
    --sage-2: #B9AF9F;
    --sage-3: #B9AF9F;
    --sage-4: #B9AF9F;
    --neutral-2: #9C9182;
    --sage-5: #9C9182;
    --sage-6: #9C9182;
    --neutral-3: #6F675B;
    --sage-7: #6F675B;
    --sage-8: #6F675B;
    --graphite: #6F675B;

    /* O 잉크 채움(검정 알약·다 읽음 배지) 위 글자 — 미색(15.13) */
    --on-accent: #F5F0E6;

    /* R 빨강 — 오류·삭제만. 낮 #A8322A(종이 5.86)는 미니앱 --adaptiveRed500과 같은 값. 진한 단·옅은 면·선은 웹 전용. */
    --danger: #A8322A;
    --danger-ink: #A8322A;
    --danger-ink-2: #A8322A;
    --danger-hover: #8C2A23;
    --danger-ink-deep: #8C2A23;
    --danger-ink-deep-2: #8C2A23;
    --danger-ink-deep-3: #8C2A23;
    --danger-ink-deep-4: #8C2A23;
    --danger-soft: #F6E7E4;
    --danger-soft-2: #F6E7E4;
    --danger-soft-3: #F6E7E4;
    --danger-soft-4: #F6E7E4;
    --danger-soft-5: #F6E7E4;
    --danger-line: #E4C6C2;
    --danger-line-2: #E4C6C2;
    --danger-line-3: #E4C6C2;
    --danger-line-4: #E4C6C2;

    /* G 잔디 — 잉크 농담 5단(미달 → 달성으로 진해진다). 소비자는 /history·/study/history의 .grass-cell.level-*. */
    --grass-0: #E6DFD2;
    --grass-1: #CDC3B2;
    --grass-2: #A29785;
    --grass-3: #625A4F;
    --grass-4: #1D1B18;

    /* X 포커스 링(잉크 50% — 종이 위 합성 3.20) · 시트·모달 뒤 딤(잉크 45% — 미니앱 시트 딤) */
    --focus-ring: rgba(29, 27, 24, .5);
    --scrim: rgba(29, 27, 24, .45);
    --scrim-soft: rgba(29, 27, 24, .45);
    --scrim-2: rgba(29, 27, 24, .45);
    --scrim-3: rgba(29, 27, 24, .45);

    /* 비색 — 모서리는 0 · 2px · 999px · 50%뿐이다(그릇 0 · 표지·배지·셀 2 · 버튼·칩 999). 토큰 둘은 2px로 모았다. */
    --radius: 2px;
    --radius-sm: 2px;
    /* 명조 — 제목·값·이니셜·시계. 미니앱 global.css와 같은 줄. 리터럴로 직접 적지 않는다(editorialTheme.test.ts). */
    --font-serif: 'Noto Serif KR', 'Noto Serif CJK KR', serif;
    /* 질감·그림자 토큰(--shadow·--pencil-frame·--pencil-frame-soft·--grain·--fiber)은 PR-2에서 지웠다 — 이펙트 0. */
}

* { box-sizing: border-box; }

/* [hidden] 전역 리셋 (normalize류) — author의 display:flex/grid가 CSS cascade origin 우선순위
   (author > UA, !important 제외)로 UA의 [hidden]{display:none}을 이겨, JS가 el.hidden=true로 감춘
   요소가 화면에 그대로 남는 트랩(T-035·T-123, #189→T-035→/settings로 3회 재발)을 앱 전역에서 제거.
   ⚠️ 이 리셋은 [hidden] "속성" 변형만 커버한다 — 닫힌 <details>의 자식 숨김은 UA의
   details:not([open]) 메커니즘이라 여기 안 걸리며, 그 케이스는 개별 :not([open]) 재숨김이 필요하다. */
[hidden] { display: none !important; }

/* 본문 배율 — 사용자 확정(2026-09-03). 손글씨 보정으로 들어왔던 값이지만, 고운돋움으로
   갈아탄 뒤 실측해 보고도 18px 본문을 그대로 택했다. 서체 교체와 독립된 결정이다.
   ⚠️ 이 값은 서체와 따로 다룬다 — 내리면 rem으로 잡힌 크기들이 전부 함께 줄어든다
   (body에만 주면 반대로 rem 크기들이 안 따라온다. 그래서 여기 html에 있다). */
html { font-size: 112.5%; }

body {
    margin: 0;
    min-height: 100vh;
    position: relative;
    background: var(--bg);
    color: var(--text);
    font-family: "Noto Sans KR", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Apple SD Gothic Neo", "Noto Sans CJK KR", "Malgun Gothic", sans-serif;
    /* 400을 '명시'한다 — 미지정으로 두면 결과가 UA에 맡겨진다. 강조는 500 하나다(실린 face = 400·500). */
    font-weight: 400;
    /* 가짜 볼드 0 — 실리지 않은 굵기(h1 기본 700 · strong의 bolder)를 합성하지 않고 500 face로 그린다(상속된다).
       기울임 합성(style)은 남긴다 — Noto KR엔 italic face가 없어 끄면 편집기 `<em>`(Ctrl+I)·명언 기울임이 똑바로 선다. */
    font-synthesis: style;
    line-height: 1.6;
    display: flex;
    justify-content: center;
    padding: 32px 16px;
}

/* 폼 요소엔 body 서체가 상속으로 오지 않는다 — UA 기본 스타일이 input/textarea/select에
   자기 폰트(Arial 13.3px)를 직접 지정하고, author 규칙이 없으면 그 값이 이기기 때문이다.
   그래서 이 한 줄이 없으면 하필 「사용자가 직접 글자를 치는 칸」만 딴 서체로 남는다.
   미니앱엔 이 구멍이 없었다 — TDS가 같은 규칙을 주고 있다(miniapp/src/global.css 상단 주석).
   ⚠️ 타입 선택자(0-0-1)로 둔 것은 일부러다. 클래스로 잡은 개별 규칙(.auth-input ·
   .set-input · 세리프를 의도적으로 쓰는 .story-composer-input 등)을 덮지 않아야 한다.
   font-size도 일부러 건드리지 않는다 — 칸 높이가 함께 바뀐다. button은 이미 개별 규칙이 맡는다. */
input, textarea, select { font-family: inherit; }

/* 강조 굵기 — UA 기본 `bolder`는 실리지 않은 700을 부른다. 500 face로 못 박는다. */
b, strong { font-weight: 500; }

/* 맨 링크 — 잉크 + 브라우저 기본 밑줄(「누를 수 있는 것 = 밑줄」). 클래스로 색을 잡은 링크는 그대로 이긴다. */
a { color: var(--text); }

/* 칸 시계(ClockDigits.vue) — 명조엔 고정폭 숫자가 없어 매초 바뀌는 시계가 흔들린다. 숫자만 1ch 칸에 세운다.
   칸(inline-block)이 줄바꿈 지점이 되므로 그릇은 nowrap(미니앱 Home.tsx HeroClock 실측). */
.clock-digits { white-space: nowrap; }
.clock-d { display: inline-block; width: 1ch; text-align: center; }

.container {
    width: 100%;
    max-width: 460px;
}

.brand {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0 0 4px;
}

.brand h1 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 1.6rem;
    margin: 0;
    letter-spacing: -.02em;
    color: var(--accent-hover);
}

/* 헤더 로고 책 아이콘 — 네비 아이콘 사전(nav-icons · navIcons.ts)과 통일한 라인아트 책 SVG(책등 3권).
   stroke=currentColor라 로고 색(--accent-hover)을 상속. .brand-home이 align-items:baseline이라
   inline SVG는 텍스트보다 살짝 떠 보여 align-self:center로 제목과 광학 정렬. */
.brand .brand-ico { width: 1.5rem; height: 1.5rem; align-self: center; color: var(--accent-hover); }
/* (구) 이모지 폴백 — admin 등 특수 이모지(🛠️ 등)는 그대로 유지 */
.brand .emoji { font-size: 1.4rem; }

/* 로고(이모지+제목)를 메인 대시보드(/) 링크로 — 최하단 '대시보드' 버튼 없이 어디서든 홈으로(UX 편의).
   링크 기본 스타일(파란색·밑줄) 제거하고 헤더 본래 모양 유지, 호버 시에만 제목에 밑줄로 클릭 가능 단서. */
.brand-home {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    text-decoration: none;
    color: inherit;
}
.brand-home:hover h1 { text-decoration: underline; }

.greeting {
    color: var(--muted);
    margin: 0 0 20px;
}

/* 독서 기록 화면 인사말 — 한 줄 .greeting 대신 헤드라인(명조 serif)+서브카피로 첫인상 강화.
   전역 .greeting과 분리한 화면 전용 클래스(다른 화면 영향 0). */
.history-greeting h1 {
    font-family: var(--font-serif);
    font-size: 31px;
    font-weight: 500;
    color: var(--text);
    margin: 0;
    letter-spacing: -.3px;
    word-break: keep-all;
}
.history-greeting p {
    font-size: 14px;
    color: var(--muted);
    margin: 7px 0 0;
}

/* 판화 한 점 — Thomas Bewick 「Barn Owl」(1797, 퍼블릭 도메인 — 미니앱 ui.tsx 6-10 주석과 같은 출처). 미니앱 assets/woodcut-owl.png와 같은 파일.
   모양은 PNG 알파, 색은 토큰 — 낮엔 잉크, 다크엔 밝은 잉크가 같은 규칙으로 칠해진다(반전 필터를 쓰면 차가운 회색 #E2E4E7이 된다).
   자리는 랜딩 히어로 · 책장 머리 · 빈 여백 셋, 한 층(페이지 또는 열린 모달)에 하나. 장식이라 aria-hidden 빈 span.
   ⚠️ 파일을 고칠 땐 이름을 바꾼다 — 해시가 안 붙으면 SW cache-first가 옛 그림을 계속 준다. */
.woodcut { display: block; margin-inline: auto; aspect-ratio: 444 / 441; background-color: var(--text);
           -webkit-mask: url('/icons/woodcut-owl-1dbd4464069e7d59890b0af010695e0e.png') center / contain no-repeat;
           mask: url('/icons/woodcut-owl-1dbd4464069e7d59890b0af010695e0e.png') center / contain no-repeat; }
.woodcut-64 { width: 64px; } .woodcut-148 { width: 148px; } .woodcut-180 { width: 180px; }

/* 내 책장 인사말 — 명조 serif 제목 + 요약통계 한 줄(시안 My Shelf).
   history-greeting 과 같은 '화면 전용 분리' 패턴(전역 .greeting 영향 0). */
.shelf-greeting { margin: 0 0 20px; }
/* 책장 머리 아치 — 미니앱 서재 아치와 같은 숫자(폭 260 · 패딩 24 · 판화 64 · 간격 8 · 명조 32/40).
   제목은 「내 책장」 고정 — 닉네임을 넣으면 긴 이름이 260 아치를 넘는다(닉네임은 아래 요약 줄로). */
.shelf-arch {
    width: 260px; max-width: 100%; box-sizing: border-box;
    padding: 24px; gap: 8px;
    display: flex; flex-direction: column; align-items: center; text-align: center;
    border: 1px solid var(--text); border-radius: 999px 999px 0 0;
}
.shelf-greeting h1 {
    font-family: var(--font-serif);
    font-size: 32px;
    line-height: 40px;
    font-weight: 500;
    color: var(--text);
    margin: 0;
    letter-spacing: -.01em;
    word-break: keep-all;
}
.shelf-summary {
    margin: 8px 0 0;
    font-size: 13px;
    color: var(--muted);
}
/* 표 형식 숫자 — 요약통계 등 숫자 폭 고정(시안 .tnum). 명시 적용한 곳만 영향. */
.tnum { font-variant-numeric: tabular-nums; }

/* 입구 폼 화면(signup·onboarding) 환영 헤더 — landing 히어로의 축소판.
   greeting 한 줄 대신 헤드라인+서브카피로 첫인상을 강화한다(페이크볼드 대신 크기로 위계 — #287 원칙 계승). */
.entry-hero { margin: 4px 0 22px; }
.entry-hero h2 {
    font-size: 1.5rem;
    line-height: 1.35;
    color: var(--text);
    margin: 0 0 8px;
    letter-spacing: -.01em;
    word-break: keep-all;
}
.entry-hero p {
    color: var(--muted);
    margin: 0;
    line-height: 1.7;
    word-break: keep-all;
}

/* 입구 폼 안내 — 가치를 전달하는 문단을 옅은 면 박스로 띄워 위계를 준다(onboarding 하루목표·7일 윈도우 설명).
   전역 공유 .status-line과 분리한 입구 전용 클래스(다른 화면 영향 차단). */
.entry-note {
    margin: 0 0 18px;
    padding: 14px 16px;
    background: var(--sage-soft);
    border-radius: var(--radius-sm);
    color: var(--text);
    line-height: 1.7;
    word-break: keep-all;
    font-size: .92rem;
}
.entry-note strong { color: var(--accent-hover); font-weight: 500; }

/* ── 온보딩 강화 (발견 9·10·11·12) — 시작을 가로막지 않으면서 프레이밍만 손본다 ───────────── */

/* 부채 규칙(7일 윈도우·자동 용서) 아코디언(발견 9) — 신규 사용자 위축 방지로 기본 접힘.
   entry-note의 옅은 면 박스 톤을 계승하되, 궁금한 사람만 펼치게 <details>로 감싼다.
   ⚠️ body 자식에 display를 강제하지 않는다 — UA의 details:not([open]) 숨김을 이기지 않도록(파일 상단 리셋 주석). */
.entry-accordion {
    margin: 0 0 18px;
    background: var(--sage-soft);
    border-radius: var(--radius-sm);
    padding: 12px 16px;
}
.entry-accordion > summary {
    cursor: pointer;
    list-style: none;
    font-size: .92rem;
    font-weight: 500;
    color: var(--accent-hover);
    word-break: keep-all;
}
.entry-accordion > summary::-webkit-details-marker { display: none; }
.entry-accordion > summary::after { content: " ▾"; font-size: 13px; }
.entry-accordion[open] > summary::after { content: " ▴"; }
.entry-accordion-body {
    margin: 10px 0 0;
    color: var(--text);
    line-height: 1.7;
    font-size: .9rem;
    word-break: keep-all;
}
.entry-accordion-body strong { color: var(--accent-hover); font-weight: 500; }

/* 불변 아이디 경고(발견 11) — 흐린 힌트가 아니라 앰버 경고 박스로 격상. README 8절 지정 앰버색
   (경고 전용, 다른 화면 무영향). 되돌릴 수 없는 결정임을 시각적으로 분명히 한다. */
.warn-box {
    margin: 6px 0 0;
    padding: 10px 12px;
    background: var(--warn-bg-3);
    border: 1px solid var(--warn-border-4);
    border-radius: var(--radius-sm);
    color: var(--warn-fg-4);
    font-size: .82rem;
    line-height: 1.55;
    word-break: keep-all;
}
.warn-box strong { font-weight: 500; }

/* 하루 목표 프리셋 칩(발견 10) — [20][30][60][직접]. 0 입력을 밀어내고 작게 시작하도록 유도.
   터치 타깃 ≥44px(min-height). Vue 아일랜드가 아래 목표 input을 세팅한다. */
.onb-presets {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 8px;
}
.onb-preset-chip {
    width: auto;               /* 전역 button{width:100%} 상쇄 — 빠지면 칩이 풀폭이 돼 flex-wrap에서 세로로 쌓임(#286 가드) */
    flex: 1 1 auto;
    min-width: 60px;
    min-height: 44px;
    padding: 8px 12px;
    font: inherit;
    font-size: .9rem;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text);
    font-weight: 400;
    cursor: pointer;
}
.onb-preset-chip:hover { background: var(--sage-hover); }
/* 고른 칩 = 잉크 1px 테 + 500(채움 없음 — 검정 채움은 주 버튼 하나의 몫이다). */
.onb-preset-chip.is-active {
    border-color: var(--text);
    font-weight: 500;
}

/* 실시간 미리보기 카드(발견 12) — "다른 사람에게 이렇게 보여요". 종이톤 카드로 폼 흐름 안에 둔다. */
.onb-preview-mount:empty { display: none; }   /* 아일랜드 미마운트(JS 비활성) 시 빈 자리 숨김 */
.onb-preview {
    margin: 0 0 16px;
    padding: 12px 0;
    background: var(--card-bg);
    border: 0;
    border-radius: 0;
}
.onb-preview-label { margin: 0 0 8px; font-size: .78rem; color: var(--muted); }
.onb-preview-card { display: flex; align-items: center; gap: 12px; }
.onb-preview-avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; border-radius: 50%;
    background: transparent; color: var(--text); border: 1px solid var(--text);
    font-family: var(--font-serif);
    font-size: 1.1rem; font-weight: 500; flex: none;
}
.onb-preview-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.onb-preview-name { font-size: .95rem; font-weight: 500; color: var(--text); word-break: break-all; }
.onb-preview-handle { font-size: .82rem; color: var(--accent-hover); word-break: break-all; }
.onb-preview-handle.is-muted { color: var(--muted); }
.onb-preview-hint { margin: 8px 0 0; font-size: .78rem; color: var(--muted); }

/* 인사말 자리의 작가 격언 — 문장은 본문 톤, 작가는 한 단 작고 흐리게(출처 표기). */
.greeting.quote .quote-text {
    font-style: italic;
}
.greeting.quote .quote-author {
    display: block;
    margin-top: 2px;
    font-size: 0.85em;
    opacity: 0.8;
}

/* 카드 — 에디토리얼엔 면이 없다(설계 §5-6 「면 없는 덩어리」). 면·테·그림자 0, 카드 면 = 종이라 덩어리 경계는
   섹션 머리의 잉크 선과 세로 여백이 맡는다. 좌우 안쪽 여백도 0 — 글 줄이 페이지 가장자리 선에 선다. */
.card {
    background: var(--card-bg);
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 24px 0;
    margin-bottom: 16px;
}

/* 섹션 머리 — 명조 500 22/30 · 잉크 · 아래 잉크 1px 선(미니앱 H1 20/28을 본문 비율로 옮긴 값 — 웹 본문 18 × 1.25). */
.card h2 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 22px;
    line-height: 30px;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text);
    padding-bottom: 8px;
    border-bottom: 1px solid var(--text);
    margin: 0 0 12px;
}

/* 큰 타이머 숫자 */
.timer-display {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
    font-size: 3rem;
    font-weight: 500;
    letter-spacing: .02em;
    color: var(--accent);
    margin: 0;
}

.timer-display.met { color: var(--ok); }

/* 설정의 체크박스 행 — 라벨 텍스트와 체크박스를 가로로 정렬. */
.check-row {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}
.check-row input[type="checkbox"] {
    width: auto;
    margin: 0;
}

.timer-sub {
    color: var(--muted);
    margin: 8px 0 0;
    font-size: .95rem;
}

.timer-sub .mono {
    font-variant-numeric: tabular-nums;
    font-weight: 500;
    color: var(--text);
}

.goal-badge {
    display: inline-block;
    margin-top: 10px;
    padding: 4px 12px;
    border-radius: 2px;
    background: var(--ok-soft-2);
    color: var(--ok);
    font-size: .85rem;
    font-weight: 500;
}

/* 누적 상한 도달 경고 (옅은 면 + 잉크 — 에디토리얼은 상태색을 빨강만 남긴다) */
.cap-badge {
    margin: 12px 0 0;
    padding: 10px 12px;
    border-radius: 2px;
    background: var(--warn-bg-2);
    color: var(--warn-fg-3);
    border: 1px solid var(--warn-border-2);
    font-size: .9rem;
    font-weight: 500;
}

.status-line { margin: 0 0 14px; color: var(--muted); }
.status-line .mono { color: var(--text); font-weight: 500; }

/* "다시 분석" 버튼 안에 같이 보이는 오늘 남은 횟수 — 작고 옅게(버튼 라벨 보조) */
.refresh-count { margin-left: 8px; font-weight: 400; font-size: .82em; opacity: .8; }

/* 책BTI 공개 안내문은 아래 "책BTI 페이지 재스킨" 블록의 ? 헬프 팝오버(.pbti-help-pop)에서 정의. */

/* 타이머와 한 카드로 합쳐진 측정 컨트롤 — 큰 숫자 바로 아래 답답하지 않게 위 여백을 둔다 */
.timer-controls { margin-top: 18px; }

/* 대시보드 첫 진입 빈상태(책 0권) — 측정 폼 대신 환영+첫 행동 유도(타이머는 00:00:00로 보이고 그 아래 CTA).
   "텅 빈 화면"이 아니라 "첫 책을 추가하면 시작"이라는 다음 행동을 또렷이 안내한다. */
.timer-empty { margin-top: 6px; }
.timer-empty p { color: var(--muted); line-height: 1.7; margin: 0 0 14px; word-break: keep-all; }
.timer-empty p strong { color: var(--accent-hover); font-weight: 500; }
.timer-empty .btn { display: block; text-decoration: none; text-align: center; } /* a는 기본 inline이라 .btn의 width:100%가 안 먹음 → block으로 측정 시작 버튼처럼 풀폭 */

/* 버튼 */
/* 버튼 2단(설계 §5-6 — 미니앱 에디토리얼과 같은 문법).
   기본 = 외곽선 알약(잉크 1px · 999px · 채움 없음). 주 행동 하나만 검정 알약(.btn-primary · .dash-btn-fill · .auth-btn-primary)이다 —
   **한 층(페이지 또는 열린 모달)에 검정 알약은 하나**, 목록 행마다 반복되는 버튼은 검정이 아니다(REQ-22).
   테를 원치 않는 버튼은 각자 `border: 0/none`으로 지운다(그 선언이 이 기본을 이긴다). */
button, .btn {
    font: inherit;
    font-weight: 500;
    border: 1px solid var(--text);
    border-radius: 999px;
    padding: 12px 18px;
    cursor: pointer;
    width: 100%;
    background: transparent;
    color: var(--text);
    transition: background-color .15s ease;
}
.btn:not(.btn-primary, .btn-danger):hover { background-color: var(--sage-hover); }

/* 검정 알약(주) — 잉크 채움 + 미색 글자. 공부 카드 안에선 --accent-fill이 파란 잉크라 저절로 파란 알약이다. */
.btn-primary {
    background: var(--accent-fill);
    color: var(--on-accent);
    border: 1px solid var(--accent-fill);
    border-radius: 999px;
}
.btn-primary:hover { opacity: .88; }

/* 비활성 — 옅게 + 금지 커서. 주 버튼은 반투명 대신 옅은 면 + 흐린 글자(불투명 1 — 미니앱과 같은 문법). */
button:disabled { opacity: .5; cursor: not-allowed; }
.btn-primary:disabled { background: var(--sage-soft); border-color: var(--sage-soft); color: var(--muted); opacity: 1; cursor: not-allowed; }

/* 위험 = 빨강 외곽선(채움 없음). */
.btn-danger {
    background: transparent;
    border: 1px solid var(--danger);
    color: var(--danger);
}
.btn-danger:hover { background: var(--danger-soft); }

/* 외곽선 알약(보조) — <a class="btn-ghost">도 있어 테를 직접 갖는다. */
.btn-ghost {
    background: transparent;
    color: var(--text);
    border: 1px solid var(--text);
    border-radius: 999px;
}
.btn-ghost:hover { background-color: var(--sage-hover); }

/* 로그아웃 — 설정 바로가기와 너무 붙어 보여 간격을 띄우고(.logout-form),
   다른 타일처럼 hover 피드백을 주되 '떠나는' 동작이라 빨강으로 강조한다. */
.logout-form { margin-top: 18px; }
.btn-logout { transition: background .15s ease, color .15s ease, border-color .15s ease; }
.btn-logout:hover {
    background: var(--bg);
    color: var(--danger);
    border-color: var(--danger);
}

/* 소셜 로그인 */
.oauth-divider {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 18px 0;
    color: var(--muted);
    font-size: .85rem;
}
.oauth-divider::before,
.oauth-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--border);
}

.btn-oauth {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    text-decoration: none;
    box-sizing: border-box;
}
.btn-oauth-google {
    background: transparent;
    color: var(--text);
    border: 1px solid var(--text);
    border-radius: 999px;
}
.btn-oauth-google:hover { background: var(--sage-hover); }
.oauth-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #4285f4;
    color: #fff;
    font-weight: 500;
    font-size: .85rem;
}

/* 폼 (회원가입 등) */
.field { margin-bottom: 16px; }
.field label {
    display: block;
    font-size: .85rem;
    font-weight: 500;
    margin-bottom: 6px;
}
.field input,
.field select {
    width: 100%;
    font: inherit;
    padding: 10px 12px;
    border: 1px solid var(--muted);
    border-radius: 2px;
    background: transparent;
    color: var(--text);
}
.field select { appearance: auto; cursor: pointer; }
.field input:focus,
.field select:focus {
    outline: none;
    border-color: var(--text);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
/* 입력 보조 안내 — label과 input 사이/아래의 흐린 설명(아이디 규칙·타임존 이유 등).
   <small class="field-hint">로 쓰이나 정의가 없어 브라우저 기본 small만 먹던 것을 종이톤에 맞게 명시. */
.field-hint {
    display: block;
    margin-top: 6px;
    color: var(--muted);
    font-size: .8rem;
    line-height: 1.5;
    word-break: keep-all;
}
.field-error {
    display: block;
    margin-top: 6px;
    color: var(--danger);
    font-size: .85rem;
}

/* 플래시 / 알림 */
.alert {
    padding: 12px 14px;
    border-radius: 2px;
    margin-bottom: 16px;
    font-size: .95rem;
}
.alert-error {
    background: var(--danger-soft-2);
    color: var(--danger);
    border: 1px solid var(--danger-line-2);
}
.alert-ok {
    background: var(--ok-soft-2);
    color: var(--ok);
    border: 1px solid var(--ok-line-2);
}
.alert-warn {
    background: var(--warn-bg-2);
    color: var(--warn-fg-2);
    border: 1px solid var(--warn-border-3);
}
/* 이메일 미검증 안내 배너 — 안내 문구 + 인라인 재발송 버튼을 한 줄에(좁으면 줄바꿈). */
.verify-banner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.verify-banner form {
    margin: 0;
}
/* 가입완료 환영 배너 (§6.4) — 온보딩 직후 1회. 안내 문구 + 닫기(✕)를 한 줄에(.alert 기반). */
.welcome-banner {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    background: var(--sage-soft);
    border: 1px solid var(--accent);
    color: var(--text);
}
.welcome-banner-body { display: flex; flex-direction: column; gap: 3px; word-break: keep-all; }
.welcome-banner-body strong { color: var(--accent-hover); }
.welcome-banner-close {
    width: auto;
    flex-shrink: 0;
    background: none;
    border: none;
    padding: 0 2px;
    font-size: 1rem;
    line-height: 1;
    color: var(--muted);
    cursor: pointer;
}
.welcome-banner-close:hover { color: var(--text); }
/* 배너 안 재발송 버튼: 전역 button{width:100%}를 받지 않게 width:auto. 링크처럼 보이는 버튼(밑줄). */
.btn-inline-link {
    width: auto;
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: var(--warn-fg-2);
    font-weight: 500;
    text-decoration: underline;
    cursor: pointer;
}

/* 회원 탈퇴 등 위험 작업 구역 */
.danger-zone { border-color: var(--danger-line-2); }
.danger-zone h2 { color: var(--danger); }

/* 공용 하단 네비 — 바 없는 화면(에러·약관·비밀번호 찾기·관리자)의 2열 타일.
   로그인 사용자 화면의 이동은 양옆 세로 바(fragments/side-rails)로 옮겼다(2026-09-15).
   링크 수가 홀수면 마지막 타일이 전체폭(단일 링크 페이지=전체폭 버튼 1개). */
.link-row {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
    margin-top: 8px;
}
.link-row a {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 14px 16px;
    background: transparent;
    border: 1px solid var(--text);
    border-radius: 999px;
    color: var(--text);
    text-decoration: none;
    font-weight: 500;
    word-break: keep-all;
    transition: background .2s ease, border-color .2s ease, transform .05s;
}
/* hover 효과 — 테두리 강조+그림자(떠오름) 대신 옅은 잉크 채움(양옆 바 .rail-item:hover와 같은 --nav-hover-* 토큰 공유). */
.link-row a:hover { background: var(--nav-hover-bg); text-decoration: none; }
.link-row a:active { transform: translateY(1px); }
.link-row a:last-child:nth-child(odd) { grid-column: 1 / -1; }
/* 하단 .link-row 내 라인 아이콘 — Thymeleaf nav-icons fragment. 색은 양옆 바 아이콘과 같은
   잉크(accent-hover) — 라벨과 같은 잉크라 색으로는 나뉘지 않는다. 정렬·간격은 .link-row a의 flex가 처리. */
.link-row a svg.link-ico { flex: 0 0 auto; color: var(--accent-hover); }

/* 하이라이트 밴드 — 측정 카드 바로 밑, '재미' 동선(내 책장·내 공개 프로필) 승격용.
   quick-tile보다 큼직하고 포인트 색으로 강조해 노출 우선순위를 위로 끌어올린다.
   좁은 화면(2칸이 답답할 때)에선 1열로 떨어뜨린다. */
.highlight-actions {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
    margin: 14px 0;
}
.highlight-tile {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 18px 18px;
    background: var(--card-bg);
    border: 1.5px solid var(--accent);
    border-radius: var(--radius);
    color: var(--text);
    text-decoration: none;
    transition: border-color .15s, box-shadow .15s, transform .05s;
}
.highlight-tile:hover { border-color: var(--accent-hover); }
.highlight-tile:active { transform: translateY(1px); }
.highlight-tile .ht-icon { font-size: 1.7rem; line-height: 1; }
.highlight-tile .ht-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.highlight-tile .ht-label { font-weight: 500; white-space: nowrap; }
.highlight-tile .ht-sub { font-size: .8rem; color: var(--muted); }
@media (max-width: 380px) {
    .highlight-actions { grid-template-columns: 1fr; }
}

/* === 페이지 세로 스택 — 간격 일원화 (간격 책임을 컨테이너 gap으로) ===
   SSR→Vue 분할로 "바깥 간격을 누가 책임지나"가 각 자식의 개별 마진(.greeting 20 / .card 16 /
   .highlight-actions 14 / .quick-actions 0 / .logout-form 18 …)으로 흩어져, 카드 아닌 요소가
   끼면 0px 붙음·비균일 리듬이 났다(예: 대시보드 20·16·14·0·16·18). 간격을 자식 마진이 아니라
   부모 컨테이너의 gap이 소유하게 일원화한다 — 직계 사이는 균일 16px, 자식의 수직 마진은 0 리셋(이중-간격 방지).
   적용 대상 두 부류: ① fragment 페이지(dashboard·history·books·personality)는 wrapper 없이 마운트 id
   직계가 평탄 → 마운트 id에 직접. ② div 래퍼 페이지(search·profile·follow-list·book-readers·block-list)는
   루트 div의 .page-stack에. 페이지마다 스코프돼 전역 .container/타 영역엔 영향 0. (learning-notes N-115) */
#dashboard-app, #history-app, #books-app, #personality-app,
.page-stack {
    display: flex;
    flex-direction: column;
    gap: 16px;
}
#dashboard-app > *, #history-app > *, #books-app > *, #personality-app > *,
.page-stack > * {
    margin-top: 0;
    margin-bottom: 0;
}

/* 일자별 독서 기록 리스트 */
.record-list { list-style: none; margin: 0; padding: 0; }
.record-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 0;
    border-bottom: 1px solid var(--border);
}
.record-row:last-child { border-bottom: none; }
/* 책장 요약(책BTI): 라벨(예: 자주 읽는 저자) 위 / 내용 아래로 세로 스택.
   기본 .record-row는 가로(space-between)라 내용이 길면 라벨이 줄바꿈돼 보기 나빴다. */
.summary-list .record-row { flex-direction: column; align-items: flex-start; gap: 4px; }
.summary-list .record-books { font-size: .9rem; }
.record-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.record-date { color: var(--text); font-weight: 500; }
.record-books {
    color: var(--muted);
    font-size: .85rem;
    word-break: keep-all;
    overflow-wrap: anywhere;
}
.record-time {
    color: var(--accent);
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    margin-left: auto;
    white-space: nowrap;
}

/* 월별 보기: 한 번에 한 달(◀▶ 이동), 그 달 일자 리스트는 고정 높이 스크롤 박스.
   기록이 쌓여도 페이지가 한없이 길어지지 않게 월 단위로 끊고 그 안에서만 스크롤한다. */
.month-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 6px;
}
.month-nav-label {
    flex: 1 1 auto;
    text-align: center;
    font-weight: 500;
    font-size: .9rem;
    color: var(--text);
}
.month-nav-btn {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--text);
    border-radius: 999px;
    background: transparent;
    color: var(--text);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease;
}
.month-nav-btn:hover:not(:disabled) { background: var(--sage-hover); }
.month-nav-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.month-nav-btn:disabled { opacity: .35; cursor: default; }
.month-section[hidden] { display: none; }
/* 일자 리스트 스크롤 박스: 길어도 화면을 점령하지 않게 고정 높이 + 내부 스크롤(모바일 관성 스크롤).
   overscroll-behavior:contain 으로 박스 끝에서 페이지로 스크롤이 새지 않게 한다. */
.record-scroll {
    max-height: 360px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}

/* 기록 날짜 줄 펼침(R2) — 측정이 있는 날은 머리 전체가 버튼이고, 펼치면 측정 한 건 = 한 줄.
   .record-head는 옛 두 칸(날짜·시간)을 그대로 감싸 펼침 없는 날도 예전과 같은 모양이다.
   공부 기록은 카드의 .is-study 토큰 스왑이 그대로 파랑으로 끌고 간다(리터럴 0줄). 애니메이션 없음. */
.record-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex: 1 1 100%; min-width: 0; }
.record-row.is-expandable { flex-wrap: wrap; }
.record-toggle {
    width: 100%; margin: 0; padding: 0; border: 0; background: none;
    font: inherit; color: inherit; text-align: left; cursor: pointer; border-radius: 999px;
}
.record-toggle:hover .record-date { color: var(--accent-hover); }
.record-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.record-chevron { flex: 0 0 auto; color: var(--muted); }
.record-row.is-open .record-chevron { transform: rotate(180deg); }
.record-sessions {
    flex: 1 1 100%; list-style: none; margin: 10px 0 0; padding: 0 0 0 12px;
    border-left: 2px solid var(--border);
}
/* [시각 범위 / 길이] · 책 · 버튼 — 시각과 길이를 두 줄로 쌓아 좁은 폭에서도 제목 칸이 남는다(390px 기준). */
.record-session {
    display: grid; grid-template-columns: max-content minmax(0, 1fr) max-content;
    align-items: center; gap: 12px; padding: 6px 0;
}
.record-session-when { display: flex; flex-direction: column; gap: 1px; font-variant-numeric: tabular-nums; }
.record-session-range { font-size: 13px; color: var(--text); white-space: nowrap; }
.record-session-len { font-size: 13px; color: var(--muted); white-space: nowrap; }
.record-session-book { min-width: 0; font-size: 13.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.record-session-book.is-none { color: var(--muted); }
.record-session-btn {
    min-height: 36px; padding: 0 12px; border: 1px solid var(--border); border-radius: 999px;
    background: var(--card-bg); color: var(--muted); font: inherit; font-size: 13px; font-weight: 500;
    white-space: nowrap; cursor: pointer;
}
/* 책 없는 측정이 이 화면이 부르는 일이다 — 「책 붙이기」만 잉크색, 「바꾸기」는 조용히. */
.record-session-btn.is-attach { color: var(--accent-hover); border-color: var(--accent); }
.record-session-btn:hover { color: var(--text); border-color: var(--accent); }
.record-session-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* === 독서 잔디 (GitHub 컨트리뷰션 그래프 스타일) === */
/* 헤더: 제목 좌측 / 연속 일수 칩(「N일 연속 독서」) 우측 상단.
   h2의 아래 여백(12px)을 래퍼로 옮겨 요약문과의 간격을 그대로 유지한다. */
.grass-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 12px; }
.grass-head { padding-bottom: 8px; border-bottom: 1px solid var(--text); }
.grass-head h2 { margin: 0; padding-bottom: 0; border-bottom: 0; }   /* 머리 줄이 섹션 머리 선을 진다 */
/* 연속 일수 뱃지 — 대시보드 .dash-streak-chip과 통일(옅은 면 칩 + 잉크 글자 + SVG 새싹). 값 바꾸면 둘 다. */
.grass-streak {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: var(--sage-soft-2);
    color: var(--accent-hover);
    font-size: 13px;
    padding: 6px 13px;
    border-radius: 999px;
    white-space: nowrap;
}
.grass-streak strong { font-weight: 500; font-variant-numeric: tabular-nums; }

.grass-summary { color: var(--ink-2); font-size: 14.5px; margin: 0 0 18px; }
.grass-summary strong { color: var(--ok); font-weight: 500; font-variant-numeric: tabular-nums; }

.grass {
    display: flex;
    gap: 6px;
    align-items: flex-start;
    overflow-x: auto;        /* 좁은 화면에선 가로 스크롤 */
    padding-bottom: 6px;
}
.grass-main { display: flex; flex-direction: column; gap: 4px; }

/* 좌측 요일 라벨 — 그리드 7행에 맞춤. 상단 월 라벨 높이(14+4)만큼 내려 정렬 */
.grass-weekdays {
    display: grid;
    grid-template-rows: repeat(7, 13px);
    gap: 3px;
    margin-top: 18px;
    font-size: 13px;
    color: var(--neutral-3-2);
    line-height: 13px;
    text-align: right;
    padding-right: 4px;
}

/* 상단 월 라벨 — 53열 트랙에 grid-column-start로 배치 */
.grass-months {
    display: grid;
    grid-template-columns: repeat(53, 13px);
    gap: 3px;
    height: 14px;
    font-size: 13px;
    line-height: 14px;
    color: var(--neutral-3-2);
}
.grass-months span { white-space: nowrap; }

/* 본체 그리드 — 열=주, 행=요일(일~토). 열 방향으로 채운다 */
.grass-grid {
    display: grid;
    grid-template-rows: repeat(7, 13px);
    grid-auto-flow: column;
    grid-auto-columns: 13px;
    gap: 3px;
}

/* 셀 색·크기·manual — 옛 대시보드 잔디와 톤을 맞춘 값이다(그쪽은 2026-09-07에 걷었고 여기만 남았다). */
.grass-cell {
    width: 13px;
    height: 13px;
    border-radius: 2px;
    background: var(--grass-0);       /* level-0(목표 미달/없음) 기본 */
}
.grass-cell.empty { background: transparent; }    /* placeholder(선행 빈칸 + 미래) — 대시보드와 동일 투명 */
.grass-cell.level-0 { background: var(--grass-0); }
.grass-cell.level-1 { background: var(--grass-1); }
.grass-cell.level-2 { background: var(--grass-2); }
.grass-cell.level-3 { background: var(--grass-3); }
.grass-cell.level-4 { background: var(--grass-4); }
/* 직접 채운 날 — 가는 테(강조색을 하나 더 들이지 않는다 — 미니앱 MANUAL_OUTLINE과 ≈ 같은 값). */
.grass-cell.manual { outline: 1px solid var(--neutral-2); outline-offset: -1px; }

.grass-legend {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 18px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--line-1-2);
    font-size: 13px;
    color: var(--muted);
}
.grass-legend-group { display: inline-flex; align-items: center; gap: 7px; }
.grass-legend-scale { display: inline-flex; gap: 3px; }
.grass-legend i { display: inline-block; }

/* 잔디 셀 hover 다크 툴팁 — 커서를 따라다닌다(JS가 left/top 인라인 지정).
   position:fixed라 카드의 overflow:auto/hidden에 안 잘리고 뷰포트 기준으로 뜬다. */
.grass-tip {
    position: fixed;
    transform: translateX(-50%);
    background: var(--card-bg);
    color: var(--text);
    border: 1px solid var(--text);
    font-size: 13px;
    padding: 6px 10px;
    border-radius: 2px;
    white-space: nowrap;
    pointer-events: none;
    z-index: 9999;
}
/* === 내 책장 (Book) === */
.muted { color: var(--muted); }

.book-search-form, .book-manual-form { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.book-search-form input[type=text],
.book-manual-form input[type=text] {
    flex: 1 1 160px;
    padding: 8px 10px;
    border: 1px solid var(--muted);
    border-radius: 2px;
    background: transparent; color: var(--text);
    font-size: .95rem;
}
.book-manual-form select,
.book-add-form select, .book-actions select {
    padding: 7px 8px;
    border: 1px solid var(--muted);
    border-radius: 2px;
    background: transparent;
    color: var(--text);
}
/* 입력칸 포커스 = 잉크 테(에디토리얼 §5-6 「입력칸」 — 흐린 글자색 테가 잉크로 진해진다). 링은 브라우저 기본 포커스 표시 그대로. */
.book-search-form input[type=text]:focus, .book-manual-form input[type=text]:focus,
.book-manual-form select:focus, .book-add-form select:focus, .book-actions select:focus,
.search-row input[type=text]:focus, .book-sheet-search input:focus, .shop-report-field select:focus,
.fb-form .fb-field select:focus, .fb-form .fb-field input:focus, .fb-form .fb-field textarea:focus,
.fb-reply-form textarea:focus { border-color: var(--text); }

/* 검색 폼: 검색 기준 칩을 위에 두고, 입력+버튼을 아래 한 줄로. */
.book-search-form { flex-direction: column; align-items: stretch; }
/* 검색 기준 칩 — 라디오 대신 제목/저자/출판사 토글(활성=잉크 테 + 500, 채움 없음). */
.search-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.search-chip {
    width: auto;                                   /* 전역 button{width:100%} 상쇄(#286 가드) */
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text);
    border-radius: 999px;
    padding: 6px 14px;
    font-size: .85rem;
    font-weight: 400;
    cursor: pointer;
    line-height: 1;
}
.search-chip:hover { border-color: var(--accent); color: var(--accent); }
.search-chip.active { border-color: var(--text); font-weight: 500; }   /* 고른 칩 = 잉크 테 + 500(채움 없음) */
/* 검색 바(넓게) 위 + 검색 버튼 아래로 세로 배치 — 버튼이 입력칸을 잡아먹지 않게. */
.search-row { display: flex; flex-direction: column; gap: 10px; align-items: stretch; }
.search-row input[type=text] {
    /* 부모가 column flex라 .book-search-form의 flex:1 1 160px가 '높이' 160px로 잘못 먹힌다 —
       리셋해서 한 줄 높이로 되돌린다(세로로 길쭉해지던 문제). */
    flex: none;
    width: 100%;
    box-sizing: border-box;
    padding: 12px 14px;
    border: 1px solid var(--muted);
    border-radius: 2px;
    background: transparent; color: var(--text);
    font-size: 1rem;
}
.search-row .btn-primary { width: 100%; }

/* 사용자 검색(/search) 폼: input+버튼이 .book-search-form 바로 밑에 온다(검색 기준 라디오 없음).
   부모가 column flex라 input의 flex:1 1 160px가 '높이' 160px로 잘못 먹혀 세로로 길쭉해진다 —
   책 검색은 .search-row가 리셋하지만 이쪽은 감싸는 래퍼가 없어 직접 리셋한다. */
.book-search-form > input[type=text] { flex: none; width: 100%; box-sizing: border-box; }

/* 직접 추가(폴백) — '책 추가' 카드 안에 접어두는 <details>. 검색이 주 경로, 못 찾을 때만 펼친다.
   검색 결과/페이저 아래에 구분선을 두고, summary는 펼침 화살표(▸/▾)가 달린 은은한 토글. JS 불필요. */
.manual-add { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.manual-add > summary {
    cursor: pointer;
    color: var(--muted);                                /* 시안: 안내문은 흐리게, '직접 추가'만 강조 */
    font-size: .9rem;
    font-weight: 500;
    list-style: none;                                   /* Firefox 기본 마커 제거 */
}
.manual-add > summary::-webkit-details-marker { display: none; }  /* WebKit 기본 마커 제거 */
.manual-add > summary::before { content: "▸ "; color: var(--accent); }        /* 접힘 표시 */
.manual-add[open] > summary::before { content: "▾ "; }  /* 펼침 표시 */
/* '직접 추가' CTA만 잉크 + 밑줄로 강조(시안 My Shelf). */
.manual-add-cta { color: var(--accent); text-decoration: underline; }
.manual-add > summary:hover .manual-add-cta { text-decoration: none; }
.manual-add .book-manual-form { margin-top: 12px; }
/* ⚠️ <details> 접힘이 실제로 동작하려면 닫혔을 때 폼을 author 규칙으로 직접 숨겨야 한다.
   위 .book-manual-form{display:flex}(author)가 브라우저 UA의 닫힘-숨김(details:not([open])>*{display:none})을
   이기기 때문(cascade origin: author > UA). 그대로 두면 접어도 폼이 늘 보인다.
   특정성을 .book-manual-form(0,1,0)보다 높여(0,3,0) 닫힘일 때만 재숨김. (cf. .book-row[hidden] 동일 함정) */
.manual-add:not([open]) .book-manual-form { display: none; }

.book-list { list-style: none; padding: 0; margin: 8px 0 0; }
/* 책 목록 — 고정 높이 스크롤 박스. 내 책장(/books)·책방(공개 프로필 /u/{id})의 공개 책장에 공용.
   책이 많아도 목록 자체는 화면의 60%까지만 차지하고 그 안에서만 스크롤되므로,
   페이지가 길어지지 않아 하단 네비(← 대시보드 등)가 늘 바로 아래 보인다.
   책이 적으면 max-height에 안 닿아 스크롤바도 안 생긴다(자연 폴백). scrollbar-gutter로 폭 흔들림 방지.
   상태 필터 칩은 이 ul 밖(위)이라 스크롤과 무관하게 고정된다. */
.shelf-scroll {
    max-height: 60vh;
    overflow-y: auto;
    scrollbar-gutter: stable;
    -webkit-overflow-scrolling: touch;  /* iOS 관성 스크롤 */
    overscroll-behavior: contain;       /* 끝에서 페이지로 스크롤 번지지 않게 */
    padding-right: 6px;                 /* 스크롤바와 내용 간격 */
}
/* 검색 결과 — ~3행 고정높이 스크롤 박스. "다음" 페이저를 대체(한 번에 받아 박스 안에서만 스크롤).
   shelf-scroll과 같은 관성/거터/번짐방지, 높이만 작게. */
.search-scroll {
    max-height: 430px;
    overflow-y: auto;
    scrollbar-gutter: stable;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding-right: 6px;
}
/* 친구 추천 — 고정높이 스크롤 박스. 추천이 꽉 차면(최대 10명) 또는 이유 칩으로 길어져도
   페이지가 늘어나 하단 네비가 밀리지 않게. 적으면 max-height 미도달=스크롤바 없음(자연 폴백).
   .search-scroll과 같은 관성/거터/번짐방지 레시피. */
.recommend-scroll {
    max-height: 430px;
    overflow-y: auto;
    scrollbar-gutter: stable;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding-right: 6px;
}
.book-row {
    display: flex;
    flex-wrap: wrap;            /* 좁으면 액션 줄을 통째로 다음 줄로 내린다 */
    align-items: center;
    gap: 12px 16px;
    padding: 12px 0;
    border-bottom: 1px solid var(--border);
}
.book-row:last-child { border-bottom: none; }
.book-cover {
    width: 44px;
    height: 64px;
    object-fit: cover;
    border-radius: 2px;
    flex-shrink: 0;
    background: var(--border);
}
/* 무표지 책 표지 플레이스홀더 — coverUrl 이 없을 때 색 배경 + 이니셜(명조 serif).
   배경/글자색은 coverColor()가 결정적으로 골라 인라인 주입(시안 My Shelf 무표지 카드). */
.book-cover-ph {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 18px;
    line-height: 1;
    user-select: none;
}
.book-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 220px; }
.book-title { font-weight: 500; color: var(--text); word-break: keep-all; overflow-wrap: anywhere; }
a.book-title { text-decoration: none; }
a.book-title:hover { text-decoration: underline; }
/* 책 상세 헤더 — 표지 + 메타 가로 배치 */
.book-detail-head { display: flex; gap: 18px; align-items: flex-start; }
/* 표지 — 테·링·그림자 0, 모서리 2(에디토리얼). 옛 연필테용 안쪽 여백 4px·content-box 클립은 테와 함께 걷었다. */
.book-detail-head .book-cover { width: 84px; height: 120px; border-radius: 2px; }
.book-detail-head .book-meta { gap: 10px; }
.book-sub { font-size: .9rem; color: var(--muted); margin: 0; }
.book-detail-head .book-meta > p:not(.affiliate-note) { margin: 0; }

/* === 책 상세 리스킨 (body.bookdetail-page 스코프 — 다른 페이지 무영향) ===
   아래 대상 클래스 다수는 책장(BooksApp.vue)·독서 기록(MonthlyRecords.vue) 등과 공유되지만,
   body.bookdetail-page 접두로 스코프해 이 페이지에서만 오버라이드한다(전역 규칙 자체는 무손상). */
body.bookdetail-page .card { border-radius: 0; }

/* 표지 플레이스홀더(무표지 책) — 단일 상세라 천 표지 해시 대신 고정 옅은 면 + 잉크 글자. */
body.bookdetail-page .bd-cover-ph {
    display: flex; align-items: center; justify-content: center;
    background: var(--sage-soft); color: var(--text);
    font-family: var(--font-serif); font-weight: 500; font-size: 40px;
}

/* 책 제목 — 전역 .card h2(uppercase 라벨체) 대신 시안 크기로 격상. 카드 섹션 제목도 같은 세리프로 통일. */
body.bookdetail-page .bd-title {
    font-family: var(--font-serif); font-weight: 500; font-size: 1.35rem;
    line-height: 1.3; color: var(--text); text-transform: none; letter-spacing: normal; margin: 0;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
body.bookdetail-page .bd-section-title {
    font-family: var(--font-serif); font-weight: 500; font-size: 16px; color: var(--text);
}

/* 상태 배지(상태별 색) + 공개 범위 칩(읽기 전용 표시) */
body.bookdetail-page .bd-status-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
body.bookdetail-page .book-status-badge {
    align-self: auto; margin-top: 0; font-size: 13px; padding: 4px 11px; border: 1px solid transparent;
}
/* 상태 배지 3톤(미니앱 피드 배지와 같은 역할) — 다 읽음 = 잉크 채움 · 읽는 중 = 가는 선 · 읽고 싶어요 = 옅은 면. */
body.bookdetail-page .bd-status-reading { background: transparent; color: var(--muted); border-color: var(--border); }
body.bookdetail-page .bd-status-finished { background: var(--accent-fill); color: var(--on-accent); border-color: var(--accent-fill); }
body.bookdetail-page .bd-status-want { background: var(--sage-soft); color: var(--ink-2); border-color: var(--sage-soft); }
body.bookdetail-page .bd-visibility-chip {
    display: inline-flex; align-items: center; gap: 4px; font-size: 13px; color: var(--muted);
    border: 1px solid var(--border);
    border-radius: 999px; padding: 3px 9px; background: transparent;
}
body.bookdetail-page .bd-visibility-chip svg { flex: 0 0 auto; width: 12px; height: 12px; }

/* 누적 시간 — 라벨은 흐리게, 수치만 명조·잉크로 강조 */
body.bookdetail-page .bd-accum { font-size: 13.5px; color: var(--muted); }
body.bookdetail-page .bd-accum-value { font-family: var(--font-serif); font-weight: 500; font-size: 17px; color: var(--accent-hover); }

/* 구매 버튼 — 전역 .btn-ghost 대신 잉크 테 알약. 드롭다운은 세로 목록 + 종이톤 카드로. */
body.bookdetail-page .bd-buy-toggle,
body.bookdetail-page .bd-buy-single {
    display: inline-flex; align-items: center; gap: 6px; border-radius: 999px;
    border-color: var(--accent); color: var(--accent-hover); padding: 7px 14px; font-size: 13px;
}
body.bookdetail-page .bd-buy-toggle:hover,
body.bookdetail-page .bd-buy-single:hover { background: var(--sage-soft); }
/* 전역 ▾▴ 글리프(content) 무력화 — 이 페이지는 summary 안 SVG 셰브론으로 대체(마크업). 전역 .buy-menu는 무손상. */
body.bookdetail-page .buy-menu > summary::after { content: none; }
body.bookdetail-page .bd-buy-chevron { flex: 0 0 auto; }
body.bookdetail-page .bd-chevron-up { display: none; }
body.bookdetail-page .buy-menu[open] .bd-chevron-down { display: none; }
body.bookdetail-page .buy-menu[open] .bd-chevron-up { display: inline; }
body.bookdetail-page .buy-menu-items {
    flex-direction: column; gap: 2px; background: var(--card-bg); border-radius: 2px;
    min-width: 148px;
}
body.bookdetail-page .buy-menu-items a {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    border: none; border-radius: 2px; padding: 9px 12px; font-size: 13px; color: var(--text);
}
body.bookdetail-page .buy-menu-items a:hover { background: var(--sage-soft); color: var(--accent-hover); }
body.bookdetail-page .buy-menu-items a svg { color: var(--muted); flex: 0 0 auto; }
body.bookdetail-page .buy-menu-items a:hover svg { color: var(--accent-hover); }

/* 월 브라우저 — 원형 버튼(◀▶ 텍스트 글리프는 템플릿에서 SVG로 교체) + 명조 라벨 + 일자 행 톤 재배색.
   .record-date/.record-time/.month-nav-btn/.record-row/.record-scroll은 독서 기록(history)과 공유라
   반드시 body.bookdetail-page 스코프 아래에서만 건드린다(전역·history 화면 무손상). */
body.bookdetail-page .month-nav-btn { border-radius: 999px; }
body.bookdetail-page .month-nav-btn svg { flex: 0 0 auto; }
body.bookdetail-page .month-nav-label { font-family: var(--font-serif); font-weight: 500; font-size: 15px; }
body.bookdetail-page .record-row { padding: 10px 2px; border-bottom-color: var(--line-1-3); }
body.bookdetail-page .record-date { color: var(--muted); font-weight: 400; font-size: 13px; letter-spacing: .3px; }
body.bookdetail-page .record-time { color: var(--accent-hover); font-family: var(--font-serif); font-weight: 500; font-size: 14px; }
body.bookdetail-page .record-scroll { max-height: 296px; }

/* 빈 상태 — 모래시계 아이콘 + 중앙 정렬(기존 문구 그대로, .status-line 색상 유지) */
body.bookdetail-page .bd-empty { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 28px 16px; text-align: center; color: var(--accent); }
body.bookdetail-page .bd-empty .status-line { margin: 0; line-height: 1.6; font-size: 13.5px; }

.book-author, .book-pub { font-size: .85rem; color: var(--muted); }
/* 검색 결과 byline — 저자 · 출판사 한 줄(byline() 조립). 시안 My Shelf. */
.book-byline { font-size: .85rem; color: var(--muted); }
.book-status-badge {
    align-self: flex-start;
    margin-top: 2px;
    font-size: .75rem;
    color: var(--ink-2);
    background: var(--sage-soft);    /* 상태가 아닌 배지(FollowAction 「나」)의 기본 — 상태 배지는 인라인 3톤이 덮는다 */
    border: 1px solid transparent;   /* 톤마다 크기가 안 흔들리게 — 읽는 중만 이 자리에 가는 선이 선다 */
    padding: 1px 8px;
    border-radius: 2px;
}
.book-add-form, .book-actions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.book-actions { margin-left: auto; }   /* 같은 줄이면 우측 정렬, 줄바꿈되면 다음 줄 전체 사용 */
/* 리스트 행 버튼은 작게 통일 — btn-primary(팔로우)도 포함해 btn-ghost(언팔로우)와 같은 크기로
   (베이스 button은 padding 12px 18px라 팔로우만 부담스럽게 컸음). */
.book-actions .btn-primary, .book-actions .btn-ghost, .book-actions .btn-danger { padding: 6px 10px; font-size: .85rem; }
.book-actions a.btn-ghost { text-decoration: none; display: inline-flex; align-items: center; }
/* 친구 추천 "추천 이유" 칩 — 공통 친구·같은 책·맞팔 근거(=.book-status-badge와 같은 pill 레시피). */
.reason-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
.reason-chip {
    font-size: 13px;
    line-height: 1.3;
    color: var(--accent);
    background: var(--info-soft-2);
    padding: 2px 8px;
    border-radius: 999px;
    white-space: nowrap;
}
/* SSR→Vue 전환으로 행 액션이 <form> 래퍼를 잃어, 직계 <button>(.vis-toggle·.btn-danger)이
   전역 button{width:100%}를 그대로 받아 풀폭으로 터지며 flex-wrap에서 한 줄씩 세로로 쌓였다(회귀).
   행 버튼은 내용폭으로 되돌린다 — 248·761·1213행과 같은 상쇄 패턴. */
.book-actions > button { width: auto; }

/* 구매처 선택 토글 — '구매'를 누르면 알라딘·쿠팡이 아래로 펼쳐지는 순수 CSS <details>(JS 불필요, manual-add 패턴과 동일).
   구매처가 2개일 때만 이 토글이 뜨고, 1개뿐이면 단일 .btn-ghost 버튼이 대신 렌더된다(템플릿 분기). */
.buy-menu { display: inline-block; position: relative; }   /* 펼친 메뉴를 절대배치로 띄울 기준점 */
.buy-menu > summary {
    list-style: none; cursor: pointer;
    padding: 6px 10px; font-size: .85rem;       /* 다른 행 버튼과 같은 크기로 통일 */
    display: inline-flex; align-items: center;
}
.buy-menu > summary::-webkit-details-marker { display: none; }   /* WebKit 기본 삼각형 마커 제거 */
.buy-menu > summary::after { content: " ▾"; font-size: 13px; margin-left: 2px; }  /* 펼칠 수 있음 표시 */
.buy-menu[open] > summary::after { content: " ▴"; }
/* 펼친 알라딘·쿠팡 목록 — 흐름에서 빼내 '구매' 버튼 바로 아래에 절대배치로 띄운다.
   흐름에 두면 .buy-menu 박스가 세로로 커져 형제 버튼(삭제 등) 정렬이 흔들렸음 → 띄워서 레이아웃 고정. */
.buy-menu-items {
    display: flex; flex-direction: row; gap: 4px;
    position: absolute; top: 100%; left: 0; z-index: 10;
    margin-top: 4px; padding: 6px;
    background: var(--card-bg); border: 1px solid var(--text);
    border-radius: 2px;
    min-width: max-content;
}
.buy-menu-items a {
    text-decoration: none; color: var(--muted); font-size: .85rem;
    padding: 6px 10px; border: 0; border-bottom: 1px solid var(--border);
    border-radius: 0; background: transparent;
}
.buy-menu-items a:hover { background: var(--bg); }
/* 행(.book-actions) 안에서는 구매 버튼이 우측 끝(margin-left:auto)이라, 메뉴를 버튼 우측 기준
   왼쪽(안쪽)으로 펼쳐 스크롤 박스 우측 경계를 넘지 않게 한다(가로 잘림·가로 스크롤 방지).
   book-detail의 <p> 직속 buy-menu는 좌측이라 기본 left:0 유지(거긴 안 잘림). */
.book-actions .buy-menu-items { left: auto; right: 0; }

/* 검색결과 '추가' 폼 — 상태 셀렉트+버튼을 행 우측 끝에 모으고, 버튼은 콤팩트하게.
   (전용 규칙이 없으면 베이스 button{width:100%; padding:12px 18px}을 그대로 받아
    버튼이 전체폭으로 셀렉트 아래 좌측에 떨어진다 — 위 .book-actions와 같은 톤으로 통일.) */
.book-add-form { margin-left: auto; }
.book-add-form .btn-primary, .book-add-form .btn-ghost { width: auto; padding: 6px 14px; font-size: .85rem; }

/* 공개/비공개 토글 칩 — ON=🌍 공개(잉크 테 + 500), OFF=🔒 비공개(가는 선). 클릭 시 반대값 POST(낙관적+롤백).
   books 전용(프로필 책방은 읽기전용이라 미사용). 시안 My Shelf — 트랙/노브 스위치를 칩으로 단순화. */
.vis-chip {
    width: auto;                                   /* 전역 button{width:100%} 상쇄(#286 가드) */
    border: 1px solid var(--border);
    background: transparent; color: var(--text);
    border-radius: 999px; padding: 5px 11px; font-size: .8rem; font-weight: 400;
    line-height: 1; cursor: pointer; white-space: nowrap;
}
.vis-chip:hover { border-color: var(--accent); }
.vis-chip.is-public { border-color: var(--text); font-weight: 500; }

/* 내 책장 상단 안내 — 공개 토글이 '책방'에 반영됨을 한 줄로 설명(책방 링크 겸). */
/* ===== 내 책장 리디자인 PR-3 — 헤더·안내·필터·상태·와이드 셸 (시안 My Shelf) ===== */

/* 인사말 헤더 — 제목·통계만. 페이지 이동은 양옆 세로 바(fragments/side-rails)가 담당. */
.shelf-greeting { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; }

/* '책 목록' 카드 헤드 — 제목(좌) + 제휴 고지 ⓘ(우). 책방 .shop-shelf-head 대응(카드 안 우상단).
   .card h2의 margin-bottom(12px)을 헤드 행으로 옮겨 제목·ⓘ를 한 줄에 정렬. */
.shelf-mine-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 12px; }
.shelf-mine-head { padding-bottom: 8px; border-bottom: 1px solid var(--text); }
.shelf-mine-head h2 { margin: 0; padding-bottom: 0; border-bottom: 0; }   /* 머리 줄이 섹션 머리 선을 진다 */

/* 공개 안내 — 옅은 면 박스 + 잉크 글자(책방 링크 겸). books 전용. */
.shelf-public-hint {
    display: flex; gap: 8px; align-items: flex-start;
    background: var(--sage-soft); color: var(--accent-hover);
    border-radius: var(--radius-sm); padding: 11px 13px;
    font-size: .8rem; margin: 0 0 16px;
}
.shelf-public-hint-text { flex: 1 1 auto; min-width: 0; }
.shelf-public-hint strong { font-weight: 500; }
.shelf-public-hint a { color: var(--accent-hover); font-weight: 500; }

/* 빈 책장 — 점선 박스 + 🌱(시안). 필터 결과 0은 기존 .status-line 유지(다른 메시지). */
.shelf-empty {
    margin-top: 4px; text-align: center; padding: 26px 12px;
    border: 1px dashed var(--line-2-2); border-radius: 2px; background: var(--paper-1-2);
}
.shelf-empty p { margin: 12px 0 0; font-size: .9rem; color: var(--muted); }

/* 로드 실패 — 시안 에러 박스(⚠️ + 다시 시도). */
.shelf-load-error {
    display: flex; gap: 10px; align-items: center;
    background: var(--danger-soft-3); border: 1px solid var(--danger-line-3); color: var(--danger-ink-deep-2);
    border-radius: var(--radius-sm); padding: 12px 14px; font-size: .9rem; margin: 8px 0;
}
.shelf-load-error .link-btn {
    width: auto; border: none; background: none; padding: 0; font: inherit;
    color: var(--danger-ink-deep-2); font-weight: 500; text-decoration: underline; cursor: pointer;
}

/* 로딩 스켈레톤 — 표지 + 텍스트 바(시안). */
.shelf-skeleton { display: flex; flex-direction: column; gap: 14px; padding: 4px 0; }
.skeleton-row { display: flex; gap: 13px; }
.skeleton-cover { width: 54px; height: 78px; border-radius: 2px; background: var(--line-1-4); flex: none; }
.skeleton-lines { flex: 1; display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.skeleton-line { height: 12px; border-radius: 2px; background: var(--line-1-4); }
.skeleton-line.w70 { width: 70%; }
.skeleton-line.w40 { width: 40%; }
.skeleton-line.w55 { width: 55%; background: var(--paper-4-2); }

/* ── 와이드: 2열 리스트 + 340px 사이드바(확정안). CSS @media 단일 출처 — JS 분기 안 씀(N-124 회피). ──
   경계 1100 = 바 여백 248을 뺀 852가 340+2열의 최소 폭 — 「본문 폭(바 있는 화면)」 절과 같은 수. */
@media (min-width: 1100px) {
    .shelf-layout {
        display: grid; grid-template-columns: 340px 1fr; gap: 24px; align-items: start;
        grid-template-areas: "greeting greeting" "add mine";
    }
    .shelf-layout > .alert { grid-column: 1 / -1; }   /* 에러는 전체 폭 */
    .shelf-greeting { grid-area: greeting; }
    .shelf-add { grid-area: add; }
    .shelf-mine { grid-area: mine; }
    .shelf-layout .card { margin-bottom: 0; }          /* grid gap이 간격 담당 */

    /* 책 목록을 2열 카드 그리드로 — .shelf-scroll의 60vh 내부 스크롤은 유지(grid와 overflow 공존).
       책방 공개 책장(.shop-shelf > .shop-books)과 같은 패턴이라 책이 많아도 페이지가 길어지지 않고
       하단 네비가 늘 바로 아래 보인다. (예전엔 max-height:none; overflow:visible로 해제했었음.) */
    #books-app .shelf-list {
        display: grid; grid-template-columns: 1fr 1fr; gap: 14px;
    }
    #books-app .shelf-list .book-row {
        border: 0; border-bottom: 1px solid var(--border);
        border-radius: 0; background: transparent;
        padding: 14px 0; align-items: flex-start;
    }
    #books-app .shelf-list .book-row:last-child { border-bottom: 1px solid var(--border); }
}

.affiliate-note { font-size: 13px; color: var(--muted); text-align: left; line-height: 1.5; margin: 6px 0 0; }   /* 법정 고지 — 불투명도로 흐리지 않는다(종이 위 5.65) */
.affiliate-note + .affiliate-note { margin-top: 3px; }

/* 제휴 고지 ⓘ 팝오버 — 책장 인사말·책방 헤드 우상단 공용. 책BTI ?(.pbti-help-*) 시각 복제이되
   앵커가 ⓘ 버튼 래퍼(페이지 헤더 무관)라 말풍선 꼬리가 버튼에 정확히 맞는다. 책BTI는 무손상. */
.affiliate-pop-wrap { position: relative; flex: 0 0 auto; align-self: flex-start; display: inline-flex; }
.affiliate-pop-wrap.is-open { z-index: 60; }   /* 열림 시 ⓘ를 백드롭(z50) 위로 — 실 브라우저 클릭 보장 */
.affiliate-pop-btn {
    flex: 0 0 auto; width: 26px; height: 26px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--sage-soft); color: var(--accent-hover);
    border: none; border-radius: 999px; cursor: pointer;
    transition: background .15s ease;
}
.affiliate-pop-btn:hover { background: var(--sage-hover); }
.affiliate-pop-btn svg { width: 16px; height: 16px; }
/* 투명 풀스크린 백드롭 — 팝오버 밖 클릭 시 닫기 */
.affiliate-pop-backdrop { position: fixed; inset: 0; z-index: 50; background: transparent; }
/* 안내 말풍선 — ⓘ 버튼 우측 아래로 펼침(제휴 고지 2줄) */
.affiliate-pop {
    position: absolute; top: calc(100% + 9px); right: 0; z-index: 61;
    width: min(300px, calc(100vw - 56px));
    background: var(--card-bg);
    border: 1px solid var(--text);
    border-radius: 2px; padding: 14px;
    display: flex; flex-direction: column; gap: 10px; text-align: left;
}
.affiliate-pop::before {   /* ⓘ 버튼을 가리키는 말풍선 꼭지 */
    content: ''; position: absolute; top: -6px; right: 8px;
    width: 11px; height: 11px; background: var(--card-bg);
    border-left: 1px solid var(--text); border-top: 1px solid var(--text);
    transform: rotate(45deg);
}
.affiliate-pop-item { margin: 0; font-size: 13px; line-height: 1.6; color: var(--muted); word-break: keep-all; }

/* 프로필 헤더 카드 — 책방명·@핸들·팔로우 카운트를 한 박스로 묶는다(페이지 카드 스택과 통일).
   카드 패딩(24px)이 바깥 여백을 담당하므로 내부 요소의 큰 마진은 제거하고 간격만 다시 잡는다. */
.profile-card .greeting { margin: 0; }
.profile-card > .muted { margin: 2px 0 0; }
.profile-card .profile-follow { margin: 14px 0 0; }

/* 프로필 — 팔로우 카운트 + 버튼 (관계는 카운트만 노출, SNS §7.3) */
.profile-follow { display: flex; align-items: center; gap: 16px; margin: 0 0 16px; flex-wrap: wrap; }
.profile-follow .follow-count { font-size: .9rem; color: var(--muted); text-decoration: none; }
.profile-follow .follow-count strong { color: var(--text); }
/* 본인 프로필에서 카운트는 목록 링크 — 클릭 가능함을 hover로 알린다 */
.profile-follow a.follow-count:hover { color: var(--accent); }
.profile-follow a.follow-count:hover strong { color: var(--accent); }
.profile-follow .follow-action { margin-left: auto; }
.profile-follow .profile-actions { display: flex; gap: 8px; }
/* SSR→Vue 전환으로 팔로우·차단이 <form> 래퍼를 잃어, 전역 button{width:100%}를 직접 받아
   풀폭으로 터졌다(.book-actions와 같은 회귀). 내용폭으로 되돌린다. */
.profile-follow .profile-actions button { width: auto; }
/* 차단 버튼 — 옅은 위험 톤(삭제만큼 강하지 않게) */
.btn-block { color: var(--danger); border-color: var(--danger); }

/* ─────────────────────────────────────────────────────────────────────────
   책방(/u/{loginId}) — 대시보드 스킨 이식. .dash-* 재사용 + 고유는 .shop-*.
   공유 .book- 과 .record- 계열은 절대 수정하지 않고 .shop- 로 분리(타 페이지 회귀 0).
   값은 계획 §10 스펙 그대로. 컨테이너·패딩 등 §10 미지정분만 시안에 맞춰 보완.
   ───────────────────────────────────────────────────────────────────────── */

/* 내 책방(self) 상단 사용자 검색 진입점 — 검색 input처럼 보이되 실제론 /search 링크(트위터식).
   책방엔 슬림 진입점만, 무거운 검색 패널/추천은 전용 페이지로 위임(책방 비대화 방지).
   톤: .book-search-form input(테두리·라운드) + 연베이지 채움·--nav-hover-* 토큰(옛 홈 빠른 이동 타일의 톤) 혼합. */
.shop-search-entry {
    display: flex; align-items: center; gap: 10px;
    padding: 11px 16px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: transparent; color: var(--text);
    text-decoration: none; font-size: .95rem;
    transition: background .2s ease, border-color .2s ease;
}
.shop-search-entry:hover { background: var(--nav-hover-bg); border-color: var(--nav-hover-border); }
.shop-search-entry svg { flex: 0 0 auto; color: var(--accent-hover); }

.shop-wide { display: flex; gap: 28px; align-items: flex-start; }
.shop-side { flex: 0 0 360px; display: flex; flex-direction: column; gap: 18px; }
.shop-main { flex: 1; min-width: 0; }

/* 헤더 정체성 — 이니셜 아바타(대시보드 .dash-header-avatar 재사용) + 책방명/핸들 */
.shop-header-card { position: relative; }   /* 케밥 메뉴 absolute 기준 */
.shop-id-head { display: flex; align-items: center; gap: 14px; }
.shop-avatar { cursor: default; }                     /* 비클릭 div라 .dash-header-avatar의 pointer 상쇄 */
.shop-id-text { min-width: 0; }                       /* flex 자식 ellipsis 함정 방지 */
.shop-id-title { font-family: var(--font-serif); font-weight: 500; font-size: 18px; color: var(--text); line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shop-id-handle { font-size: 13px; color: var(--muted); margin-top: 2px; }

/* BTI 태그칩 — 클릭형 vs 정적형 */
.shop-tags { display: flex; flex-wrap: wrap; gap: 7px; }
.shop-tag { font-size: 13px; padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border);
    color: var(--text); background: transparent; }
.shop-tag-click { border-color: var(--nav-hover-border-2); color: var(--accent-hover); background: var(--sage-soft); cursor: pointer; width: auto; }
.shop-tag-click:hover { background: var(--sage-hover-2); }

/* 카운트 + 액션 */
.shop-counts { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.shop-count { font-size: 13.5px; color: var(--muted); text-decoration: none; }
a.shop-count { text-decoration: underline; text-underline-offset: 3px; }   /* 누를 수 있는 수(팔로워 목록) — 맨 글자라 밑줄이 신호(U-15) */
.shop-count strong { font-family: var(--font-serif); font-weight: 500; color: var(--text); font-variant-numeric: tabular-nums; }
a.shop-count:hover, a.shop-count:hover strong { color: var(--accent); }
.shop-actions { margin-left: auto; display: flex; gap: 8px; }
.shop-actions .dash-btn-fill, .shop-actions .dash-btn-outline { width: auto; padding: 9px 16px; border-radius: 999px; font-size: 14px; display: inline-flex; align-items: center; gap: 6px; box-sizing: border-box; }

/* 케밥 더보기 메뉴 (헤더 우상단 절대 배치) */
.shop-menu { position: absolute; top: 12px; right: 14px; }
.shop-menu-btn {
    background: none; border: none; cursor: pointer; padding: 4px; border-radius: 2px;
    display: inline-flex; align-items: center; color: var(--muted); width: auto;
}
.shop-menu-btn:hover { background: var(--sage-soft); color: var(--text); }
.shop-menu-backdrop { position: fixed; inset: 0; z-index: 100; }
.shop-menu-list {
    position: absolute; top: calc(100% + 4px); right: 0; z-index: 101;
    background: var(--card-bg); border: 1px solid var(--text);
    border-radius: 2px;
    min-width: 110px; padding: 6px;
    display: flex; flex-direction: column; gap: 2px;
}
.shop-menu-item {
    background: none; border: none; cursor: pointer; width: 100%;
    display: inline-flex; align-items: center; gap: 8px;
    padding: 9px 12px; border-radius: 2px; font-size: 14px; color: var(--text); text-align: left;
}
.shop-menu-item:hover { background: var(--sage-soft); }
.shop-menu-item-danger { color: var(--danger); }
.shop-menu-item-danger:hover { background: var(--danger-soft-4); }

/* 신고 모달 */
.shop-report-modal-overlay {
    position: fixed; inset: 0; z-index: 200;
    background: var(--scrim-2);
    display: flex; align-items: center; justify-content: center; padding: 16px;
}
.shop-report-modal-panel {
    background: var(--card-bg); border: 1px solid var(--text); border-radius: 2px; padding: 24px;
    width: 100%; max-width: 360px;
    display: flex; flex-direction: column; gap: 16px;
}
.shop-report-modal-head { display: flex; align-items: center; justify-content: space-between; }
.shop-report-modal-title { font-size: 16px; font-weight: 500; color: var(--text); margin: 0; }
.shop-report-modal-close {
    background: none; border: none; cursor: pointer; padding: 4px; border-radius: 2px;
    display: inline-flex; color: var(--muted); width: auto;
}
.shop-report-modal-close:hover { color: var(--text); background: var(--sage-soft); }
.shop-report-modal-body { display: flex; flex-direction: column; gap: 10px; }
.shop-report-modal-submit { width: auto; align-self: flex-start; }
.shop-report-modal-ok { margin: 0; font-size: 13px; color: var(--ok); }

/* 통합 책 시트(발견 1, §6.5) — 측정 전 책 고르기('start') + 종료 후 태깅('tag')을 한 시트가 겸한다.
   모달 토큰(card-bg·border·sage-soft·muted·accent·ok) 재사용 + 설계 §6.5/§8 지정 시트색(배경 #F6F2E9·
   백드롭 rgba(34,32,26,.34), 지정 예외)만 새로 쓴다. 모바일=하단 시트, 데스크톱=하단 정렬 카드. */
.book-sheet-overlay {
    position: fixed; inset: 0; z-index: 200;
    background: var(--scrim-soft);              /* 설계 §8 지정 백드롭(따뜻한 ink 톤) */
    display: flex; align-items: flex-end; justify-content: center;
}
.book-sheet-panel {
    background: var(--card-bg); border: 1px solid var(--text);   /* 떠 있는 것 = 종이 + 잉크 1px(그림자 0) */
    border-radius: 0;
    padding: 12px 20px calc(20px + env(safe-area-inset-bottom, 0px));
    width: 100%; max-width: 460px;
    display: flex; flex-direction: column; gap: 12px;
    max-height: 85vh; overflow-y: auto;
    animation: book-sheet-up .28s cubic-bezier(.32, .72, 0, 1);
}
.sheet-handle {
    width: 36px; height: 4px; border-radius: 999px; background: var(--border);
    margin: 0 auto 2px; flex-shrink: 0;
}
.book-sheet-head { display: flex; align-items: center; justify-content: space-between; }
.book-sheet-title { font-size: 16px; font-weight: 500; color: var(--text); margin: 0; }
.book-sheet-close {
    background: none; border: none; cursor: pointer; padding: 4px 8px; border-radius: 2px;
    font-size: 16px; line-height: 1; color: var(--muted); width: auto;
}
.book-sheet-close:hover { color: var(--text); background: var(--sage-soft); }
.book-sheet-hint { margin: 0; font-size: 13px; color: var(--muted); }
/* 시트 안 오류(R2 P7) — 페이지 상단 .alert는 딤 뒤에 가려져 시트가 열린 동안 안 보인다. 힌트 바로 밑,
   목록보다 먼저 서서 「왜 안 됐는지」가 누른 자리 가까이 있다. 톤은 책장 로드 오류와 같은 조용한 테라코타. */
.book-sheet-error {
    margin: 0; padding: 10px 12px; border-radius: var(--radius-sm);
    background: var(--danger-soft); border: 1px solid var(--danger-line);
    color: var(--danger-ink-deep); font-size: 13px; line-height: 1.5; word-break: keep-all;
}

/* 검색해서 담기 — 시트 안에서 카탈로그를 찾아 바로 책장에 담는다(책장 검색 재사용). */
.book-sheet-search { display: flex; gap: 8px; align-items: stretch; }
.book-sheet-search input {
    flex: 1 1 auto; min-width: 0; box-sizing: border-box;
    padding: 10px 14px; border: 1px solid var(--muted);
    border-radius: 2px;
    background: transparent; color: var(--text); font-size: 14px;
}
.book-sheet-search-btn {
    width: auto; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
    padding: 0 14px; border: 1px solid var(--text); border-radius: 999px; background: transparent; color: var(--text); cursor: pointer;
}
.book-sheet-search-btn svg { width: 18px; height: 18px; }
.book-sheet-search-btn:hover { background: var(--sage-hover); }

/* 상태 필터칩(전체/읽는중/완독/읽고싶음) — pill, 좁으면 줄바꿈. */
.book-sheet-filters { display: flex; flex-wrap: wrap; gap: 6px; }
.book-sheet-chip {
    width: auto; padding: 6px 12px; border: 1px solid var(--border);
    border-radius: 999px;
    background: transparent; color: var(--text); font-size: 13px; font-weight: 400; cursor: pointer;
}
.book-sheet-chip:hover:not(.active) { background: var(--sage-hover); }
.book-sheet-chip.active { border-color: var(--text); font-weight: 500; }

/* 책 목록 · 검색결과 — 표지 34×48 + 제목/저자 + 상태 배지. */
.book-sheet-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.book-sheet-results { max-height: 220px; overflow-y: auto; }
.book-sheet-book, .book-sheet-result {
    width: 100%; display: flex; align-items: center; gap: 12px; text-align: left;
    min-height: 44px; padding: 8px 10px; border-radius: 0;
    background: transparent; border: 0; border-bottom: 1px solid var(--border);
    color: var(--text);
}
.book-sheet-book { cursor: pointer; }
.book-sheet-book:hover { background: var(--sage-hover); }
.book-sheet-book:disabled { opacity: .5; cursor: default; }
.book-sheet-cover {
    width: 34px; height: 48px; border-radius: 2px; flex-shrink: 0; object-fit: cover;
    background: var(--border); display: flex; align-items: center; justify-content: center;
    font-family: var(--font-serif); font-weight: 500; font-size: 15px; line-height: 1; user-select: none;
}
.book-sheet-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.book-sheet-book-title { font-weight: 500; color: var(--text); font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.book-sheet-byline { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.book-sheet-badge { flex-shrink: 0; font-size: 13px; font-weight: 500; padding: 3px 8px; border: 1px solid transparent; border-radius: 2px; }
/* .book-sheet-owned 의 모양은 책장 배지와 한 규칙으로 묶여 있다 — 「이미 책장에 있음」 배지 절 참고. */
.book-sheet-add-btn {
    width: auto; flex-shrink: 0; padding: 8px 14px; border: 1px solid var(--text); border-radius: 999px;
    background: transparent; color: var(--text); font-size: 13px; font-weight: 500; cursor: pointer;
}
.book-sheet-add-btn:hover { background: var(--sage-hover); }
.book-sheet-add-btn:disabled { opacity: .5; cursor: default; }
.book-sheet-empty { margin: 0; font-size: 13px; color: var(--muted); text-align: center; padding: 8px 0; }

.book-sheet-cta {
    width: 100%; min-height: 44px; margin-top: 2px;
    background: none; border: none; cursor: pointer;
    color: var(--muted); font-size: 13px; text-decoration: underline;
}
.book-sheet-cta:hover { color: var(--text); }
.book-sheet-cta:disabled { opacity: .5; cursor: default; }
@media (prefers-reduced-motion: reduce) {
    .book-sheet-panel { animation: none; }
}

/* 신고 박스 — 콤팩트 카드(시안: 박스 4px + summary 자체 패딩) */
.shop-report { background: var(--card-bg); border: 0; border-radius: 0; padding: 4px 0; }
.shop-report > summary { cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 7px; font-size: 13px; color: var(--muted); padding: 12px 14px; }
.shop-report > summary::-webkit-details-marker { display: none; }
.shop-report > summary:hover { color: var(--danger); }
.shop-report[open] > summary { margin-bottom: 0; }
.shop-report-caret { transition: transform .15s ease; }            /* §6 chevron — 펼침 시 90° 회전 */
.shop-report[open] > summary .shop-report-caret { transform: rotate(90deg); }
.shop-report-field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); }
.shop-report-field select {
    width: 100%; box-sizing: border-box; font: inherit; font-size: 13px; color: var(--text);
    background: transparent; border: 1px solid var(--muted);
    border-radius: var(--radius-sm); padding: 9px 11px;
}
.shop-report-submit { width: auto; align-self: flex-start; }       /* 전역 button{width:100%} 상쇄 */
.shop-report-ok { margin: 0; font-size: 13px; color: var(--ok); }

/* 탭 (모바일 전용) */
.shop-tab-card { gap: 0; }                             /* dash-card flex gap 상쇄 — 탭 margin-bottom만 간격 */
.shop-tabs { display: flex; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
.shop-tab { flex: 1; text-align: center; padding: 11px 0; font-size: 14.5px; color: var(--muted); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; background: none; width: auto; border-radius: 0; }
.shop-tab.active { color: var(--accent-hover); border-bottom-color: var(--accent); font-weight: 500; }

/* 책BTI */
.shop-bti { display: flex; flex-direction: column; gap: 12px; }
.shop-bti-text { font-family: var(--font-serif); font-size: 15.5px; line-height: 1.75; color: var(--text); margin: 0; }
.shop-bti-note { font-size: 13px; color: var(--muted); margin: 0; }
.shop-bti-cold { font-size: 13.5px; color: var(--muted); border: 1px dashed var(--border); border-radius: 2px; padding: 16px; line-height: 1.6; margin: 0; }

/* 드릴다운 */
.shop-drill { background: var(--card-bg); border: 0;
    border-radius: 0; padding: 14px 0; }
.shop-drill-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.shop-drill-head h3 { font-family: var(--font-serif); font-weight: 500; font-size: 15px; color: var(--text); margin: 0; }
.shop-drill-close { width: auto; flex: none; background: transparent; border: none; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; font-family: inherit; font-size: 13px; color: var(--muted); padding: 2px; }
.shop-drill-close:hover { color: var(--text); }
/* 드릴다운(근거책) 리스트 — 헤더 카드 안 보조 미리보기라 셸프(.shop-shelf>.shop-books 60vh)보다
   짧은 스크롤 박스(50vh). 헤드(제목·×닫기)는 이 ul 밖이라 스크롤 중 고정, 책 적으면 미도달=스크롤바 없음.
   (원래 .tag-books-scroll로 있던 50vh 레시피가 마크업 리네임으로 단절돼 무한정 길어지던 것 복원.) */
.shop-drill .shop-books {
    grid-template-columns: 1fr; gap: 8px;  /* 사이드바 폭이라 와이드에서도 1열 유지 */
    max-height: 50vh;
    overflow-y: auto;
    scrollbar-gutter: stable;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding-right: 6px;
}

/* 공개 책장 */
.shop-shelf { display: flex; flex-direction: column; gap: 14px; }
.shop-shelf-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding-bottom: 8px; border-bottom: 1px solid var(--text); }
.shop-shelf-title { font-family: var(--font-serif); font-weight: 500; font-size: 22px; line-height: 30px; color: var(--text); margin: 0; }
/* 헤드 우측 도구 묶음 — 필터칩 + 제휴 고지 ⓘ. head는 제목|도구 2분할 유지(space-between). */
.shop-shelf-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.shop-filter { display: flex; flex-wrap: wrap; gap: 7px; }
.shop-filter button { font-size: 13px; padding: 5px 13px; border-radius: 999px; border: 1px solid var(--border);
    color: var(--text); background: transparent; cursor: pointer; width: auto; font-weight: 400; }
.shop-filter button:hover { background: var(--sage-hover); }
.shop-filter button.active { border-color: var(--text); font-weight: 500; }
/* 완독 정렬 칩 행 — 완독 필터에서만 뜨는 둘째 행. 상태필터 칩(head 우측) 바로 아래 우측 정렬로 이어붙인다
   (.shop-shelf gap 14px를 -6px로 좁혀 필터칩과 한 묶음으로 읽히게). */
.shop-sort { justify-content: flex-end; margin-top: -6px; }

/* 책 그리드 — 모바일 1열, 와이드 2열 */
.shop-books { display: grid; grid-template-columns: 1fr; gap: 12px; list-style: none; padding: 0; margin: 0; }
.shop-wide .shop-books { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; }  /* 카드 최소 300px — 넓으면 2열, 중간폭(메인<614px)이면 1열 풀폭으로 우아하게 강등(repeat(auto-fit, minmax()) 관용구) */

/* 공개 책장 ul을 스크롤 박스로(PC·모바일 공통) — max-height에 닿으면 내부 스크롤이라 페이지가
   책 수만큼 길어지지 않고, 하단 네비(대시보드·내 책장)가 늘 바로 아래 보인다. 책 적으면
   미도달=스크롤바 없음(자연 폴백). 필터칩(.shop-shelf-head)·제휴고지는 이 ul 밖이라 고정.
   /books의 .shelf-scroll 전례와 같은 거터·관성·번짐방지 레시피(60vh는 뷰포트 적응).
   직계(>)라 BTI 드릴다운(.shop-drill > .shop-books.shop-drill-books)엔 영향 0. */
.shop-shelf > .shop-books {
    max-height: 60vh;
    overflow-y: auto;
    scrollbar-gutter: stable;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}
.shop-book { display: flex; gap: 12px; padding: 12px 0; border: 0;
    border-radius: 0; background: var(--card-bg); }

/* 책등 표지 — 무표지는 제목 천 색(인라인 coverStyle — 책장·홈과 같은 책은 같은 색) + 미색 이니셜 */
.shop-cover { flex: 0 0 auto; width: 54px; height: 78px; border-radius: 2px; display: flex; align-items: center; justify-content: center; object-fit: cover;
}
.shop-cover-ph { font-family: var(--font-serif); font-weight: 500; font-size: 22px; }

/* 책 메타 */
.shop-book-meta { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.shop-book-title { font-size: 14.5px; color: var(--text); font-weight: 500; line-height: 1.4; }
.shop-book-author { font-size: 13px; color: var(--muted); }
.shop-book-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 2px; }

/* 상태 배지 3톤 — 다 읽음 = 잉크 채움 · 읽는 중 = 가는 선 · 읽고 싶어요 = 옅은 면(미니앱 피드 배지와 같은 역할) */
.shop-badge { font-size: 13px; font-weight: 500; padding: 3px 10px; border: 1px solid transparent; border-radius: 2px; }
.shop-badge-finished { background: var(--accent-fill); color: var(--on-accent); }
.shop-badge-reading  { background: transparent; color: var(--muted); border-color: var(--border); }
.shop-badge-want     { background: var(--sage-soft); color: var(--ink-2); }

/* 독서시간 / 구매 / 제휴 */
.shop-time { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; color: var(--ok); font-weight: 500; }
.shop-buy-row { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 6px; }
.shop-buy { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; color: var(--accent-hover); text-decoration: none; }
.shop-buy:hover { text-decoration: underline; }
/* 구매 드롭다운 — 알라딘+쿠팡 둘 다일 때(구매처 추가 대비). summary=칩, items=팝업. */
.shop-buy-menu { display: inline-block; position: relative; }
.shop-buy-menu > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; width: auto; font-size: 13px; color: var(--text); border: 1px solid var(--text);
    border-radius: 999px; padding: 4px 10px; }
.shop-buy-menu > summary::-webkit-details-marker { display: none; }
.shop-buy-menu > summary:hover { background: var(--sage-hover); }
.shop-buy-caret { transition: transform .15s ease; }
.shop-buy-menu[open] > summary .shop-buy-caret { transform: rotate(90deg); }
.shop-buy-menu-items { position: absolute; z-index: 20; top: calc(100% + 4px); left: 0; min-width: 112px; background: var(--card-bg); border: 1px solid var(--text);
    border-radius: 2px; padding: 4px; display: flex; flex-direction: column; gap: 2px; }
.shop-buy-menu-items a { display: flex; align-items: center; gap: 6px; padding: 7px 10px; border-radius: 2px; font-size: 13px; color: var(--text); text-decoration: none; }
.shop-buy-menu-items a:hover { background: var(--bg); color: var(--accent-hover); }
/* (구) .shop-affiliate 하단 상시 고지문은 헤드 우상단 ⓘ 팝오버(.affiliate-pop)로 이전·폐지. */

/* 빈/콜드 상태 한 줄 */
.shop-empty { font-size: 13.5px; color: var(--muted); padding: 18px 0; text-align: center; margin: 0; }

/* 404 — 미존재·차단·운영자 통합 카드 */
.shop-notfound { align-items: center; text-align: center; gap: 14px; padding: 44px 24px; }
.shop-notfound .shop-ico { color: var(--accent); opacity: .5; }
.shop-notfound-msg { margin: 0; font-family: var(--font-serif); font-weight: 500; font-size: 19px; color: var(--text); }
.shop-notfound-link { display: inline-flex; align-items: center; gap: 6px; font-size: 13.5px; color: var(--accent-hover); text-decoration: none; font-weight: 500; }
.shop-notfound-link:hover { text-decoration: underline; }

/* 와이드에서 탭 숨김 / 모바일에서 사이드바 평탄화는 isWide 분기로 처리(이 CSS는 안전망) */
/* 팔로워/팔로잉 목록 페이지 탭 */
.follow-tabs { display: flex; gap: 8px; margin: 0 0 14px; }
.follow-tabs a {
    flex: 1; text-align: center; padding: 8px 0; border: 0;
    border-radius: 0; color: var(--muted); text-decoration: none; font-weight: 400; font-size: .9rem;
}
/* 탭 = 잉크 2px 밑줄(채움 없음) */
.follow-tabs a.active { color: var(--text); font-weight: 500; box-shadow: inset 0 -2px 0 var(--text); }

.book-time { font-size: .8rem; color: var(--ok); font-weight: 500; }
/* 내 책장 필터 — 상태/공개여부 토글(활성=잉크 2px 밑줄 탭). books 전용.
   (옛 주석은 "프로필 .shelf-filter와 별개"라 했는데 그 클래스는 죽어서 2026-09-12 삭제됐다 — 이름이
    접두로 겹쳐 문자열 검색에 같이 걸리니, 지울 때 이쪽을 건드리지 않도록 주의한다.)
   두 칩 그룹(상태·공개여부)을 같은 모양으로 통일 — 기존 세그먼티드 '서브 필터' 룩 대신 시안의 단일 칩. */
/* 필터 묶음 = 탭 줄(그릇 테 없음 — 칸 사이 가는 선만, 고른 칸은 잉크 2px 밑줄). */
.shelf-filter-chips { display: flex; width: fit-content; flex-wrap: nowrap; margin: 0 0 9px; }
.shelf-filter-chips + .shelf-filter-chips { margin-bottom: 18px; }
.filter-chip {
    width: auto;                                   /* 전역 button{width:100%} 상쇄(#286 가드) */
    border: 0; border-radius: 0;                   /* 전역 button의 잉크 테·999px 상쇄 — 탭 칸은 밑줄만 */
    background: transparent; color: var(--muted);
    padding: 6px 14px; font-size: .8rem; font-weight: 400;
    line-height: 1.2; cursor: pointer; white-space: nowrap;
}
.filter-chip + .filter-chip { border-left: 1px solid var(--border); }   /* 셀 사이 구분선 */
.filter-chip:hover:not(.active) { background: var(--sage-hover); color: var(--text); }
.filter-chip.active { color: var(--text); font-weight: 500; box-shadow: inset 0 -2px 0 var(--text); }
/* 팔로우 스코프 인기 카운트(§7.4) — 책 메타 안 작은 배지 */
.follow-popularity { font-size: .78rem; color: var(--accent); font-weight: 500; text-decoration: none; cursor: pointer; }
.follow-popularity:hover { text-decoration: underline; }

/* 검색 결과 중 이미 내 책장에 있는 책 표시(중복 추가 방지). followPopularity와 같은 메타 줄의 인포 배지지만,
   사회적 신호(accent)와 구분되게 소유 상태는 중립(muted) 톤. */
/*
 * 「이미 책장에 있음」 배지 — 책장 검색 결과(.shelf-owned-badge)와 대시보드 책 시트(.book-sheet-owned)가
 * 한 규칙을 공유한다. 둘은 같은 검색 API의 같은 `owned` 플래그를 그리므로, 표기가 갈리면 같은 사실이
 * 두 얼굴로 보인다. 미니앱의 「서재에 있어요」 칩과 같은 언어이되 **문구는 「책장」이다** — 웹에서
 * 웹은 책 목록을 「책장」으로 부른다(용어 단일 출처).
 *
 * 흐린 회색 글자였던 것을 옅은 면 칩으로 올렸다. 저자·출판사 줄과 같은 옷이라 한 줄 더 붙은 메타로
 * 읽혔는데, 이건 메타가 아니라 「담을 수 없다」는 상태 신호다.
 */
.shelf-owned-badge,
.book-sheet-owned {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  flex-shrink: 0;
  padding: .05rem .45rem .1rem;
  border: 1px solid transparent;
  border-radius: 2px;
  background: var(--sage-soft);   /* 상태가 아닌 배지 = 옅은 면 + 보조 글자 */
  font-size: .78rem;
  font-weight: 500;
  color: var(--ink-2);
}

/*
 * ⚠️ 책장 쪽 배지는 `.book-meta`(세로 flex)의 자식이라 기본 `align-items: stretch`가 **가로로 늘린다** —
 * 흐린 글자였을 땐 안 보이던 것이 채움·테두리가 생기자 행 전체를 가로지르는 띠로 드러났다.
 * 시트 쪽은 부모가 가로 flex(`align-items: center`)라 해당 없다.
 */
.shelf-owned-badge { align-self: flex-start; }

/*
 * 체크 표식 — 기본 이모지를 쓰지 않기로 해서(2026-08-18) 선 하나로 그린다. 마크업이 아니라 여기서
 * 그리는 이유는 두 자리가 자동으로 같아지기 때문이다. mask라 색은 글자색을 그대로 따라간다.
 */
.shelf-owned-badge::before,
.book-sheet-owned::before {
  content: '';
  width: .7em;
  height: .7em;
  flex-shrink: 0;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.6 9 10 3' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.4 4.6 9 10 3' fill='none' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* 인기 카운트 drill-down — "이 책 읽는 내 팔로우" 버킷 제목 */
.reader-bucket { font-size: .85rem; color: var(--muted); margin: 1rem 0 .4rem; text-align: left; }

/* 개인정보처리방침 등 고지 문서 — 읽기용 본문(카드 기본 h2의 작은 라벨 스타일을 본문 제목으로 되돌림) */
.legal { text-align: left; line-height: 1.6; }
.legal h2 {
    font-size: .95rem;
    text-transform: none;
    letter-spacing: normal;
    color: var(--text, inherit);
    margin: 20px 0 8px;
}
.legal h2:first-of-type { margin-top: 8px; }
.legal ul { margin: 0 0 8px; padding-left: 20px; }
.legal li { margin-bottom: 4px; }
.legal-date { font-size: .8rem; color: var(--muted); margin-top: 20px; }

/* 위탁 현황 표(처리방침 8절). 셀 안에서 줄바꿈하므로 좁은 화면에서도 가로로 넘치지 않는다. */
.legal-table {
    width: 100%;
    border-collapse: collapse;
    margin: 4px 0 12px;
    font-size: .9rem;
}
.legal-table th,
.legal-table td {
    border: 1px solid var(--border);
    padding: 8px 10px;
    text-align: left;
    vertical-align: top;
}
.legal-table th { background: var(--bg); font-weight: 500; }

/* 이번 주 빠뜨린 날 (독서 기록 화면 7일 윈도우 부채 채우기) — 시안: 박스 행 → border-bottom 리스트,
   날짜 위 / "N분 부족"(옅은 면 + 잉크) 아래 세로 스택 + 우측 채우기 고스트 버튼. */
.missed-list { list-style: none; padding: 0; margin: 8px 0 0; }
.missed-list li { display: flex; align-items: center; gap: 12px; padding: 13px 4px; border-bottom: 1px solid var(--line-1-5); }
.missed-list li:last-child { border-bottom: none; }
.missed-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.missed-list .missed-date { font-weight: 500; }
.missed-list .missed-debt { color: var(--warn-fg-5); font-size: .9rem; font-variant-numeric: tabular-nums; }
.missed-list .btn-fill { margin-left: auto; padding: 7px 15px; font-size: .85rem; text-decoration: none; white-space: nowrap; }

/* 독서 기록 카드: 헤드의 탭 버튼 2개로 바디를 전환한다(일자별 독서 시간 ↔ 이번 주 빠뜨린 날).
   JS 없이 라디오(:checked) + 형제 선택자(~)로 패널을 토글 — 두 데이터는 서버가 미리 렌더, 보이기만 전환.
   라디오는 시각만 숨기고(off-screen) 키보드 포커스는 살려 탭 전환이 키보드로도 된다. */
.record-card { position: relative; }
.record-card .tab-radio { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
/* 탭 버튼 2개(라디오 뒤 라벨)를 가로로 반반 띄운다. float라 인접 라벨 사이 공백 간격이 없어
   밑줄(탭 바 baseline)이 끊김 없이 이어진다. 패널은 clear:both로 탭 바 아래로 내려간다. */
.record-card .record-tab {
    float: left;
    width: 50%;
    box-sizing: border-box;
    text-align: center;
    padding: 10px 12px;
    font-weight: 500;
    font-size: .9rem;
    color: var(--muted);
    cursor: pointer;
    border-bottom: 2px solid var(--border);
    user-select: none;
    transition: color .15s ease, border-color .15s ease;
}
.record-card .record-tab:hover { color: var(--text); }
/* 활성 탭 = 액센트 밑줄. history는 라디오 :checked + 라벨, profile(Vue 섬)은 JS 토글 .active 클래스로
   같은 활성 스타일을 공유한다(선별 SPA 2d 전환 시 라디오 → v-if로 바뀌며 .active 경로가 필요해짐). */
.record-card .tab-radio:checked + .record-tab,
.record-card .record-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
.record-card .tab-radio:focus-visible + .record-tab {
    outline: 2px solid var(--accent);                 /* 키보드 포커스 표시(접근성) */
    outline-offset: 2px;
}
.tab-panel { display: none; }
#tab-records:checked ~ .panel-records,
#tab-missed:checked ~ .panel-missed { display: block; clear: both; padding-top: 18px; }
/* profile 탭 패널은 record-tab(float:left)을 clear해야 한다 — 안 하면 float가 record-card를
   collapse시켜 다음 형제 블록이 stretch 폭을 못 받고 min-content로 짓눌린다(당시엔 하단 .link-row).
   (#449가 죽은 #tab-bti:checked~.panel 셀렉터를 지우며 여기 있던 clear:both를 함께 잃어 회귀.) */
.panel-bti, .panel-shelf { clear: both; padding-top: 18px; }
.panel-missed .muted { margin: 0 0 4px; font-size: .85rem; }

/* === 독서 기록(/history) 반응형 기록 카드 (PR-2) ===
   좁으면 pill 탭(stacked) 한 카드, 넓으면 좌 일자별 / 우 빠뜨린날 2단(split).
   분기는 JS chooseLayout(innerWidth)가 하고(layout.ts), CSS는 두 모드의 시각만 담당.
   ※ 컨테이너 확장은 body.history-wide(JS 토글)로 — @media와 innerWidth의 스크롤바 폭 불일치 회피. */

/* split이면 940으로 둔다 — 바 있는 화면 기본 1160보다 좁은 2단 읽기 폭(본문 폭 절의 유일한 예외). */
body.history-page.history-wide .container { max-width: 940px; }

/* split: 좌(일자별) 1.45 : 우(빠뜨린날) 1 */
.hist-split { display: grid; grid-template-columns: 1.45fr 1fr; gap: 22px; align-items: start; }
.hist-pane { margin: 0; }
.hist-pane > h2 { margin: 0 0 12px; }
.hist-pane .muted { margin: 0 0 8px; font-size: .85rem; }

/* stacked: 탭 2개(활성=잉크 2px 밑줄, 비활성=흐린 글자) + 선택 패널 하나 */
.hist-tabs { display: flex; gap: 8px; margin-bottom: 4px; }
.hist-tab {
    width: auto;                              /* 전역 button{width:100%} 상쇄(#286 가드) */
    flex: 0 0 auto;
    font-family: inherit;
    font-size: .9rem;
    font-weight: 400;
    padding: 9px 16px;
    border-radius: 0;
    border: 0;
    background: transparent;
    color: var(--muted-3);
    cursor: pointer;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.hist-tab:not(.active):hover { color: var(--text); }
.hist-tab.active { color: var(--text); font-weight: 500; box-shadow: inset 0 -2px 0 var(--text); }   /* 탭 = 잉크 2px 밑줄(채움 없음) */
.hist-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hist-panel { padding-top: 14px; }

/* 일자별 시간 색 — 잉크(accent-hover). 책장 summary-list 등 타 .record-time는 안 건드리게 스코프. */
.hist-records .record-time,
.hist-pane .record-time { color: var(--accent-hover); }

/* --- 광고 (AdSense) — 부가 화면 하단에 1개. 콘텐츠와 떨어뜨려 비침습적으로. --- */
.ad-slot {
    margin: 28px auto 8px;
    max-width: 100%;
    text-align: center;
    overflow: hidden;            /* 반응형 광고가 컨테이너를 넘지 않도록 */
}
.ad-slot .ad-label {
    display: block;
    margin-bottom: 4px;
    font-size: 13px;
    color: var(--muted);
    letter-spacing: .04em;
    text-align: left;            /* '광고' 표기로 콘텐츠와 구분(투명성) */
}

/* === 공개 소개(랜딩) 페이지 스타일은 static/css/landing.css 로 이관. === */

/* === 문의·피드백 (feedback.html / admin-feedback.html) === */
.fb-form .fb-field { display: block; margin: 0.6rem 0; }
.fb-form .fb-field select,
.fb-form .fb-field input,
.fb-form .fb-field textarea {
    display: block; width: 100%; margin-top: 0.25rem; padding: 0.5rem 0.6rem;
    border: 1px solid var(--muted);
    border-radius: 2px; font: inherit; box-sizing: border-box;
    background: transparent; color: var(--text);
}
.fb-form .fb-field textarea { resize: vertical; }

.fb-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.75rem; }
.fb-item, .fb-admin-item { border: 0; border-bottom: 1px solid var(--border); border-radius: 0; padding: 0.8rem 0; }
.fb-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.fb-type { font-size: 0.78rem; font-weight: 500; background: var(--paper-2-2); border-radius: 2px; padding: 0.12rem 0.45rem; }
.fb-author { font-size: 0.8rem; opacity: 0.65; margin-left: auto; }
.fb-title { font-weight: 500; margin: 0.45rem 0 0.2rem; }
.fb-content { margin: 0 0 0.5rem; white-space: pre-wrap; word-break: break-word; opacity: 0.9; }
.fb-actions { display: flex; gap: 0.4rem; flex-wrap: wrap; }

/* 상태 배지 — 작성자 본인만 보는 처리 상태(미확인/읽음/처리완료) */
.fb-badge { display: inline-block; font-size: 0.75rem; font-weight: 500; padding: 0.12rem 0.5rem; border-radius: 999px; }
.fb-submitted { background: var(--paper-2-3); color: var(--muted-2); }
.fb-read { background: var(--info-soft-3); color: var(--info-ink); }
.fb-resolved { background: var(--ok-soft-5); color: var(--ok-ink-2); }

.btn-small { padding: 0.3rem 0.7rem; font-size: 0.85rem; }

/* 문의 — 유형 필터 탭 + 개발자 답장 */
.fb-filter { display: flex; gap: 0.4rem; flex-wrap: wrap; margin: 0.5rem 0 1rem; }
.fb-filter a {
    font-size: 0.85rem; text-decoration: none; padding: 0.25rem 0.7rem;
    border: 1px solid var(--border); border-radius: 999px; color: inherit;
}
.fb-filter a.active { border-color: var(--text); font-weight: 500; }

.fb-reply-shown { margin: 0.5rem 0; padding: 0.55rem 0.7rem; background: var(--info-soft-4); border-radius: 2px; }
.fb-reply-shown p { margin: 0.2rem 0 0; white-space: pre-wrap; word-break: break-word; }
.fb-reply-label { font-size: 0.78rem; font-weight: 500; color: var(--info-ink); }

.fb-reply-form { margin-top: 0.6rem; display: flex; flex-direction: column; gap: 0.35rem; }
.fb-reply-form textarea {
    width: 100%; padding: 0.45rem 0.6rem; border: 1px solid var(--muted);
    border-radius: 2px; font: inherit; box-sizing: border-box; resize: vertical;
    background: transparent; color: var(--text);
}
.fb-reply-form button { align-self: flex-start; }

/* ═══════════════════════════════════════════════════════════════════════
   책BTI 페이지 재스킨 (/personality) — Claude Design 이식.
   스코프: .pbti-* 신규 클래스 + personality 전용 .personality-* 와 .carousel-*
   (이 둘은 personality 페이지에서만 쓰여 재스킨해도 회귀 0). 공유 클래스
   (.card · .greeting · .status-line · .btn-* · .record-* · .link-row)는 미접촉.
   토큰: :root 단일 출처(값은 파일 머리 토큰 블록).
   ═══════════════════════════════════════════════════════════════════════ */

/* #personality-app 직계 간격: 공유 16px(N-115) 그룹 위에 페이지 스코프로 18px 덮어쓰기
   (시안 본문 gap). 공유 규칙은 건드리지 않는다. */
body.personality-page #personality-app { gap: 18px; }

/* 페이지 제목 — sr-only(시각 숨김, 문서 제목·접근성·SEO만 보존). 표준 visually-hidden 유틸. */
.sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* 최하단 정확도 고지 — 보험 약관식 작은 글씨(옛 헤더 안내문을 페이지 맨 아래로 이전, 모든 상태 공통) */
.pbti-disclaimer { font-size: 13px; color: var(--muted); text-align: center; line-height: 1.5; margin: 0; word-break: keep-all; }

/* 카드 — 시안 personality/책장요약 카드(종이톤 표면 + 따뜻한 보더 + 둥근 18) */
.pbti-card {
    background: var(--card-bg);
    border: 0;
    border-radius: 0;
    padding: 22px 0;
    display: flex; flex-direction: column; gap: 16px;
}
.pbti-card-title { font-family: var(--font-serif); font-size: 22px; line-height: 30px; font-weight: 500; color: var(--text); margin: 0; }

/* "내 독서 성향" 카드 헤더 — 제목(좌) + ? 헬프 버튼(우) 행, 팝오버 앵커(position:relative) */
.pbti-card-head { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding-bottom: 8px; border-bottom: 1px solid var(--text); }
.pbti-card-head.is-open { z-index: 60; }   /* 열림 시 버튼·팝오버를 백드롭(z50) 위로 — 실 브라우저 클릭 보장 */

/* ? 헬프 아이콘 버튼 — 작은 원형, 옅은 면 + 잉크 글자 */
.pbti-help-btn {
    flex: 0 0 auto; width: 26px; height: 26px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--sage-soft); color: var(--accent-hover);
    border: none; border-radius: 999px; cursor: pointer;
    transition: background .15s ease;
}
.pbti-help-btn:hover { background: var(--sage-hover); }
.pbti-help-btn svg { width: 16px; height: 16px; }

/* 투명 풀스크린 백드롭 — 팝오버 밖 클릭 시 닫기 */
.pbti-help-backdrop { position: fixed; inset: 0; z-index: 50; background: transparent; }

/* 안내 팝오버 — 카드 헤더 우측 아래로 펼치는 말풍선(공개 안내 + 정확도 고지) */
.pbti-help-pop {
    position: absolute; top: calc(100% + 9px); right: 0; z-index: 61;
    width: min(300px, calc(100vw - 56px));
    background: var(--card-bg);
    border: 1px solid var(--text);
    border-radius: 2px; padding: 14px;
    display: flex; flex-direction: column; gap: 11px; text-align: left;
}
.pbti-help-pop::before {   /* ? 버튼을 가리키는 말풍선 꼭지 */
    content: ''; position: absolute; top: -6px; right: 8px;
    width: 11px; height: 11px; background: var(--card-bg);
    border-left: 1px solid var(--text); border-top: 1px solid var(--text);
    transform: rotate(45deg);
}
.pbti-help-note { display: flex; gap: 9px; align-items: flex-start; }
.pbti-help-note span { font-size: 13px; line-height: 1.6; color: var(--accent-hover); word-break: keep-all; }
.pbti-help-note a { color: var(--accent-hover); font-weight: 500; text-decoration: underline; text-underline-offset: 2px; }
.pbti-help-note--muted { border-top: 1px solid var(--line-1-6); padding-top: 11px; }
.pbti-help-note--muted span { color: var(--muted); }

/* COLD_START / FALLBACK 상태 카드 — 아이콘 + 제목 행, 본문, 보조 안내 */
.pbti-state-head { display: flex; align-items: center; gap: 9px; }
.pbti-state-ico { width: 19px; height: 19px; flex: 0 0 auto; color: var(--accent-hover); }
.pbti-state-text { font-size: 14.5px; line-height: 1.75; color: var(--text); margin: 0; word-break: keep-all; }
.pbti-hint {
    display: flex; gap: 9px; align-items: center;
    background: var(--sage-soft); border-radius: 2px; padding: 11px 13px;
}
.pbti-hint-ico { width: 16px; height: 16px; flex: 0 0 auto; color: var(--accent-hover); }
.pbti-hint span { font-size: 13px; line-height: 1.55; color: var(--accent-hover); word-break: keep-all; }

/* 책장 요약 — 균일 비클릭 칩(시안의 button/span 구분은 /personality엔 부적합, §4.1) */
.pbti-chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.pbti-chip {
    display: inline-flex; align-items: center;
    background: var(--sage-soft); color: var(--accent-hover);
    padding: 6px 13px; border-radius: 999px;
    font-size: 13.5px; white-space: nowrap;
}
.pbti-divider { height: 1px; background: var(--line-1-6); }
.pbti-summary { display: flex; flex-direction: column; gap: 13px; }
.pbti-summary-row { display: flex; flex-direction: column; gap: 3px; }
.pbti-summary-label { font-size: 13px; color: var(--muted); }
.pbti-summary-value { font-size: 15px; color: var(--text); word-break: keep-all; }
.pbti-meta { font-size: 13px; color: var(--muted); margin: 0; word-break: keep-all; }
/* 강조 수치(완독·저자·장르 수, 남은 횟수) — 명조 잉크 500 */
.pbti-num { font-family: var(--font-serif); color: var(--accent-hover); font-weight: 500; }

/* 성향 안내 블록 — 「다시 분석」 버튼이 있던 자리(2026-09-08에 웹 생성을 걷으며 제거).
   .pbti-exhausted는 원래 「한도 소진」 박스였는데 지금은 「앱에서 만들 수 있어요」 안내가 쓴다 —
   이름이 낡았지만 스타일은 그대로 맞아 재사용한다. */
.pbti-refresh { display: flex; flex-direction: column; gap: 9px; }
.pbti-exhausted {
    display: flex; gap: 9px; align-items: flex-start;
    background: var(--card-bg); border: 0;
    border-radius: 0; padding: 13px 0;
}
.pbti-exhausted .pbti-hint-ico { width: 17px; height: 17px; margin-top: 1px; }
.pbti-exhausted span { font-size: 13px; line-height: 1.65; color: var(--muted); word-break: keep-all; }

/* 공개 안내 지구본 아이콘 — 이제 ? 헬프 팝오버(.pbti-help-note) 안에서 사용(상시 박스는 폐지) */
.pbti-note-ico { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 1px; color: var(--accent-hover); }

/* ── 분석 카드 캐러셀 (CSS scroll-snap + 화살표 버튼 JS — 스크롤 로직 보존, 시각만 재스킨) ── */
.pbti-carousel-block { display: flex; flex-direction: column; gap: 14px; }
.personality-carousel-wrap { display: flex; align-items: center; gap: 6px; }
.personality-carousel {
    flex: 1; min-width: 0;
    display: flex;
    gap: 0.75rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scroll-behavior: smooth;
    scrollbar-width: none;
    padding-block: 6px;  /* 고른 카드의 잉크 테가 overflow-x 트랙에 위아래로 잘리지 않게 여유 */
}
.personality-carousel::-webkit-scrollbar { display: none; }
.personality-slide {
    flex: 0 0 80%;              /* 양옆 이웃이 엿보이게 */
    scroll-snap-align: center;  /* 활성 카드를 가운데로 */
    scroll-snap-stop: always;
    min-width: 0;
    margin-top: 0;
}
.personality-slide:first-child { margin-left: 10%; }   /* 첫 카드도 중앙 (= (100-80)/2) */
.personality-slide:last-child  { margin-right: 10%; }  /* 끝 카드도 중앙 */
.personality-slide:only-child  { flex-basis: 100%; margin-left: 0; margin-right: 0; }  /* 1개면 꽉, 여백 0 */
@media (prefers-reduced-motion: reduce) {
    .personality-carousel { scroll-behavior: auto; }
}

/* 좌우 네비 — 시안: 34px 원형(인라인). 전역 button{width:100%}을 명시 폭으로 상쇄. */
.carousel-nav {
    flex: 0 0 auto;
    width: 34px; height: 34px;
    padding: 0;
    border-radius: 999px;
    border: 1px solid var(--text);
    background: transparent;
    color: var(--text);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer; transition: background .15s ease;
}
.carousel-nav svg { width: 17px; height: 17px; }
.carousel-nav:hover { background: var(--sage-hover); }
.carousel-nav[disabled] { opacity: 0.4; cursor: default; }
/* 넘칠 게 없으면(단일 카드 등) 버튼 숨김 — JS가 .nav-hidden 토글, 트랙이 풀폭 */
.personality-carousel-wrap.nav-hidden .carousel-nav { display: none; }
/* 터치 기기: 네이티브 스와이프 — 버튼 숨김(도트는 유지) */
@media (pointer: coarse) {
    .carousel-nav { display: none; }
}

/* 도트 인디케이터 — 시안 신규(entries>1일 때). 활성=중앙 슬라이드(dotIndex) */
.pbti-dots { display: flex; justify-content: center; gap: 6px; }
.pbti-dot { width: 7px; height: 7px; border-radius: 999px; background: var(--line-2); transition: background .2s ease; }
.pbti-dot.is-active { background: var(--accent-hover); }

/* 슬라이드 내용 — 배지 행 / 서술 / 변경 알림 / 대표 선택.
   각 슬라이드를 테두리+은은한 그림자로 띄워 개별 카드로 인식되게 한다(섹션 안의 패널). */
.personality-entry {
    display: flex; flex-direction: column; gap: 13px;
    min-height: 200px; margin: 0;
    background: var(--card-bg);
    border: 1px solid transparent;   /* 고른 카드만 이 자리에 잉크 테 — 크기가 안 흔들리게 */
    border-radius: 0;
    padding: 18px;
}
/* 대표(선택) 카드 — 잉크 1px 테로 한눈에 구분 */
.personality-entry.is-selected {
    border-color: var(--text);
}
.personality-entry-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.personality-badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 5px 11px; border-radius: 999px;
    font-size: 13px; white-space: nowrap;
}
.personality-badge svg { width: 13px; height: 13px; flex: 0 0 auto; }
.personality-badge-rep { background: var(--accent); color: var(--card-bg); font-weight: 500; }
.personality-badge-cand { background: transparent; border: 1px solid var(--sage-line-2); color: var(--accent-hover); padding: 5px 12px; }
.personality-time { font-size: 13px; color: var(--muted); flex: 0 0 auto; }
.personality-narrative {
    font-family: var(--font-serif);
    font-size: 16px; line-height: 1.85; color: var(--text);
    margin: 0; word-break: keep-all; text-wrap: pretty;
}
/* 모바일(<600px)만: 좁은 폭에서 긴 AI 서술이 카드를 길쭉하게 늘이던 걸 본문 내부 세로 스크롤로 자른다.
   ⚠️ 서술을 고정 max-height로 자르면 빈칸이 생긴다: 캐러셀(display:flex, align stretch)은 모든 슬라이드를
   가장 높은 카드로 늘이는데, 모바일 좁은 폭에선 'stale 알림'(이 분석 이후 책장이 바뀌었어요…)이 여러 줄로
   감겨 그 카드가 제일 커진다. 그러면 stale 없는 카드는 (고정 높이 본문 + margin-top:auto 풋터) 사이에 큰 빈칸.
   해결: 서술을 flex 아이템으로 남는 세로 공간을 채우게(flex:1 1 0) + 슬라이드에 기준 높이(min-height).
   → stale 없는 카드는 본문이 더 길게 차고(빈칸 0), stale 카드는 본문이 그만큼 줄어 내부 스크롤(카드 높이 일정).
   데스크톱(≥600px)은 narrow-page 720로 이미 짧아 무변경 — min-width:600px 경계와 정합.
   step()/dotIndex는 가로 로직이라 높이 무관(JS 무변경). */
@media (max-width: 599px) {
    .personality-entry { min-height: 500px; }   /* 카드 기준 높이 — 빈칸 대신 본문이 채움(요청: 더 길어도 OK) */
    .personality-narrative {
        flex: 1 1 0;
        min-height: 0;                  /* flex 자식 내부 스크롤 가능(기본 min-height:auto 상쇄) */
        overflow-y: auto;
        overscroll-behavior: contain;   /* 끝까지 스크롤해도 페이지로 체이닝 안 됨 */
        scrollbar-width: thin;          /* "더 있다" 힌트 — 캐러셀과 달리 스크롤바 숨기지 않음 */
    }
}
.personality-stale {
    display: flex; gap: 9px; align-items: flex-start;
    background: var(--sage-soft); border-radius: 2px; padding: 11px 13px; margin: 0;
}
.personality-stale svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 1px; color: var(--accent-hover); }
.personality-stale span { font-size: 13px; line-height: 1.6; color: var(--accent-hover); word-break: keep-all; }
.pbti-select-rep {
    width: 100%; margin-top: auto;  /* 카드 하단에 고정 — 카드 높이 정렬 */
    background: transparent; border: 1px solid var(--accent); color: var(--accent-hover);
    border-radius: 2px; padding: 10px;
    font-family: inherit; font-size: 14px;
    display: flex; align-items: center; justify-content: center; gap: 6px;
    cursor: pointer; transition: background .15s ease;
}
.pbti-select-rep svg { width: 14px; height: 14px; flex: 0 0 auto; }
.pbti-select-rep:hover { background: var(--sage-soft); }
/* 대표 카드 하단 — 비클릭 '선택됨' 상태(선택 버튼과 같은 footprint로 카드 균형·빈 느낌 해소) */
.pbti-selected-mark {
    width: 100%; margin-top: auto;
    background: var(--sage-soft); border: 1px solid transparent; color: var(--accent-hover);
    border-radius: 2px; padding: 10px;
    font-family: inherit; font-size: 14px; font-weight: 500;
    display: flex; align-items: center; justify-content: center; gap: 6px;
}
.pbti-selected-mark svg { width: 15px; height: 15px; flex: 0 0 auto; }

/* ═══════════════════════════════════════════════════════════════════════
   대시보드 Claude Design 이식 (PR-2) — dashboard 전용 .dash-* 스코프.
   기존 .grass-cell·.timer-*·.quick-* 등 공유 클래스와 격리(전역 회귀 0).
   ═══════════════════════════════════════════════════════════════════════ */

.dash-card {
    background: var(--card-bg);
    /* 면 없는 덩어리(에디토리얼) — 테·그림자·모서리 0. 덩어리 사이는 #dashboard-app의 세로 간격이 가른다. */
    border: 0;
    border-radius: 0;
    padding: clamp(18px, 2.4vw, 26px) 0;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.dash-pill {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: transparent;   /* 눈썹 — 채움 없는 흐린 글자(에디토리얼) */
    color: var(--muted);
    font-size: 13px;
    padding: 0;
    border-radius: 999px;
    width: auto;
}
.dash-pill-ok { color: var(--text); font-weight: 500; }
/* 목표 달성 표식 — 미니앱과 같은 획(SPROUT_PATHS). 프레젠테이션 속성엔 var()가 안 먹어 선 색을 여기서 준다. */
.dash-sprout { stroke: var(--accent); vertical-align: -2px; flex: none; }
.dash-goal-stamp { stroke: var(--text); }

/* 제목(pill/head)을 본문에서 띄워 섹션 분리감 — 카드 안 본문은 촘촘히, 제목 아래만 여유 */
.dash-card-head { margin-bottom: 4px; }

/* 헤더 한 줄 명언 — 홈 카드 묶음을 "닫는 각주"로 정리(2026-07-10, C안 하이브리드).
   기존엔 카드 밖 맨몸 좌측정렬 이탤릭이라 위 카드들과 동떨어져 보였다. 카드로 감싸지 않되
   (1) 위로 넉넉한 여백 + 짧은 가는 구분선, (2) 본문을 감싼 흐린 글자 따옴표,
   (3) 중앙정렬 + 폰트 축소로 "각주" 위상을 만들어 위 카드 묶음과의 소속감을 준다.
   슬롯(#brand-quote-slot)은 dashboard.html SSR — Vue(BrandQuote)가 Teleport로 채운다.
   장식(구분선·따옴표)은 명언 있을 때만 렌더되는 .brand-quote/.brand-quote-text에만 붙여
   명언 0개일 때 장식만 뜨는 사고를 막는다. 공유 .brand는 건드리지 않는다(타 페이지 회귀 0). */
.brand-quote-slot { margin: 4px 0 10px; }
.brand-quote {
    --bq-size: 0.9rem;                 /* 각주 톤: 1.05rem → 0.9rem 로 약화 */
    position: relative;
    overflow: hidden;
    box-sizing: content-box;           /* 전역 리셋이 border-box여도 padding-top(구분선 자리)이 2줄 높이를 안 갉게 못박음 */
    /* 위 카드 그리드와의 시각적 텀: 위로 넉넉한 여백 + padding-top에 페이드 구분선 자리 */
    margin-top: 22px;
    padding-top: 16px;
    /* 2줄 높이로 고정 → 명언 길이가 바뀌어도(롤링 포함) 아래 요소가 안 밀린다. 3줄 극단은
       overflow:hidden 안전망. 높이는 --bq-size에 비례해 재계산(데스크톱에서 키워도 자동 동기화). */
    display: flex;
    align-items: center;
    justify-content: center;
    height: calc(var(--bq-size) * 1.5 * 2);
    line-height: 1.5;
    font-family: var(--font-serif);
    font-style: italic;
    color: var(--muted);               /* 카드 시절(--text)보다 톤 다운 — 약화 취지 */
    text-align: center;                /* 중앙정렬 각주 */
}
/* 구분선 — 짧은 중앙 가는 선 1px(에디토리얼: 그라데이션 0). 명언 있을 때만 렌더. */
.brand-quote::before {
    content: "";
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: min(220px, 58%);
    height: 1px;
    pointer-events: none;
    background: var(--border);
}
.brand-quote-line {
    /* 본문+저자를 하나의 연속 텍스트 흐름으로(flex 아님) — 저자가 별도 줄을 차지하지 않고
       본문 끝에 이어 붙어, 본문이 2줄이어도 저자까지 2줄 안에 담긴다. width:100%로 부모 폭 확보,
       text-align:center는 .brand-quote에서 상속. */
    width: 100%;
    /* 긴 명언만 폰트 축소(--q-scale = BrandQuote.vue가 글자수로 계산 주입) — 2줄에도 넘칠 때
       잘림 없이 담기 위함. 상한=--bq-size, 하한 13px 하드가드(글자 바닥 — 미니앱과 같은 「최소 13」). font-size는 롤 트랜지션
       대상(transform·opacity)이 아니라 즉시 확정(깜빡임 없음). */
    font-size: clamp(13px, calc(var(--bq-size) * var(--q-scale, 1)), var(--bq-size));
}
/* 본문은 자연 줄바꿈(사용자 피드백: 말줄임 대신 개행). 흐린 글자 따옴표로 본문만 감싼다 —
   장식이 .brand-quote-text에 붙어 롤과 함께 자연 교체되고, 저자("— 저자")는 닫는 따옴표 뒤에
   이어져 흐름 유지. 명언 없으면 텍스트 자체가 없어 따옴표도 안 뜬다. */
.brand-quote-text { overflow-wrap: break-word; }
.brand-quote-text::before,
.brand-quote-text::after {
    font-style: normal;
    color: var(--muted);
}
.brand-quote-text::before { content: "\201C"; margin-right: 1px; }
.brand-quote-text::after  { content: "\201D"; margin-left: 1px; }
.brand-quote-author { font-size: max(13px, .78em); margin-left: 6px; white-space: nowrap; }
/* 데스크톱(홈 컬럼 넓음)은 각주를 아주 살짝만 키우고 --q-scale 축소를 끈다 — 높이는 --bq-size에
   비례해 자동 재계산되므로 2줄 클립 없음. */
@media (min-width: 640px) {
    .brand-quote { --bq-size: 0.95rem; }
    .brand-quote-line { font-size: var(--bq-size); }
}
/* 슬롯 롤: 새 줄은 아래에서 위로, 옛 줄은 위로 사라짐(고정 %가 아니라 짧은 고정 거리 —
   줄 수가 가변이라 자기 높이 기준 %는 일관성이 없음). .brand-quote가 클립. */
.brand-quote-roll-enter-active,
.brand-quote-roll-leave-active { transition: transform .3s cubic-bezier(.4, 0, .2, 1), opacity .3s ease; }
.brand-quote-roll-enter-from { transform: translateY(10px); opacity: 0; }
.brand-quote-roll-leave-to { transform: translateY(-10px); opacity: 0; }
/* 모션 최소화: 슬라이드만 끔(로테이션=명언 다양성은 유지, 즉시 교체) */
@media (prefers-reduced-motion: reduce) {
    .brand-quote-roll-enter-active,
    .brand-quote-roll-leave-active { transition: none; }
    .brand-quote-roll-enter-from,
    .brand-quote-roll-leave-to { transform: none; }
}

/* 타이머 히어로 */
.dash-timer-hero {
    border-radius: 0;
    padding: clamp(22px, 3vw, 36px) 0;
    flex-direction: row;
    flex-wrap: wrap;
    gap: clamp(22px, 3vw, 40px);
    align-items: center;
}
/* 아치 표제창(에디토리얼 PR-3 — 미니앱 ui.tsx 아치와 같은 잉크 1px · 999 999 0 0). 폭은 고정 —
   반경이 폭의 절반이라 넓게 늘이면 돔이 거대해진다. 342×252(미니앱)의 비율로 400×296. 내용은 세로 가운데. */
.dash-timer-left {
    flex: 0 0 auto; width: min(400px, 100%); min-height: 296px; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px;
    padding: 40px 24px 44px; text-align: center;
    border: 1px solid var(--text); border-radius: 999px 999px 0 0;
}
.dash-timer-left .dash-pill { align-self: center; font-size: 14px; line-height: 21px; }
/* 시계 — 5자(mm:ss) 84/88 · 1시간 넘은 8자 68/72(좁은 폭은 화면 폭에 맞춰 줄인다 — 미니앱 Home.tsx와 같은 식).
   측정 중 공부 머리 막대(.focus-bar)의 시계는 아치 밖이라 이 크기를 받지 않는다. */
.dash-timer-left .dash-timer-num { font-size: 84px; line-height: 88px; }
.dash-timer-left .dash-timer-num.is-long { font-size: min(68px, calc((100vw - 90px) / 4.1)); line-height: 72px; }
.dash-timer-num {
    font-family: var(--font-serif);
    font-weight: 500;
    line-height: .95;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
    transition: color .4s ease;
}
/* 목표 달성 시 히어로 숫자·진행바를 --ok(성취 = 잉크)로 전환 — 색만, 새 색 없음(가드레일) */
.dash-timer-num-ok { color: var(--ok); }
.dash-progress-wrap { display: flex; flex-direction: column; gap: 8px; width: 240px; max-width: 100%; }
.dash-progress-track { height: 4px; border-radius: 2px; background: var(--border); overflow: hidden; }
.dash-progress-fill { height: 100%; background: var(--accent); border-radius: 2px; transition: width .5s ease, background .4s ease; }
.dash-progress-fill-ok { background: var(--ok); }
.dash-progress-meta { display: flex; justify-content: space-between; font-size: 13px; color: var(--muted); }
.dash-progress-pct { color: var(--accent-hover); font-variant-numeric: tabular-nums; }
/* 밀린 시간 안내 — 오늘 표 끝(주 버튼 아래) 가는 선 위, 톤 다운(밀린 빚을 위협이 아니라 안심으로) */
.dash-forgive-note {
    margin: 2px 0 0;
    padding-top: 12px;
    border-top: 1px solid var(--border);
    font-size: 13px;
    line-height: 1.5;
    color: var(--muted);
    word-break: keep-all;      /* 한글 어절(공백) 단위 개행 — 조사 중간 끊김 방지 */
    overflow-wrap: break-word; /* 긴 불가분 토큰 오버플로 안전장치 */
    text-wrap: pretty;         /* 마지막 줄 고아 단어 방지 (미지원 브라우저는 무시) */
}

/* 오늘 표 — 면 없는 줄 표(줄 = 아래 가는 선 · 값 = 명조). 넓으면 아치 옆 칸, 좁으면 아래(경계는 히어로 미디어 쿼리 둘). */
.dash-timer-right { flex: 1 1 320px; max-width: 560px; min-width: 0; }

/* 상태 패널 */
.dash-state-panel {
    background: var(--card-bg);
    border: 0;
    border-radius: 0;
    padding: 20px 0;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.dash-state-row { display: flex; align-items: center; justify-content: space-between; min-height: 48px; border-bottom: 1px solid var(--border); }
.dash-state-row .dash-pill { align-self: center; }   /* 눈썹 기본 flex-start면 「측정 중」이 시간 값보다 위로 뜬다 */
.dash-state-row + .dash-divider { display: none; }   /* 줄 선이 구분을 맡는다 — 둘이면 이중선 */
.dash-pill-pulse { gap: 7px; }
.dash-pulse-dot {
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--accent);
    animation: btPulse 1.4s ease-in-out infinite;
}
@keyframes btPulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: .4; transform: scale(.65); }
}
.dash-session-time {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 24px;
    line-height: 30px;
    color: var(--accent-hover);
    font-variant-numeric: tabular-nums;
}
.dash-divider { height: 1px; background: var(--border); }
.dash-kv { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; min-height: 48px; padding: 9px 0; border-bottom: 1px solid var(--border); }
/* 오늘 표 라벨 14 흐린 · 값 명조 24/30(미니앱 「큰 값」). 공부 머리 막대(.focus-kv)는 같은 라벨·값 클래스를 쓰지만 이 줄 밖이라 그대로. */
.dash-kv .dash-kv-k { font-size: 14px; }
.dash-kv .dash-kv-v,
.dash-kv .dash-kv-v-num { font-family: var(--font-serif); font-weight: 500; font-size: 24px; line-height: 30px; }
.dash-kv-k { font-size: 13px; color: var(--muted); }
.dash-kv-v { font-family: var(--font-serif); font-weight: 500; font-size: 16px; color: var(--text); text-align: right; }
.dash-kv-v-num { font-size: 14.5px; color: var(--text); font-variant-numeric: tabular-nums; }

/* 버튼 — 패널 안 풀폭(전역 button{width:100%} 활용); a는 block 명시 */
.dash-btn-outline {
    margin-top: 4px;
    padding: 14px;
    border-radius: 999px;
    border: 1px solid var(--text);
    background: transparent;
    color: var(--text);
    font-family: inherit;
    font-size: 16px;
    font-weight: 500;
    cursor: pointer;
    transition: background .2s ease;
}
.dash-btn-outline:hover { background: var(--sage-hover); }
.dash-btn-fill {
    padding: 14px;
    border-radius: 999px;
    border: 1px solid var(--accent-fill);
    background: var(--accent-fill);
    color: var(--on-accent);
    font-family: inherit;
    font-size: 16px;
    cursor: pointer;
    transition: opacity .2s ease;
}
.dash-btn-fill:hover { opacity: .88; }
.dash-btn-link { display: block; width: 100%; box-sizing: border-box; text-align: center; text-decoration: none; }

/* ACHIEVED */
/* 가운데는 축하 문구(도장·제목·한 줄)만 — 패널에 text-align을 두면 아래 시작 폼(책 줄·「이 책으로…」)까지
   상속돼 대기 상태와 정렬이 갈린다(에디토리얼 PR-4 마감). */
.dash-state-achieved { align-items: center; gap: 12px; }
.dash-achieved-title { margin: 0; font-family: var(--font-serif); font-weight: 500; font-size: 19px; color: var(--text); line-height: 1.4; text-align: center; }
.dash-achieved-sub { margin: 0; font-size: 13.5px; color: var(--muted); line-height: 1.5; text-align: center; }
/* 달성 패널에 측정 시작 폼이 함께 들어갈 때: 격려 텍스트는 가운데 유지, 폼 컨트롤은 풀폭으로
   (패널이 align-items:center라 폼 자식이 좁아지는 것 방지). */
.dash-state-achieved .dash-divider,
.dash-state-achieved .dash-idle-label,
.dash-state-achieved .dash-book-chip,
.dash-state-achieved .dash-empty,
.dash-state-achieved .dash-btn-fill { align-self: stretch; width: 100%; box-sizing: border-box; }

/* 타이머 우패널 전환 크로스페이드 — <Transition name="panel-fade" mode="out-in">.
   측정 시작/종료 시 패널이 "툭" 즉시 교체되던 것을 페이드+살짝 떠오르기로 부드럽게.
   out-in이라 나가는 패널이 사라진 뒤 들어오는 패널이 등장. */
.panel-fade-enter-active,
.panel-fade-leave-active { transition: opacity .2s ease, transform .2s ease; }
.panel-fade-enter-from { opacity: 0; transform: translateY(6px); }
.panel-fade-leave-to { opacity: 0; transform: translateY(-6px); }

/* 진행 중(서버 왕복) 비활성 버튼 — 눌렸지만 흐릿하게(중복 클릭 차단을 시각적으로). */
.dash-btn-outline:disabled { opacity: .6; cursor: progress; }
/* 주 버튼 비활성 — 옅은 면 + 흐린 글자(불투명 1). 반투명 검정은 「눌림」과 구별이 안 된다. */
.dash-btn-fill:disabled { background: var(--sage-soft); border-color: var(--sage-soft); color: var(--muted); opacity: 1; cursor: progress; }

@media (prefers-reduced-motion: reduce) {
    /* 모션 최소화 사용자는 페이드 없이 즉시 교체. */
    .panel-fade-enter-active,
    .panel-fade-leave-active { transition: none; }
    .panel-fade-enter-from { transform: none; }
    .panel-fade-leave-to { transform: none; }
}

/* IDLE 책 선택 */
.dash-idle-label { font-size: 14px; color: var(--muted); }
.dash-empty { display: flex; flex-direction: column; gap: 12px; text-align: center; }
.dash-empty p { margin: 0; font-size: 14px; color: var(--muted); line-height: 1.6; }

/* 책 칩(측정 시작 진입, §6.5) — 기본 책 표지 + 제목 + '바꾸기' pill. 카드 토큰 재사용(새 색 없음). */
.dash-book-chip {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 0; border: 0; border-bottom: 1px solid var(--border); min-height: 48px;
    border-radius: 0; background: var(--card-bg);
}
.dash-book-chip-cover {
    width: 30px; height: 42px; border-radius: 2px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-serif); font-weight: 500; font-size: 14px; line-height: 1; user-select: none;
}
/* 실표지일 때 — 비율이 제각각이라 잘라 채운다. 로드 전·투명 PNG의 뒷배경은 종이색으로 둔다. */
img.dash-book-chip-cover { object-fit: cover; background: var(--line-1); }

/* 제목은 2줄까지 — 한 줄 ellipsis는 좁은 우패널에서 9자쯤에 끊겼다(실측 57자 제목이 「2026 이기적 …」).
   2줄로도 넘치는 초장문은 :title(호버 툴팁)이 받는다 — bookChipTitle.test.ts가 그 속성을 못 박는다. */
.dash-book-chip-title {
    flex: 1 1 auto; min-width: 0; font-weight: 500; color: var(--text); line-height: 1.35;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* 「바꾸기 ›」 — 표 안의 글자 링크(외곽선 알약이면 표 줄 하나에 버튼이 둘로 보인다). › 는 화면 읽기에서 뺀다. */
.dash-book-chip-change {
    width: auto; flex-shrink: 0; padding: 6px 0; border: 0;
    border-radius: 0;
    background: none; color: var(--text); font-size: 13px; font-weight: 500; cursor: pointer;
}
/* 두 번 선언 — 대체 텍스트 문법(/ "")을 모르는 브라우저(Safari 17.4·Firefox 128 미만)는 뒤 줄을 버리고 앞 줄의 ›를 쓴다. */
.dash-book-chip-change::after { content: " \203A"; content: " \203A" / ""; }
.dash-book-chip-change:hover { text-decoration: underline; }
.dash-book-chip-change:disabled { opacity: .5; cursor: default; }
/* '책 없이 시작' — 눈에 띄지 않는 보조 링크(시작을 막지 않되 기본 강조는 '측정 시작'). */
.dash-bookless {
    align-self: center; width: auto; background: none; border: none; cursor: pointer;
    color: var(--muted); font-size: 13px; text-decoration: underline;
}
.dash-bookless:hover { color: var(--text); }
.dash-bookless:disabled { opacity: .5; cursor: default; }

/* 카드 머리 — 옛 잔디 카드에서 온 공용 부품(2026-09-07 잔디 철거). 여백·백지복습 카드가 같은 머리를
   쓴다: 왼쪽에 pill(+칩·부제), 오른쪽에 기록 링크. 이름에서 grass를 걷은 것은 이제 잔디가 아니라서다. */
.dash-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.dash-card-head-left { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dash-card-sub { font-size: 13px; color: var(--muted); }
.dash-card-note { margin: 0; font-size: 14px; color: var(--muted); line-height: 1.6; }
.dash-streak-chip {
    display: inline-flex; align-items: center; gap: 7px;
    background: transparent; color: var(--muted);
    font-size: 13px; padding: 0; border-radius: 999px;
}
/* 홈 카드 머리(여백 · 공부 필기) = 섹션 머리 — 명조 22/30 잉크 + 잉크 1px 선(`.card h2`와 같은 값). 눈썹(.dash-pill)을 머리로 올린다.
   필기는 .focus-body(홈 StudyNotesCard)로 좁힌다 — /study/recall 백지노트도 .dash-recall-card라 거기까지 바뀐다. */
.dash-margin-card > .dash-card-head,
.dash-recall-card.focus-body > .dash-card-head { padding-bottom: 8px; border-bottom: 1px solid var(--text); }
.dash-margin-card > .dash-card-head .dash-pill,
.dash-recall-card.focus-body > .dash-card-head .dash-pill { font-family: var(--font-serif); font-weight: 500; font-size: 22px; line-height: 30px; color: var(--text); }
.dash-streak-chip strong { font-variant-numeric: tabular-nums; }

/* 홈 여백 미리보기 — 최근 2건. 넓어지면 2열로 눕는다(카드가 둘뿐이라 auto-fit이면 충분하다).
   카드 자체는 책방 여백 패널의 .margin-card를 그대로 쓴다 — 같은 글이 두 화면에서 다르면 어색하다. */
/* 홈 백지복습 — 패널이 스스로 그리는 「백지복습」 라벨은 여기선 카드 머리의 pill과 겹친다.
   /study에선 그 라벨이 유일한 제목이라 패널은 그대로 두고, 이 카드 안에서만 감춘다. */
.dash-recall-card .study-day-label { display: none; }

/* 긴 것에 상한을 둔다 — 잔디를 걷어낸 이유가 「늘어짐」이라 여기서 다시 늘어나면 헛일이다.
   책 제목은 한 줄, 미리보기 본문은 4줄까지. 책방 여백 패널(.margin-card)엔 안 닿는다 —
   거기선 글 전문을 읽는 것이 목적이다. */
.dash-card-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 46ch; }
.dash-margin-cards .margin-card-text {
    display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.dash-margin-card .dash-btn-outline {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 부가 입력이 카드 폭까지 늘어나는 것을 640~1099px 대역에서도 막는다(2열이 서는 폭 아래).
   ≥1100px에선 그리드 열이 330px이라 이 상한은 닿지 않는다. */
.dash-recall-card .study-recall-side { max-width: 460px; }

.dash-margin-cards {
    list-style: none; margin: 0; padding: 0;
    display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px;
}

/* 1099px 이하: 아치 위 · 오늘 표 아래(둘 다 가운데, 표는 최대 560). 경계는 아래 ≥1100 절과 맞물린다 — 1099.98인 것은
   배율·확대로 생기는 1099~1100 사이 소수 폭에서 두 쿼리가 다 꺼지지 않게다(1099px이면 기본 row·wrap·center로 돌아간다).
   flex-wrap으로 접히면 CSS가 그 상태를 몰라 표 위 선을 켜고 끌 수 없다. 좁은 화면에선 아치 밑선이 표 위 선을 대신한다. */
@media (max-width: 1099.98px) {
    .dash-timer-hero { flex-direction: column; align-items: stretch; }
    /* column 축에선 flex-basis(320px)가 height로 잡혀 블록이 과잉 높이 → 공백.
       basis를 auto로 풀어 콘텐츠 높이로 (N-118 부류 아님, flexbox 축 전환 함정) */
    .dash-timer-left, .dash-timer-right { flex: 0 0 auto; }
    .dash-timer-left { align-self: center; }   /* stretch가 400 고정 아치를 늘이지 않게 */
    .dash-timer-right { align-self: center; width: 100%; }
}
@media (max-width: 639px) {
    .dash-timer-left { min-height: 252px; }
}

/* ── PR-3: 헤더 사용자영역 · 서재 · 로그아웃 · 와이드 2단 ── */

/* 데스크톱 — 넓어진 카드에 안의 요소 크기도 맞춘다(폭만 키우면 카드가 비어 보인다).
   경계 1100px은 원래 잔디에서 나온 값이다(1년치가 16px 칸으로 스크롤 없이 들어가는 최소 폭). 잔디는
   2026-09-07에 걷었지만 경계는 그대로 둔다 — 3열 타일·백지복습 2열이 편해지는 폭이 마침 같은 자리다. */
@media (min-width: 1100px) {
    /* 홈 히어로 — 아치 | 오늘 표 한 줄. 표가 옆 칸이라 아치 밑선이 표 위를 잇지 못해 표 위에 잉크 선을 따로 긋는다.
       위 맞춤 — 그 선이 아치 꼭대기와 같은 높이에 선다(가운데 맞춤이면 표 높이 — 측정 중·공부·밀린 시간 안내 — 마다 어긋났다). */
    .dash-timer-hero { flex-wrap: nowrap; align-items: flex-start; }
    .dash-timer-right { border-top: 1px solid var(--text); }
    /* 공부 측정 중 머리 막대는 아치가 없다 — 막대·회당 시간 폼·안내가 한 줄씩(flex-basis 100%) 떨어져야 한다. */
    .dash-timer-hero:has(> .focus-bar) { flex-wrap: wrap; }

    /* 홈 백지복습 — 본문을 왼쪽에 크게, 책·과목·범위를 오른쪽 좁은 열로. 안 그러면 한 줄짜리 「과목」
       입력이 1100px로 늘어나 잔디를 걷어낸 이유를 그대로 되부른다.
       order로 뒤집는 이유: /study의 쓰는 순서(과목·범위 → 본문)를 DOM에서 지켜야 해서 side가 앞에 있다. */
    .dash-recall-card .study-recall-split {
        display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 18px; align-items: start;
    }
    .dash-recall-card .study-recall-main { order: 0; }
    .dash-recall-card .study-recall-side { order: 1; }
}

/* ── 공부 집중 — 측정 중 타이머와 필기가 한 장이 된다(설계 2026-09-15-study-focus-lamp). 색 리터럴 0 ──
   독서등 색(밤·등불 종이·불빛)은 파일 끝 다크 절 안 「독서등」에 있다(래칫이 건너뛰는 자리). */
.focus-stack { display: flex; flex-direction: column; gap: 20px; }
/* 전환 이름 — 필기 카드의 틀이 위로 자라 한 장의 틀이 되고(focus-frame), 히어로는 머리 막대로 줄어들며(focus-top),
   필기 내용은 같은 요소라 그대로 따라간다(focus-notes). 숫자는 따로 날아간다(clock).
   이름은 한 화면에 하나씩이어야 한다 — 겹치면 브라우저가 에러 없이 전환을 통째로 건너뛴다. */
.focus-stack:not(.is-merged) > .focus-top { view-transition-name: focus-top; }
.focus-stack:not(.is-merged) > .focus-body { view-transition-name: focus-frame; }
.focus-stack.is-merged .focus-bar { view-transition-name: focus-top; }
.focus-body .study-day { view-transition-name: focus-notes; }
.vt-clock { view-transition-name: clock; width: fit-content; }   /* 블록 폭 스냅숏이면 크기가 틀어진다 */
.focus-stack.is-merged {
    gap: 0; view-transition-name: focus-frame;
    border: 0; border-radius: 2px;
    background: var(--card-bg);   /* 독서등 종이 한 장 — 낮 토큰 목록이 .lamp-page에 종이를 다시 깐다(투명으로 두면 밤 위 잉크 글자). */
}
/* (0,4,1) — 다크의 `:root[data-theme="dark"] .dash-timer-hero.is-study`(0,4,0, 파일 끝)를 이겨야 한다.
   body를 빼면 특이도가 같아져 파일 순서로 다크가 이기고, 다크 테마에서 막대만 푸른 차콜로 남는다. */
body .focus-stack.is-merged > .dash-card.is-study { border: 0; border-radius: 0; background: transparent; box-shadow: none; }
/* 히어로(.dash-timer-hero)는 원래 flex row·wrap이다 — 막대가 한 줄을 다 차지하고(flex-basis 100%) 회당 시간 폼이 그 아래 줄로 떨어진다 */
.focus-stack.is-merged > .focus-top { padding: 16px 26px 14px; gap: 0; border-bottom: 1px dashed var(--line-2); }
/* 종이 한 장 안쪽 — .dash-card의 좌우 0(면 없는 덩어리)을 물려받으면 필기 칸이 종이 가장자리에 붙는다. */
.focus-stack.is-merged > .focus-body { padding-top: 18px; padding-inline: 26px; }
.focus-stack.is-merged > .focus-body > .dash-card-head { display: none; }
.focus-bar { flex: 1 1 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 12px 28px; }
.focus-bar .dash-timer-num { font-size: 42px; }
.focus-kv { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.focus-kv .dash-kv-v { text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.focus-kv.is-book { flex: 1 1 200px; }
.focus-actions { display: flex; align-items: center; gap: 14px; margin-left: auto; }
.focus-bar .dash-btn-outline { width: auto; margin: 0; padding: 9px 20px; font-size: 15px; }
.focus-bar .dash-bookless { align-self: auto; }
/* 측정 시작·종료 단축키 힌트 — 버튼 안 작은 보조 글자(글자 바닥 13px, editorialTheme REQ-24). 색은 버튼 글자를 물려받아 흐리게:
   토큰 색을 박으면 검정 알약 위에서 대비가 무너진다. 폰(639px 이하)엔 외장 키보드가 드물어 숨긴다.
   흐리기는 .8이 바닥 — 가장 어두운 조합(다크 공부 파랑 #8FA9BE 위 #1C1A17)이 .8에서 4.92:1, .7이면 3.98:1로 AA 4.5 미달이었다. */
.focus-kbd { margin-left: 8px; font: inherit; font-size: 13px; opacity: .8; }
@media (max-width: 639px) { .focus-kbd { display: none; } }
.focus-top .dash-goal-edit { flex-basis: 100%; justify-content: flex-start; margin-top: 10px; }
/* 탭을 떠나 멈춘 안내 — 폼과 같은 자리(막대 아래 한 줄)의 조용한 문장. 움직임 없음(정적 표현이 기본값, T-176). */
.focus-away { flex-basis: 100%; margin: 10px 0 0; font-size: 13px; color: var(--muted); }
.focus-away .dash-bookless { display: inline; padding: 0 2px; }
.focus-away .focus-away-close { margin-left: 10px; }
/* 자리 비움 선택(설계 §9) — 대기 패널 맨 끝 조용한 설정 줄(위 점선 구분). 체크박스는 설정 .set-check-box와 같은 상자(아래 설정 절에서 셀렉터 공유). */
.dash-away-pref { display: flex; align-items: flex-start; gap: 8px; padding-top: 12px; border-top: 1px dashed var(--border); cursor: pointer; }
.dash-away-pref-title { display: block; font-size: 13px; color: var(--text); }
.dash-away-pref-desc { display: block; margin-top: 3px; font-size: 13px; line-height: 1.5; color: var(--muted); word-break: keep-all; }
.focus-stack.is-merged .study-editor .ProseMirror { min-height: max(300px, calc(100vh - 464px)); font-size: 16px; }
/* 전환 — 히어로는 먼저 빠지고 막대는 조금 늦게 들어온다(둘이 반투명으로 겹쳐 뿌예지는 구간 제거, 시안 실측) */
::view-transition-group(*) { animation-duration: .6s; animation-timing-function: cubic-bezier(.22, .9, .24, 1); }
::view-transition-group(focus-top), ::view-transition-group(focus-notes) { overflow: clip; }
::view-transition-old(focus-top) { animation-duration: .26s; animation-fill-mode: both; }
::view-transition-new(focus-top) { animation-delay: .24s; animation-duration: .36s; animation-fill-mode: both; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .6s; }
@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none; }
}

/* 카드 사이 간격 — 공유 #dashboard-app gap(16px) 위에 대시보드만 여유롭게.
   특이도 (1,1,1) > #dashboard-app (1,0,0)이라 history/books/personality엔 회귀 0. (N-115) */
body.dashboard-page #dashboard-app { gap: 20px; }

/* 헤더 사용자영역 (brand 로고는 dashboard.html SSR 유지 — 로고 중복 0) */
.dash-header-user { display: flex; align-items: center; justify-content: flex-end; gap: 12px; margin-bottom: 4px; }
.dash-header-text { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.2; }
.dash-header-name { font-family: var(--font-serif); font-weight: 500; font-size: 16px; color: var(--text); }
.dash-header-name strong { color: var(--accent-hover); }
.dash-header-sub { font-size: 13px; color: var(--muted); }
/* 아바타 = 사용자 메뉴 토글 버튼(클릭 가능). 전역 button{width:100%}은 width:42px 고정(클래스 특이도)으로 상쇄. */
.dash-header-avatar {
    width: 42px; height: 42px; border-radius: 50%; flex-shrink: 0;
    background: transparent; color: var(--text);   /* 사람은 선으로만 선다 — 색은 표지(천 장정)의 몫(미니앱 Avatar) */
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-serif); font-weight: 500; font-size: 18px;
    padding: 0; border: 1px solid var(--text); cursor: pointer; appearance: none;
    overflow: hidden;   /* 작가 스프라이트를 원형으로 클립 */
    transition: background .15s ease;
}
.dash-header-avatar:hover { background: var(--sage-hover); }
.dash-header-avatar:focus-visible { outline: 2px solid var(--accent-hover); outline-offset: 2px; }
/* 아바타 드롭다운 — 설정·문의·로그아웃 일원화. wrap이 절대배치 기준. */
.dash-header-menu-wrap { position: relative; flex-shrink: 0; }
.dash-header-menu {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 30;
    min-width: 168px; padding: 6px;
    background: var(--card-bg); border: 1px solid var(--text);
    border-radius: 2px;
    display: flex; flex-direction: column; gap: 2px;
}
/* a·button 공용 한 줄 항목. button은 전역 width:100%가 여기선 곧 풀폭 행이라 그대로 둠. */
.dash-header-menu-item {
    width: 100%; box-sizing: border-box;
    display: flex; align-items: center; gap: 10px;
    padding: 10px 12px; border-radius: 2px;
    background: transparent; border: none; cursor: pointer;
    color: var(--text); font-family: inherit; font-size: 14px; text-align: left;
    text-decoration: none; transition: background .15s ease;
}
.dash-header-menu-item:hover { background: var(--bg); }
.dash-header-menu-item svg { flex-shrink: 0; color: var(--muted); }
/* 로그아웃은 구분선으로 위 두 항목과 시각적 분리 */
.dash-header-menu-logout { margin: 4px 0 0; padding-top: 4px; border-top: 1px solid var(--border); }
.dash-header-menu-logout .dash-header-menu-item { color: var(--muted); }
.dash-header-menu-logout .dash-header-menu-item:hover { color: var(--text); }

.dash-card-link { font-size: 13.5px; color: var(--accent-hover); text-decoration: none; }
.dash-card-link:hover { text-decoration: underline; }
/* 모드 스위치 — 페이지 단위(타이머 카드·아래 카드·세로 바)라 카드 밖 화면 아래 가운데에 띄운다(2026-09-17 D안).
   비홈 화면의 SSR 알약(fragments/side-rails)도 이 규칙들을 그대로 쓴다 — 공부 잉크는 #side-rails 토큰 상속(설계 2026-09-17-single-rail-mode-switch).
   z 94 = 바(95) 아래 · 칩·스킵링크(100) 아래(옛 종이 결 90은 에디토리얼에서 걷었다).
   PWA 설치 칩(pwa-install.js — bottom 72px+safe-area, 띠 72~109px)과는 세로 띠가 다르다(여긴 16~55px) — 가로 폭·바 유무와 무관하게 안 겹친다.
   좁은 창에서 펼친 바가 힌트 칩에 닿으면 바가 이긴다(힌트는 일시적). 공부 잉크는 .is-study 스코프 스왑을 그대로 탄다
   (ModeToggle이 공부 모드에 is-study를 붙인다 — 다크·독서등판 0줄). 잠김은 버튼만 옅게 —
   떠 있는 종이 자체를 반투명으로 두면 밑 콘텐츠가 비쳐 깨진 것처럼 보인다. 전역 button{width:100%; 잉크 테}는 width:auto·border:0으로 상쇄. */
.dash-mode-toggle-wrap {
    position: fixed; left: 0; right: 0; bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    z-index: 94; width: max-content; margin-inline: auto;
    display: flex; flex-direction: column-reverse; align-items: center; gap: 6px;   /* 힌트(DOM 뒤)가 알약 위에 선다 */
}
/* 떠 있는 것 = 종이 + 잉크 1px(그림자 0) · 그릇 모서리 999(탭바) · 고른 칸은 탭과 같은 잉크 2px 밑줄(미니앱 Home 모드 스위치).
   overflow: hidden — 고른 칸 밑줄(칸 폭 전체)이 둥근 끝 밖으로 2~4px 나가지 않게 그릇이 자른다(시안 사양서 §8.6 R2). */
.dash-mode-toggle {
    display: inline-flex; padding: 0; border-radius: 999px; overflow: hidden;
    background: var(--card-bg);
    border: 1px solid var(--text);
}
.dash-mode-toggle button {
    width: auto; padding: 8px 18px; border: 0; border-radius: 0;
    background: transparent; color: var(--muted); font: inherit; font-size: 13px; font-weight: 400; cursor: pointer;
}
/* 비홈 SSR 알약(fragments/side-rails)은 첫 페인트 전에 JS 없이 눌림이 맞아야 해서 속성 셀렉터로도 같은 선언을 받는다 */
.dash-mode-toggle button[aria-pressed="true"],
#side-rails[data-mode="study"] .dash-mode-toggle [data-pick="study"],
#side-rails:not([data-mode="study"]) .dash-mode-toggle [data-pick="reading"] { background: none; color: var(--accent); font-weight: 500; box-shadow: inset 0 -2px 0 var(--accent); }
.dash-mode-toggle.is-locked button { opacity: .5; cursor: not-allowed; }
.dash-mode-hint { padding: 4px 10px; border-radius: 2px; background: var(--card-bg); border: 1px solid var(--border); font-size: 13px; color: var(--muted); }
/* 마지막 콘텐츠(명언·광고·폼 버튼·편집기 하단)가 스위치 밑에 깔리지 않게 — body 기본 32 + 스위치 띠 상단 55 + 숨 13.
   스위치가 바 있는 화면 전부에 뜨므로(홈 Vue · 비홈 SSR) 여백도 바 있는 화면 전부. 스크롤 중 겹침은 고정 요소의 본성이라 범위 밖. */
body.has-rails { padding-bottom: calc(100px + env(safe-area-inset-bottom, 0px)); }
/* 브라우저가 스스로 정하는 스크롤(Tab 포커스·글자 입력 캐럿)도 같은 띠를 비킨다 — 안 주면 창 맨 아래 끝에 맞춰 알약 밑에 깔린다
   (2026-10-17 실측: 4폭 Tab 포커스 일부 가림 10건 → 0). 스크롤 루트가 html이라 body 클래스를 :has로 올려 읽는다.
   편집기(ProseMirror)는 이걸 안 읽어 RecallEditor.vue scrollMargin에 같은 100을 따로 둔다. */
:root:has(> body.has-rails) { scroll-padding-bottom: calc(100px + env(safe-area-inset-bottom, 0px)); }

/* 공부 잉크 — 카드 스코프 토큰 스왑(미니앱 body.study-mode의 카드 한정판, 값은 그쪽과 같다 — editorialTheme.test.ts 대조).
   대시보드 카드(.dash-card)와 /study/history의 .card가 같은 클래스를 쓴다 — 규칙 하나가 두 화면을 덮는다.
   에디토리얼(2026-10 PR-2): **강조 자리만** 파란 잉크(#2B4A6F — 종이 8.00, 그 위 미색 8.00)로 갈아 끼우고 종이·면·선·본문 잉크는
   낮 값을 그대로 상속한다(옛 푸른 히어로 면·칩 면·숫자 리터럴 규칙은 걷었다). 주 버튼은 --accent-fill을 따르니 저절로 파란 알약,
   잔디는 파란 잉크 농담 사다리(미니앱 --grass1~4). 0단(기록 없음)은 종이 쪽 그대로. */
.is-study, #side-rails[data-mode="study"], body.study-lamp .lamp-page .is-study {
    --accent: #2B4A6F; --accent-hover: #2B4A6F; --ok: #2B4A6F;
    --accent-fill: #2B4A6F; --accent-hover-2: #2B4A6F; --ok-fill: #2B4A6F;
    --grass-1: #B8C3D1; --grass-2: #8598B0; --grass-3: #4F6A8B; --grass-4: #2B4A6F;
}

/* 공부 서재(/study/books) — 회독 칩은 토큰만 쓰므로 .is-study 카드 안에서 저절로 파랑이다(리터럴 없음).
   ± 버튼은 .book-actions 규칙(padding·width:auto)을 그대로 받고, 여기선 가로 정렬만 얹는다 —
   .book-actions보다 뒤에 오므로 같은 특이성에서도 이 줄이 이긴다. */
.study-read-chip {
    display: inline-block; width: fit-content;
    padding: 2px 9px; border-radius: 999px; font-size: 13px;
    background: transparent; color: var(--text); border: 1px solid var(--border);
}
.study-count-actions { display: flex; gap: 6px; align-items: center; }

/* 공부 책별 회당 시간 — 히어로 인라인 편집(2026-09-13, 하루 목표 대체). 전부 공부 카드 안 클래스라 독서엔 0줄이다.
   전역 button{width:100%; padding:12px 18px; 잉크 테}보다 특이성이 한 단 위(0,1,0 / 0,2,0)라
   여기 선언이 이긴다 — .dash-mode-toggle button이 쓰는 것과 같은 관용구(font:inherit 뒤에 font-size). */
.dash-goal-change {
    width: auto; padding: 0 6px; border: 0; background: transparent;
    color: var(--accent-hover); font: inherit; font-size: 13px;
    text-decoration: underline; cursor: pointer;
}
/* 칩 아래 「회당 50분 · 변경」 줄 — 칩·「책 없이 시작」과 같은 가운데 축. */
.dash-session-goal { align-self: center; font-size: 13px; color: var(--muted); }
/* 닿으면 색만 바뀐다(애니메이션 없음) — 측정은 계속된다. .is-study가 --ok를 덮어 공부 파란 잉크(#2B4A6F)다. */
.dash-session-line.is-reached .dash-kv-k,
.dash-session-line.is-reached .dash-kv-v { color: var(--ok); }
/* 폼은 우측 패널(.dash-state-panel, 좁은 폭에서 ≈420px) 안 손잡이 바로 아래에 선다 — 패널 폭을 넘지 않고
   (min-width:0) 한 줄에 안 들어가면 버튼 단위로 줄바꿈하며 칩·손잡이와 같은 가운데 축에 모인다.
   라벨은 「이 책 회당 시간 [ ] 분」이 한 덩어리로 넘어가게 줄바꿈을 막는다. */
.dash-goal-edit { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; min-width: 0; }
.dash-goal-edit label { white-space: nowrap; font-size: 13px; color: var(--muted); }
.dash-goal-edit input[type="number"] { width: 5.5em; }
/* 전역 button{width:100%} 상쇄 — 한 줄에 나란히 세운다(보조 둘은 .dash-bookless가 이미 width:auto). */
.dash-goal-edit .dash-btn-outline { width: auto; padding: 9px 16px; margin-top: 0; }

/* ============================================================
   인증 화면(로그인·회원가입) — claude.ai/design 시안 재이식.
   전역 공유 클래스(.card·.field·.btn-primary·.alert·.oauth-계열·.entry-hero 등)는
   landing·onboarding·password-*·verify-email-*·unsubscribe- 등 형제 페이지가 공유하므로
   절대 건드리지 않는다. 이 블록은 body.auth-page 스코프 전용 클래스(.auth-*)로만 구성 →
   타 페이지 회귀 0. 픽셀값 출처: 시안 프레임 1~6(로그인 기본/회원가입 기본/로그인 에러/
   가입직후 안내/로그아웃 안내/회원가입 필드에러). 색은 :root 토큰 재사용, 토큰 없는
   에러톤(테라코타 #B0524A 계열)만 raw hex. */
.auth-page .auth-shell {
    width: 100%;
    max-width: 400px;   /* 시안 콘텐츠 컬럼(480 - 좌우 40 패딩) — 페이지 스코프 폭(전역 .container 무손상) */
}

/* 브랜드 워드마크 — 책 라인아이콘 + 'BookTimer'(명조 22px) */
.auth-page .auth-brand {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 26px;
}
.auth-page .auth-brand-ico { flex: 0 0 auto; color: var(--accent); }
.auth-page .auth-brand-name {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 22px;
    line-height: 1;
    color: var(--text);
    letter-spacing: .01em;
}

/* 로그인 화면 소제목('로그인') */
.auth-page .auth-greeting {
    font-size: 15px;
    color: var(--muted);
    margin: 0 0 18px;
}

/* 회원가입 히어로 — 명조 25px 제목 + 서브카피(나머지는 본문 고딕) */
.auth-page .auth-hero { margin: 0 0 22px; }
.auth-page .auth-hero-title {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 25px;
    line-height: 1.45;
    color: var(--text);
    margin: 0 0 8px;
    word-break: keep-all;
}
.auth-page .auth-hero-sub {
    font-size: 14px;
    line-height: 1.6;
    color: var(--muted);
    margin: 0;
    word-break: keep-all;
}

/* 카드 */
.auth-page .auth-card {
    background: var(--card-bg);
    border: 0;
    border-radius: 0;
    padding: 26px 0;
}

/* 필드 */
.auth-page .auth-field { margin-bottom: 18px; }
.auth-page .auth-field:last-of-type { margin-bottom: 20px; }
.auth-page .auth-label {
    display: block;
    font-size: 13px;
    color: var(--text);
    margin-bottom: 6px;
}
.auth-page .auth-input,
.auth-page .auth-select {
    width: 100%;
    padding: 13px 15px;
    border: 1px solid var(--muted);
    border-radius: 2px;
    background: transparent;
    font-family: inherit;
    font-size: 15.5px;
    color: var(--text);
    outline: none;
}
.auth-page .auth-input:focus,
.auth-page .auth-select:focus {
    border-color: var(--text);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
/* 필드 에러 — 입력 테두리를 빨강으로(서버 검증 실패 시 th:classappend로 토글). 빨강 링은 걷었다(이펙트 0). */
.auth-page .auth-input.is-error,
.auth-page .auth-select.is-error {
    border-color: var(--danger);
}

/* 셀렉트 — 기본 화살표 제거 + 커스텀 chevron */
.auth-page .auth-select-wrap { position: relative; }
.auth-page .auth-select {
    padding-right: 40px;
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
}
.auth-page .auth-select-chevron {
    position: absolute;
    right: 14px;
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    color: var(--muted);
}

/* 입력 보조 힌트 — 아이디 힌트만 강조색(--accent-hover), 나머지는 --muted */
.auth-page .auth-hint {
    display: block;
    margin-top: 6px;
    font-size: 13px;
    line-height: 1.6;
    color: var(--muted);
    word-break: keep-all;
}
.auth-page .auth-hint-accent { color: var(--accent-hover); }
.auth-page .auth-check-hint { margin-left: 26px; margin-top: 7px; }  /* 체크박스(17) + gap(9) 아래로 정렬 */

/* 필드 에러 메시지(th:errors가 채움) */
.auth-page .auth-field-error {
    display: block;
    margin-top: 6px;
    font-size: 13px;
    line-height: 1.6;
    color: var(--danger-ink-2);
    word-break: keep-all;
}

/* 마케팅 동의 체크 행 */
.auth-page .auth-check {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    cursor: pointer;
}
.auth-page .auth-check input[type="checkbox"] {
    width: 17px;
    height: 17px;
    margin: 2px 0 0;
    accent-color: var(--accent);
    flex-shrink: 0;
}
.auth-page .auth-check-label {
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--text);
}

/* 주 버튼(로그인/가입) */
.auth-page .auth-btn-primary {
    width: 100%;
    padding: 14px;
    border: 1px solid var(--accent-fill);
    border-radius: 999px;
    background: var(--accent-fill);
    color: var(--on-accent);   /* 검정 알약 — 로그인·가입 화면의 주 행동 하나 */
    font-family: inherit;
    font-weight: 500;
    font-size: 16px;
    cursor: pointer;
    transition: opacity .15s ease;
}
.auth-page .auth-btn-primary:hover { opacity: .88; }

/* 구분선 '또는' */
.auth-page .auth-divider {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 18px 0;
}
.auth-page .auth-divider::before,
.auth-page .auth-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--border);
}
.auth-page .auth-divider span {
    font-size: 13px;
    color: var(--muted);
}

/* Google 버튼 — 좌측 멀티컬러 G 로고 + '계속하기' */
.auth-page .auth-btn-google {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    width: 100%;
    padding: 13px;
    border: 1px solid var(--text);
    border-radius: 999px;
    background: transparent;
    color: var(--text);
    font-family: inherit;
    font-size: 15px;
    text-decoration: none;
    cursor: pointer;
    transition: background .15s ease;
}
.auth-page .auth-btn-google:hover { background: var(--sage-hover); }
.auth-page .auth-btn-google svg { flex: 0 0 auto; }

/* 알림 배너 — 에러/성공/로그아웃 (아이콘 + 텍스트) */
.auth-page .auth-alert {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 11px 14px;
    border-radius: 2px;
    margin-bottom: 16px;
    font-size: 13.5px;
    line-height: 1.6;
    word-break: keep-all;
}
.auth-page .auth-alert svg { flex: 0 0 auto; }
.auth-page .auth-alert-error  { background: var(--danger-soft); color: var(--danger-ink-2); }
.auth-page .auth-alert-ok     { background: var(--sage-soft); color: var(--ok); }
.auth-page .auth-alert-logout { background: var(--sage-soft); color: var(--text); }
.auth-page .auth-alert-logout svg { color: var(--accent); }  /* 로그아웃 아이콘 = 잉크(accent) */

/* 하단 링크 — 중앙정렬 세로 스택 */
.auth-page .auth-links {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 11px;
    margin-top: 20px;
    text-align: center;
}
.auth-page .auth-links a {
    font-size: 13.5px;
    color: var(--accent);
    text-decoration: none;
}
.auth-page .auth-links a:hover { text-decoration: underline; }
.auth-page .auth-links a.auth-link-muted { color: var(--muted); }
.auth-page .auth-link-accent { color: var(--accent); }

/* ============================================================
   설정 페이지 재스킨 — claude.ai/design 시안(설정.decoded.html) 이식.
   전역 공유 클래스(.card·.field·.btn-primary·.btn-danger·.alert·.link-row·.check-row·
   .status-line·.danger-zone·.verify-banner·.btn-inline-link 등)는 로그인·가입·온보딩·
   비번재설정 등 형제 페이지가 공유하므로 절대 건드리지 않는다. 이 블록은 body.settings-page
   스코프 + .set-* 클래스로만 구성 → 타 페이지 회귀 0(auth-page 재스킨과 같은 격리 규약).
   색은 :root 토큰 재사용, 토큰 없는 경고(#F6ECD9/#8A6D3B)·위험(#C0524A 계열) 톤만 raw hex(시안값).
   ============================================================ */

/* 셸 — 시안 프레임 폭(480) */
.settings-page .set-shell { max-width: 480px; margin: 0 auto; padding: 20px 18px 40px; }

/* (이전의 .settings-page [hidden] 스코프 리셋은 전역 [hidden]{display:none!important}로 승격돼 제거 — 파일 상단 리셋 참조) */

/* 헤더 — 톱니(왼쪽·장식) + 제목. 상단 .brand(홈 링크)는 전역 스타일 그대로 사용. */
.settings-page .set-header { display: flex; align-items: center; gap: 10px; padding: 6px 2px 18px; }
.settings-page .set-title { font-family: var(--font-serif); font-weight: 500; font-size: 26px; margin: 0; color: var(--text); }
.settings-page .set-header-ico { display: flex; color: var(--accent-hover); }

/* 카드 */
.settings-page .set-card { background: var(--card-bg); border: 0;
    border-radius: 0; padding: 24px 0; margin-bottom: 16px; }
/* 위험 카드도 테 0 — 위험 신호는 머리 글자·버튼의 빨강이 진다. */
.settings-page .set-card-danger { margin-bottom: 20px; }
/* 섹션 머리 — 명조 22/30 + 잉크 1px 선(.card h2와 같은 문법) */
.settings-page .set-card-title { font-family: var(--font-serif); font-weight: 500; font-size: 22px; line-height: 30px; margin: 0 0 18px; color: var(--text); padding-bottom: 8px; border-bottom: 1px solid var(--text); }
.settings-page .set-card-title-danger { color: var(--danger-ink); margin-bottom: 8px; }
.settings-page .set-card-desc { margin: 0 0 18px; font-size: 13px; color: var(--muted); line-height: 1.5; word-break: keep-all; }
.settings-page .set-card-danger .set-card-desc { font-size: 13px; line-height: 1.55; }
.settings-page .set-card-disabled { position: relative; }
.settings-page .set-card-overlay {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    text-align: center;
    background: var(--scrim-3);
    border-radius: inherit;
    font-weight: 500;
    color: var(--text);
}

/* 필드 */
.settings-page .set-field { margin-bottom: 16px; }
.settings-page .set-label { display: block; font-size: 13px; font-weight: 500; margin-bottom: 7px; color: var(--text); }
.settings-page .set-input,
.settings-page .set-select {
    width: 100%; background: transparent; border: 1px solid var(--muted);
    border-radius: 2px;
    padding: 12px 14px; font-family: inherit; font-size: 15px; color: var(--text);
    outline: none; transition: border-color .15s, box-shadow .15s;
}
.settings-page .set-input:focus,
.settings-page .set-select:focus { border-color: var(--text); box-shadow: 0 0 0 3px var(--focus-ring); }
/* 위험 입력칸 — 빨강 테(옛 --danger-line은 새 종이 위 ≈ 1.4라 3:1 미달). 빨강 링은 걷었다. */
.settings-page .set-input-danger { border-color: var(--danger); }
.settings-page .set-input-danger:focus { border-color: var(--danger); box-shadow: 0 0 0 3px var(--focus-ring); }

/* select — 기본 화살표 제거 + 커스텀 chevron */
.settings-page .set-select-wrap { position: relative; }
.settings-page .set-select { appearance: none; -webkit-appearance: none; padding-right: 40px; cursor: pointer; }
.settings-page .set-select-chevron { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); pointer-events: none; color: var(--muted); display: flex; }

/* 힌트 · 필드 에러 */
.settings-page .set-hint { display: block; margin-top: 7px; font-size: 13px; color: var(--muted); line-height: 1.5; word-break: keep-all; }
.settings-page .set-field-error { display: block; margin-top: 7px; font-size: 13px; color: var(--danger-ink); line-height: 1.5; }

/* 저장 버튼(우측 정렬 pill) / 위험 버튼(전체폭 pill) */
.settings-page .set-actions { display: flex; justify-content: flex-end; margin-top: 20px; }
/* 설정 저장 = 외곽선 알약 — 한 화면에 폼이 여섯이라 하나를 고를 수 없다(검정 알약은 한 층에 하나 · REQ-22). */
.settings-page .set-btn-save { width: auto; background: transparent; color: var(--text); border: 1px solid var(--text); border-radius: 999px; padding: 11px 24px; font-family: inherit; font-size: 14px; font-weight: 500; cursor: pointer; transition: background .15s; }
.settings-page .set-btn-save:hover { background: var(--sage-hover); }
/* 「휴대폰에서 토스 앱 열기」는 button이 아니라 a라 버튼 모양을 직접 갖춘다 — inline이라 padding이
   눌리고 밑줄이 남는다. 나머지 색·모양은 위 규칙을 그대로 탄다. */
.settings-page a.set-btn-save { display: inline-block; text-decoration: none; }
.settings-page .set-btn-danger { width: 100%; background: transparent; color: var(--danger); border: 1px solid var(--danger); border-radius: 999px; padding: 12px 24px; font-family: inherit; font-size: 14px; font-weight: 500; cursor: pointer; transition: background .15s; }
.settings-page .set-btn-danger:hover { background: var(--danger-soft); }

/* 커스텀 체크박스(밀린시간 합산 / 복귀 메일 · 공부 홈 「자리 비우면 멈추기」) — 실제 <input>은 숨기고 박스 span으로 그린다.
   공부 홈도 같은 규칙을 탄다 — 브라우저 기본 흰 상자는 종이 위에서 혼자 흰 면이었다(에디토리얼 PR-4). */
.settings-page .set-check { display: flex; align-items: flex-start; gap: 11px; cursor: pointer; }
.settings-page .set-check--card { background: var(--card-bg); border: 0;
    border-radius: 0; padding: 14px 0; }
.settings-page .set-check input[type="checkbox"],
.dash-away-pref input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0; }
.settings-page .set-check-box,
.dash-away-pref .set-check-box {
    flex-shrink: 0; width: 22px; height: 22px; border-radius: 2px; border: 1.6px solid var(--accent);
    background: var(--surface); display: flex; align-items: center; justify-content: center; margin-top: 1px;
    color: var(--on-accent); transition: background .15s;
}
.settings-page .set-check-box svg,
.dash-away-pref .set-check-box svg { opacity: 0; }
.settings-page .set-check input:checked ~ .set-check-box,
.dash-away-pref input:checked ~ .set-check-box { background: var(--accent); }
.settings-page .set-check input:checked ~ .set-check-box svg,
.dash-away-pref input:checked ~ .set-check-box svg { opacity: 1; }
.settings-page .set-check input:focus-visible ~ .set-check-box,
.dash-away-pref input:focus-visible ~ .set-check-box { outline: 2px solid var(--accent-hover); outline-offset: 2px; }
.settings-page .set-check-body { flex: 1; }
.settings-page .set-check-title { display: block; font-size: 14px; font-weight: 500; color: var(--text); }
.settings-page .set-check-title-row { display: flex; align-items: center; gap: 7px; }
.settings-page .set-check-desc { display: block; margin-top: 5px; font-size: 13px; color: var(--muted); line-height: 1.5; word-break: keep-all; }

/* 광고 배지 */
.settings-page .set-badge { font-size: 13px; color: var(--neutral-3-3); border: 1px solid var(--border);
    border-radius: 999px; padding: 1px 7px; white-space: nowrap; }

/* 플래시(아이콘 + 텍스트) */
.settings-page .set-alert { display: flex; align-items: center; gap: 10px; border-radius: 2px; padding: 12px 14px; margin-bottom: 16px; font-size: 13.5px; line-height: 1.5; word-break: keep-all; }
.settings-page .set-alert svg { flex-shrink: 0; }
.settings-page .set-alert-ok { background: var(--sage-soft); border: 1px solid var(--sage-line); color: var(--ok-ink); }
.settings-page .set-alert-ok svg { color: var(--ok-fill); }
.settings-page .set-alert-error { background: var(--danger-soft-5); border: 1px solid var(--danger-line-4); color: var(--danger-ink-deep-3); }
.settings-page .set-alert-error svg { color: var(--danger-ink); }

/* 이메일 미검증 배너(경고 톤) */
.settings-page .set-banner { display: flex; align-items: flex-start; gap: 10px; background: var(--warn-bg); border: 1px solid var(--warn-border); color: var(--warn-fg); border-radius: 2px; padding: 13px 14px; margin-bottom: 16px; font-size: 13px; line-height: 1.5; }
.settings-page .set-banner-ico { flex-shrink: 0; margin-top: 1px; }
.settings-page .set-banner-body { flex: 1; }
.settings-page .set-banner-body form { margin: 6px 0 0; }
.settings-page .set-banner-link { width: auto; background: none; border: none; padding: 0; font: inherit; color: var(--warn-fg); font-weight: 500; font-size: 13px; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }

/* 알림 행 */
.settings-page .set-notif-row { display: flex; align-items: flex-start; gap: 12px; padding: 14px 0; }
.settings-page .set-notif-text { flex: 1; }
.settings-page .set-notif-name { font-size: 14px; font-weight: 500; color: var(--text); }
.settings-page .set-notif-name-row { display: flex; align-items: center; gap: 7px; }
.settings-page .set-notif-desc { margin-top: 5px; font-size: 13px; color: var(--muted); line-height: 1.5; word-break: keep-all; }
.settings-page .set-notif-divider { height: 1px; background: var(--line-1); }
.settings-page .set-notif-subhint { display: flex; align-items: flex-start; gap: 6px; margin-top: 8px; font-size: 13px; color: var(--neutral-3-3); line-height: 1.5; }
.settings-page .set-notif-subhint svg { flex-shrink: 0; margin-top: 1px; }
.settings-page .set-notif-mail { padding-top: 14px; }
.settings-page .set-notif-mail .set-actions { margin-top: 16px; }

/* ═══════════════ 여백 (책에 딸린 자리 — 2026-08-16 책 귀속 재설계) ═══════════════
   .story-* / .margin-* 전용 네임스페이스 — 전역 공유 클래스 미접촉(기존 페이지 격리 규약).
   z 층: 도감 50 < 여백 패널/작성 150 < 신고 모달 200 (옛 뷰어의 층을 그대로 계승).
   옛 인스타 문법(스트립 링·풀스크린 뷰어·진행바·열람자 시트)의 스타일은 함께 폐기했다. */

/* ── 책 리스트 표지 발광 — 24시간 안에 여백에 새 글이 달린 책(.shop-book 안) ──
   ⚠️ 맥동(pulse) 폐기 (2026-08-16, 실기기 회귀). `box-shadow`는 GPU 합성이 안 되는 속성이라 무한
   애니메이션하면 매 프레임 그 영역을 다시 페인트하는데, 이 클래스가 붙는 칸이 표지 이미지를 감싸고 있어
   초당 60번 표지를 재래스터화했다. 미니앱(iOS WebView)에서 앱 전반이 느려지고 페인트가 밀려 「버튼이
   안 보이는데 눌리는」 상태까지 갔다. 웹은 데스크톱이라 증상이 약하지만 원인이 같아 함께 걷어낸다.
   정지 테두리 + 점 배지만으로 「새 글 있음」은 충분히 전달된다(사용자 결정). 움직임이 없어졌으므로
   prefers-reduced-motion 분기도 함께 사라졌다. 자세한 경위는 miniapp/src/global.css의 같은 절. */
.shop-cover-wrap { position: relative; flex: 0 0 auto; display: block; }
.shop-cover-wrap.margin-fresh {
    border-radius: 2px;
    outline: 2px solid var(--accent); outline-offset: 2px;
}
.margin-fresh-dot {
    position: absolute; top: -4px; right: -4px;
    width: 10px; height: 10px; border-radius: 50%;
    background: var(--accent); box-shadow: 0 0 0 2px var(--card-bg);
}
/* 「여백」 손잡이 — 상태 배지 줄(.shop-book-foot)의 작은 칩 버튼 */
.shop-margin-btn {
    width: auto; /* 전역 button width:100% 상쇄 */
    background: none; border: 1px solid var(--text);
    border-radius: 999px;
    color: var(--text); font-size: 13px; font-weight: 500;
    padding: 3px 10px; cursor: pointer; appearance: none;
}
.shop-margin-btn:hover { background: var(--sage-hover); }

/* ── 배경 팔레트 — 닫힌 코드 6색(백엔드 Story.BG_CODES와 일치) ── */
.story-bg-paper  { background: #f6f1e7; color: #2c2a24; }
.story-bg-night  { background: #1f2233; color: #f2f2f6; }
.story-bg-forest { background: #23402f; color: #eef5ee; }
.story-bg-sunset { background: #c96a4a; color: #fff7ef; }
.story-bg-sea    { background: #2b5d73; color: #eef7fa; }
.story-bg-plum   { background: #5a3b5e; color: #f7eef8; }
/* 종이 프리셋(#f6f1e7)은 새 종이와 대비 1.01이라 카드·견본이 사라진다 — 흐린 글자색 1px 테(미니앱 PR-4와 같은 처방). 다른 5색은 면이 곧 경계. */
.margin-card.story-bg-paper, .story-composer-preview.story-bg-paper, .story-swatch.story-bg-paper { border: 1px solid var(--muted); }

/* ── 여백 패널 (책 하나의 글 목록 오버레이 — 옛 풀스크린 뷰어 자리) ── */
.margin-overlay {
    position: fixed; inset: 0; z-index: 150;
    background: var(--scrim);
    display: flex; align-items: center; justify-content: center; padding: 16px;
}
.margin-panel {
    width: 100%; max-width: 480px; background: var(--card-bg); border: 1px solid var(--text);
    border-radius: var(--radius); padding: 20px;
    display: flex; flex-direction: column; gap: 10px;
    max-height: 90dvh; overflow-y: auto;
}
.margin-head { display: flex; align-items: flex-start; gap: 12px; }
.margin-book-cover { width: 44px; height: 64px; font-size: 18px; }
.margin-book-meta { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.margin-book-title { font-size: 15px; font-weight: 500; color: var(--text); line-height: 1.4; }
.margin-book-sub { font-size: 13px; color: var(--muted); }
.margin-close {
    margin-left: auto; background: none; border: none; cursor: pointer;
    color: var(--text); font-size: 18px; line-height: 1; padding: 6px;
    width: auto; /* 전역 button width:100% 상쇄 — 안 하면 헤더 오른쪽 전체가 투명 닫기 히트존 */
}
.margin-count { margin: 6px 0 0; font-size: 13px; color: var(--muted); }
.margin-compose { justify-content: center; }
.margin-empty { margin: 8px 0 0; font-size: 14px; color: var(--muted); line-height: 1.6; }
/* 빈 여백(글 0건)만 판화 + 명조 문장 — 실패·불러오는 중엔 없다(오류 화면에 장식 0). */
.margin-empty.is-blank { margin-top: 24px; font-family: var(--font-serif); font-size: 16px; line-height: 26px; text-align: center; word-break: keep-all; }
.margin-empty.is-blank .woodcut { margin-bottom: 16px; }
.margin-cards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.margin-card { border-radius: 2px; padding: 16px; }
.margin-card-text {
    margin: 0; font-family: var(--font-serif); font-size: 16px; line-height: 1.75;
    white-space: pre-wrap; word-break: break-word;
}
/* 책에서 옮긴 문장 — 主인 주석보다 작고 옅게. 본문이 이미 명조라 서체로는 못 가르고,
   currentColor 세로선이라 팔레트 6색을 그대로 탄다(색을 박으면 어두운 배경에서 사라진다). */
.margin-card-quote {
    margin: 0 0 14px; padding-left: 12px; border-left: 2px solid currentColor; border-radius: 0;
    font-family: var(--font-serif); font-size: 15px; line-height: 1.7; opacity: .82;
    white-space: pre-wrap; word-break: break-word;
}
.margin-card-foot {
    display: flex; align-items: center; gap: 8px; margin-top: 12px;
    font-size: 13px; opacity: .78;
}
.margin-card-age { flex: 1; min-width: 0; }
.margin-card-btn {
    width: auto; /* 전역 button width:100% 상쇄 — 안 하면 카드 하단 전체가 삭제/신고 히트존 */
    background: none; border: 1px solid currentColor; border-radius: 999px;
    color: currentColor; font-size: 13px; padding: 3px 10px; cursor: pointer; appearance: none;
}
.margin-card-btn:disabled { opacity: .5; cursor: not-allowed; }
/* 좋아요 — 색을 currentColor로 상속한다. 배경 팔레트가 6종이고 그중 sunset이 붉은 주황(#c96a4a)이라
   빨간 하트는 거기서 사라진다. 카드 본문 색을 쓰면 여섯 배경 전부에서 읽히는 것이 보장되고,
   상태 구분은 색이 아니라 채움 여부가 진다. */
.margin-card-like { display: inline-flex; align-items: center; flex: 0 0 auto; }
.margin-like-ico { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; }
.margin-card-like.is-liked .margin-like-ico { fill: currentColor; }
/* 「좋아요 N명」 — 하트(누르기)와 갈라 아래 줄에 둔다. 한 버튼이 둘을 겸하면 명단을 보려다 좋아요가
   눌리고, 푸터에 넷째 칸으로 넣으면 좁은 폭에서 접힌다. */
.margin-card-likes {
    width: auto; /* 전역 button width:100% 상쇄 — 안 하면 카드 하단 전체가 명단 히트존 */
    margin-top: 8px; padding: 4px 0 0;
    background: none; border: none; color: currentColor;
    font-size: 13px; opacity: .78; text-decoration: underline; cursor: pointer; appearance: none;
}
/* 명단은 카드 안에 접혀 든다 — 패널(z-150) 위에 또 오버레이를 얹지 않는다(새 z 층 발명 금지). */
.margin-likers { list-style: none; margin: 6px 0 0; padding: 0; }
.margin-likers .book-row { padding: 6px 0; border: none; background: none; }
.margin-likers .book-title, .margin-likers .book-author { color: currentColor; }
.margin-likers .book-author { opacity: .78; }
.margin-likers-note { font-size: 13px; opacity: .78; padding: 6px 0; }

/* ── 작성 모달 ── */
.story-composer-overlay {
    position: fixed; inset: 0; z-index: 150;
    background: var(--scrim);
    display: flex; align-items: center; justify-content: center; padding: 16px;
}
.story-composer-panel {
    width: 100%; max-width: 420px; background: var(--card-bg); border: 1px solid var(--text);
    border-radius: var(--radius); padding: 20px;
    display: flex; flex-direction: column; gap: 12px;
    max-height: 90dvh; overflow-y: auto;
}
.story-composer-head { display: flex; align-items: center; justify-content: space-between; }
.story-composer-title { margin: 0; font-weight: 500; font-size: 16px; }
.story-composer-preview { border-radius: 2px; padding: 14px; }
.story-composer-input {
    width: 100%; background: none; border: none; resize: vertical;
    color: inherit; font-family: var(--font-serif); font-size: 17px; line-height: 1.7;
    outline: none; min-height: 120px;
}
.story-composer-input::placeholder { color: inherit; opacity: .55; }
/* 인용 칸 — 카드의 인용 블록과 같은 모양이라, 쓰는 동안 보이는 것이 그대로 결과가 된다 */
.story-composer-quote {
    padding-left: 12px; border-left: 2px solid currentColor; border-radius: 0;
    font-size: 15px; min-height: 0;
}
.story-composer-label { margin: 0 0 4px; font-size: 13px; opacity: .6; }
.story-composer-rule { height: 1px; background: currentColor; opacity: .15; margin: 14px 0; }
.story-composer-meta { display: flex; justify-content: flex-end; gap: 10px; }
.story-composer-count { font-size: 13px; color: var(--muted); }
.story-composer-count.over { color: var(--danger-ink-deep-4); }
.story-composer-swatches { display: flex; gap: 10px; }
.story-swatch {
    width: 32px; height: 32px; border-radius: 50%; cursor: pointer;
    border: 2px solid var(--border); padding: 0; appearance: none;
}
.story-swatch.selected { box-shadow: 0 0 0 2px var(--card-bg), 0 0 0 4px var(--accent); }
/* 어느 책의 여백인지 — 진입점이 이미 그 책이라 선택 select 자리는 라벨 한 줄로 대체됐다 */
.story-composer-hint { margin: 0; font-size: 13px; color: var(--muted); }
.story-composer-submit { justify-content: center; }
.story-composer-submit:disabled { opacity: .5; cursor: not-allowed; }

/* 신고 모달의 글 원문 발췌 컨텍스트 표시 */
.story-report-context {
    margin: 0; font-size: 13px; color: var(--muted);
    background: var(--bg); border-radius: 2px; padding: 8px 10px;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ── 공부 화면(/study) — 달력 + 일정 원장 ─────────────────────────────────
   미니앱 공부 달력과 같은 의미론이다: 자동 정보는 「그날 측정이 있었나」(점)까지,
   지킴 여부는 수동 표시(원), 목표 대비 달성 배지는 그리지 않는다(V80 주석). */
.study-monthbar { display: flex; align-items: center; justify-content: center; gap: 14px; margin: 4px 0 12px; }
.study-month { margin: 0; font-size: 18px; font-weight: 500; white-space: nowrap; }
/* 전역 button{width:100%}가 달 내비 화살표를 늘려 제목을 세 줄로 접는다 — 이 줄만 되돌린다 */
.study-monthbar .btn { width: auto; flex: 0 0 auto; }
.study-error { color: var(--danger); }
.study-weekdays, .study-grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.study-weekdays { margin-bottom: 4px; }
.study-weekdays span { text-align: center; font-size: 13px; color: var(--muted); }
.study-grid { gap: 2px; }
.study-cell {
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    /* 그리드 항목의 기본 min-width:auto가 긴 일정 문구에 밀려 1fr 트랙을 벌린다 —
       그러면 칸 너비가 제각각이 되고 요일 머리글(별도 그리드)과 열이 어긋난다. 0으로 눌러야
       .study-plan의 말줄임이 실제로 걸린다. */
    min-width: 0;
    min-height: 62px; padding: 4px 2px;
    background: none; border: 1px solid transparent; border-radius: 2px;
    color: inherit; font: inherit; cursor: pointer;
}
.study-cell.is-selected { border-color: var(--accent); background: var(--sage-soft); }
.study-cell.is-today .study-mark { font-weight: 500; }
/* 미래 칸 — 일정은 보이되 지킴 표시만 잠근다(탭하면 그날이 열리기만 한다) */
.study-cell.is-locked { cursor: default; }
.study-cell.is-locked .study-mark { color: var(--muted); }
.study-cell:disabled { opacity: .55; }
.study-mark {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; border-radius: 50%;
    border: 1px solid transparent; font-size: 13px; line-height: 1;
}
.study-mark.is-kept { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.study-mark.is-missed { border-color: var(--accent-hover); color: var(--accent-hover); }
.study-dot { display: inline-block; width: 4px; height: 4px; border-radius: 50%; background: var(--accent-hover); }
.study-plan {
    max-width: 100%; font-size: 13px; color: var(--muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.study-flags { display: flex; gap: 3px; }
.study-flag {
    font-size: 13px; line-height: 1.4; padding: 0 3px; border-radius: 2px;
    background: var(--sage-soft); color: var(--accent-hover);
}
.study-legend {
    display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: center;
    margin: 12px 0 4px; font-size: 13px; color: var(--muted);
}
.study-legend span { display: inline-flex; align-items: center; gap: 5px; }
.study-legend-mark { width: 12px; height: 12px; border-radius: 50%; border: 1px solid var(--accent-hover); }
.study-legend-mark.is-kept { background: var(--accent); border-color: var(--accent); }

/* 입력칸 — 다른 폼 화면(.field · .fb-field)과 같은 재료(흐린 글자색 1px · 2px)다. 새 값을 만들지 않는다.
   ⚠️ type을 열거하는 것은 일부러다: 사진 탭의 file 입력에 프레임을 씌우면 브라우저가 그리는
   「파일 선택」 버튼이 종이 테두리 안에 갇혀 테두리가 두 겹으로 보인다. */
.study-day input[type="text"],
.study-day input[type="date"],
.study-day input[type="number"],
.study-day textarea,
.study-day select {
    width: 100%;
    box-sizing: border-box;
    font: inherit;
    padding: 9px 11px;
    border: 1px solid var(--muted);
    border-radius: 2px;
    background: transparent;
    color: var(--text);
}
.study-day input:focus,
.study-day textarea:focus,
.study-day select:focus {
    outline: none;
    border-color: var(--text);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.study-day ::placeholder { color: var(--muted); opacity: 1; }

/* 책 고르기 — OS 기본 화살표를 걷고 직접 그린 chevron을 얹는다(.auth-select-wrap과 같은 방식). */
.study-select-wrap { position: relative; display: block; }
.study-day .study-select-wrap select { padding-right: 38px; appearance: none; -webkit-appearance: none; cursor: pointer; }
.study-select-chevron {
    position: absolute; right: 13px; top: 50%; transform: translateY(-50%);
    pointer-events: none; color: var(--muted);
}

.study-day { margin-top: 8px; display: flex; flex-direction: column; gap: 14px; }
.study-day-title { margin: 0; font-size: 16px; }
.study-day-label { margin: 0 0 6px; font-size: 13px; color: var(--muted); }
.study-day-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.study-day-list li {
    display: flex; align-items: center; gap: 8px;
    padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg);
}
.study-day-subject { flex: 0 0 auto; font-size: 13px; color: var(--muted); }
.study-day-task { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.study-day-ai { margin: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.study-day-ai .btn { width: auto; flex: 0 0 auto; }
.study-day-form { display: flex; flex-direction: column; gap: 8px; }
.study-day-form input, .study-day-book { width: 100%; }
.study-day-form .btn { align-self: flex-start; width: auto; }
.study-day-list .btn { width: auto; flex: 0 0 auto; }
/* 하루 패널의 「이 날의 백지노트」 링크 — <p> 기본 여백이 패널 gap에 더해지고, a는 inline이라 밑줄이 남았다(실측 2026-09-16). */
.study-day-block { margin: 0; }
.study-day-block a.btn { display: inline-flex; align-items: center; width: auto; text-decoration: none; }

/* 백지복습 — 쓰는 자리가 화면의 주인공이라 본문 textarea만 크게 두고 나머지는 눌러 둔다. */
.study-recall { display: flex; flex-direction: column; gap: 8px; }
/* 두 묶음 — /study에선 display:contents로 래퍼가 사라져 옛 한 줄 세로 배치 그대로다(side·main이
   .study-recall의 flex 아이템이 되고, 각자도 gap 8px라 간격이 같다). 홈의 넓은 폭에서만 2열이 된다. */
.study-recall-split { display: contents; }
.study-recall-side, .study-recall-main { display: flex; flex-direction: column; gap: 8px; }
.study-recall input, .study-recall textarea, .study-recall-book { width: 100%; }
/* 본문 편집기(Tiptap) — 종이 한 장. 안쪽 글은 .ProseMirror가 그리니 여기선 상자와 서식만 정한다.
   ⚠️ 옛 28px 줄노트 배경은 걷었다(2026-09-09). 제목·목록·인용이 들어오면서 줄 높이가 블록마다
   달라져 격자와 글줄이 어긋났다 — 줄과 글이 어긋난 노트는 안 그린 것만 못하다. */
.study-editor {
    position: relative;
    box-sizing: border-box;
    border: 1px solid var(--muted);
    border-radius: 2px;
    background: transparent;
    color: var(--text);
}
/* 포커스 링은 안쪽 contenteditable이 받으므로 상자가 대신 표시한다(.study-day input:focus와 같은 처방). */
.study-editor:focus-within {
    border-color: var(--text);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
/* 폰에서 키보드가 올라와도 툴바가 남게 sticky — 스크롤되는 것은 글이지 도구가 아니다.
   좌우 4px margin은 옛 연필선 보호 몫이 남은 것이다(1px 테에선 무해하다 — 툴바 배경이 편집기와 같은 --card-bg). */
.study-editor-toolbar {
    position: sticky; top: 0; z-index: 2;
    display: flex; flex-wrap: wrap; gap: 2px;
    margin: 0 4px;
    padding: 5px 6px;
    border-bottom: 1px solid var(--border);
    border-radius: 0;
    background: var(--card-bg);
}
.study-editor-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; padding: 0;
    border: 0; border-radius: 2px; background: transparent; color: var(--muted); cursor: pointer;
}
.study-editor-btn:hover:not(:disabled), .study-editor-btn.is-on { background: var(--sage-soft); color: var(--accent-hover); }
.study-editor-btn:disabled { opacity: .35; cursor: default; }

.study-editor-body { position: relative; }
/* Placeholder 확장을 하나 더 넣는 대신 빈 문서일 때만 겹쳐 그린다. */
.study-editor-placeholder {
    position: absolute; top: 10px; left: 12px; margin: 0;
    color: var(--muted); pointer-events: none;   /* 불투명도 0 — 흐린 글자에 또 흐림을 걸면 종이 위 3.32(시안 사양서 §14 ⓓ) */
}
.study-editor .ProseMirror {
    min-height: 196px;
    padding: 10px 12px;
    outline: none;
    line-height: 1.7;
    overflow-wrap: anywhere;
}
.study-editor .ProseMirror > * { margin: 0 0 8px; }
.study-editor .ProseMirror > :last-child { margin-bottom: 0; }
/* 제목 — 본문(16px 고딕)과 세 축으로 갈라 둔다: 크기 · 위 여백 · 서체.
   ⚠️ 옛 `h1 19px / h2 16px`은 본문이 16px이라 H2가 본문과 완전히 같은 크기였고, H1도 1.19배였다.
   서체를 명조로 가르는 것이 핵심이다 — 옛 본문 고운돋움은 400 단일 face라 제목의 굵게가
   합성 볼드로 흐려졌다. 지금 명조는 Noto Serif KR 500 face가 @import에 실려
   있어 합성 없이 서고, 표지·인용·명언이 이미 쓰는 이 레포의 장식 축이라 새 서체도 아니다.
   줄높이를 본문 1.7에서 내리는 것은 26px×1.7=44px로 벌어져 제목 한 줄이 문단처럼 보이기 때문. */
.study-editor .ProseMirror h1 {
    font-family: var(--font-serif); font-weight: 500;
    font-size: 26px; line-height: 1.35; margin-top: 20px;
}
.study-editor .ProseMirror h2 {
    font-family: var(--font-serif); font-weight: 500;
    font-size: 19.5px; line-height: 1.4; margin-top: 14px;
}
/* 종이 첫 줄이 제목이면 위 여백은 빼야 한다 — 안 그러면 글이 아래로 내려앉아 보인다.
   `> :first-child`(0-3-0)가 위 제목 규칙(0-2-1)을 특이도로 이기니 순서에 기대지 않는다. */
.study-editor .ProseMirror > :first-child { margin-top: 0; }
.study-editor .ProseMirror ul, .study-editor .ProseMirror ol { padding-left: 22px; }
/* 자손 선택자인 것이 일부러다 — 체크 목록은 `li > label + div > p` 구조라 자식(>) 규칙이 안 닿아
   항목마다 UA 기본 1em 여백이 살아나고, 목록 하나가 문단 여럿처럼 벌어진다. */
.study-editor .ProseMirror li p { margin: 0; }
/* 중첩 단계가 눈에 보여야 Tab을 쓴 보람이 있다. */
.study-editor .ProseMirror ul ul { list-style: circle; }
.study-editor .ProseMirror ul ul ul { list-style: square; }
.study-editor .ProseMirror ol ol { list-style: lower-alpha; }
.study-editor .ProseMirror ol ol ol { list-style: lower-roman; }
.study-editor .ProseMirror ul[data-type="taskList"] { list-style: none; padding-left: 2px; }
.study-editor .ProseMirror ul[data-type="taskList"] li { display: flex; align-items: baseline; gap: 8px; }
.study-editor .ProseMirror ul[data-type="taskList"] li > div { flex: 1 1 auto; min-width: 0; }
.study-editor .ProseMirror mark { background: var(--sage-soft); color: inherit; border-radius: 2px; padding: 0 2px; }
.study-editor .ProseMirror blockquote { border-left: 3px solid var(--border); padding-left: 10px; color: var(--muted); }
.study-editor .ProseMirror hr { border: 0; border-top: 1px solid var(--border); margin: 12px 0; }
/* 필기 사진 — 노드는 인라인 원자다(editor/noteImage.ts). 1568px 원본이 카드 밖으로 나가지 않게 폭·높이를 묶는다.
   테는 두르지 않는다: .study-editor 아래 border 색은 muted·text·danger뿐이다(editorialTheme.test.ts REQ-09).
   인라인 그대로 두는 이유: 블록으로 그리면 사진 앞뒤 캐럿이 안 보이는 브라우저가 있다 — 폭 100% 사진은 어차피 한 줄을 혼자 쓴다.
   ProseMirror의 빈 img.ProseMirror-separator도 이 선택자에 걸리지만 Tiptap이 주입한 !important 0×0 규칙이 이긴다. */
.study-editor .ProseMirror img { vertical-align: bottom; max-width: 100%; max-height: 480px; height: auto; border-radius: var(--radius-sm); }
.study-editor .ProseMirror img.ProseMirror-selectednode { box-shadow: 0 0 0 3px var(--focus-ring); }
.study-editor-image-status:empty { margin: 0; }

/* 슬래시 메뉴 — 캐럿 좌표는 컴포넌트가 인라인 style로 준다(tippy·floating-ui를 안 넣는 이유).
   ⚠️ fixed인 것이 일부러다: 좌표를 뷰포트 기준으로 계산하면(slashPosition) 조상 상자가 무엇이든
   화면 밖으로 나갈 수 없다. absolute였을 때는 좌표를 잰 상자와 먹는 상자가 달라 툴바 높이만큼
   밀렸고, 캐럿이 화면 아래쪽이면 팝업이 화면 밖(+82px 실측)이었다. */
.study-editor-slash {
    position: fixed; z-index: 5; margin: 0; padding: 4px; list-style: none;
    min-width: 148px; max-height: 220px; overflow-y: auto;
    border: 1px solid var(--text); border-radius: 2px;
    background: var(--card-bg);
}
.study-editor-slash-item {
    display: block; width: 100%; padding: 7px 10px; text-align: left;
    border: 0; border-radius: 2px; background: transparent; color: var(--text); font: inherit; cursor: pointer;
}
.study-editor-slash-item:hover, .study-editor-slash-item.is-on { background: var(--sage-soft); color: var(--accent-hover); }
.study-recall-scope { resize: vertical; }
.study-recall-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.study-recall-actions .btn { width: auto; flex: 0 0 auto; }
/* 타이핑 / 사진 — 탭 둘뿐이라 별도 컴포넌트 없이 눌린 버튼 하나로 현재 자리를 표시한다. */
.study-recall-tabs { display: flex; gap: 6px; }
.study-recall-tabs .btn { width: auto; flex: 0 0 auto; }
.study-recall-tabs .btn.is-active { border-color: var(--accent); color: var(--accent); font-weight: 500; }
.study-recall-photo { display: flex; flex-direction: column; gap: 8px; }
.study-recall-photo .btn { align-self: flex-start; width: auto; }
.study-recall-photo-list { margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 8px; }
.study-recall-photo-list li { display: flex; flex-direction: column; gap: 4px; align-items: center; }
.study-recall-photo-list img {
    width: 96px; height: 96px; object-fit: cover;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
}
/* 「고쳐 주세요」가 이 화면의 필수 단계라, 안내를 문구 하나가 아니라 눈에 띄는 띠로 둔다. */
.study-recall-transcribed {
    margin: 0; padding: 8px 10px; border-radius: var(--radius-sm);
    border: 1px solid var(--accent); background: var(--sage-soft);
}
.study-recall-heading { margin: 10px 0 4px; font-size: 13px; color: var(--muted); }
.study-recall-summary { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.study-recall-list { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 4px; }
.study-recall-list li { overflow-wrap: anywhere; }
.study-recall-yesterday, .study-recall-result {
    border: 1px solid var(--border); border-radius: 2px; padding: 10px 12px; background: var(--sage-soft);
}

/* 채점 기준 카드 — 「무엇과 대조해 구멍을 찾는가」. 결과 카드(.study-recall-result)와 같은 결이되
   바탕을 깔지 않는다: 이건 입력 쪽 정보라 옆의 책·주제·범위와 한 묶음으로 읽혀야 한다. */
.study-recall-reference { border: 1px solid var(--border); border-radius: 2px; padding: 8px 12px 10px; }
.study-recall-reference-list {
    margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 2px; font-size: 14px;
}
.study-recall-reference-list li { overflow-wrap: anywhere; }
/* 빠진 장 경고는 muted로 두지 않는다 — 조용한 누락을 막으려고 세운 줄이라 눈에 걸려야 한다. */
.study-recall-reference-cut { color: var(--text); }

/* 필기 — 목록 열 없이 편집기가 카드 폭 전체를 쓴다(2026-09-17). 지난 필기는 제목 줄 「최근 필기」 팝오버와
   빈 필기의 「이어 쓰기」 칩으로 간다. 상태줄은 이 화면에서 저장 버튼을 대신하므로 비어 있어도 자리를
   차지한다(min-height) — 글자가 들고 날 때마다 편집기가 위아래로 뛰면 쓰던 자리를 잃는다.
   ⚠️ .study-recall-split 규칙은 백지노트(/study/recall)가 쓴다 — 필기는 그 래퍼를 안 쓸 뿐 규칙은 그대로다. */
.study-notes { display: flex; flex-direction: column; gap: 8px; }
.study-notes input { width: 100%; }
/* 필기 책 이름 — 옛 숨김 라벨(.study-day-label)과 같은 값. 새 클래스라 홈의 display:none 규칙에 안 걸린다. */
/* 머리 줄 — 책 이름 + 「최근 필기 ▾ | ＋ 새 필기」(2026-09-29). 버튼은 테두리 없는 글자 버튼이라 제목 칸과 키를 겨루지 않는다.
   누르는 자리 44px은 지키되 위아래 음수 여백으로 줄 높이는 글자만큼만 먹는다(오른쪽은 카드 여백으로 살짝 걸친다).
   팝오버는 이 줄 기준으로 오른쪽 끝에 맞춘다 — 버튼 기준이면 폰에서 280px 목록이 화면 왼쪽 밖으로 나간다. */
.study-notes-head { position: relative; display: flex; align-items: center; gap: 2px; margin: -6px -8px -6px 0; }
.study-notes-book {
    flex: 1 1 auto; min-width: 0; margin: 0; font-size: 13px; color: var(--muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.study-notes-action {
    flex: 0 0 auto; width: auto; min-height: 44px; padding: 0 8px;
    display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
    border: 0; border-radius: 2px;
    font-size: 14px; color: var(--accent-hover);
}
.study-notes-action:hover { background: var(--sage-soft); }
/* 줄에서 자리를 받는 것은 버튼이 아니라 이 감싸개다 — 옛 규칙이 버튼에만 flex를 걸어 감싸개가 줄어든 것이 세로 꺾임의 뿌리였다. */
.study-notes-recent { flex: 0 0 auto; }
.study-notes-sep { flex: 0 0 auto; width: 1px; height: 14px; background: var(--border); }
/* 편집기 툴바(sticky, z-index 2) 위에 뜬다. */
.study-notes-recent-menu {
    position: absolute; right: 0; top: calc(100% + 6px); z-index: 5;
    min-width: 280px; max-width: 360px; padding: 8px;
    display: flex; flex-direction: column; gap: 8px;
    border: 1px solid var(--text); border-radius: 2px; background: var(--card-bg);
}
.study-notes-recent-menu .btn { align-self: flex-start; text-decoration: none; }
/* 이어 쓰기 칩 — 안내문구(top 10px + 한 줄) 아래 빈자리에 겹쳐 그린다. 절대 배치라 편집기 높이가 안 변한다(설계 D9).
   상자는 클릭을 통과시키고(빈 곳을 누르면 편집기에 캐럿) 칩만 받는다. */
.study-editor-empty-slot { position: absolute; top: 48px; left: 12px; right: 12px; pointer-events: none; }
.study-notes-chips { display: flex; flex-wrap: wrap; gap: 6px; }
/* 이어 쓰기 칩 — 가는 선 알약(전역 button의 잉크 테를 칩 선으로 낮춘다). */
.study-notes-chip {
    pointer-events: auto; width: auto; padding: 6px 12px;
    border: 1px solid var(--border); border-radius: 999px;
    background: var(--card-bg); color: var(--muted);
    font: inherit; font-size: 13px; font-weight: 400; text-decoration: none; cursor: pointer;
}
.study-notes-chip:hover { background: var(--sage-soft); }
.study-notes-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 4px; }
.study-notes-item {
    display: flex; flex-direction: column; gap: 2px; width: 100%; text-align: left;
    padding: 7px 10px; border: 1px solid var(--border); border-radius: 2px;
    background: transparent; color: inherit; font: inherit; cursor: pointer;
    text-decoration: none;   /* 필기 화면(/study/notes)에선 이 행이 <a>다 */
}
.study-notes-item.is-active { border-color: var(--accent); background: var(--sage-soft); }
.study-notes-label { overflow-wrap: anywhere; }
.study-notes-meta { font-size: 13px; color: var(--muted); }
.study-notes-status { min-height: 18px; }

/* AI 일정 생성 — 폼 → 미리보기 → 적용 */
.study-day-planbtn { align-self: flex-start; width: auto; }
.study-plan-form { display: flex; flex-direction: column; gap: 8px; }
.study-plan-form input[type="text"], .study-plan-form textarea, .study-plan-book { width: 100%; }
.study-plan-scope { resize: vertical; }
.study-plan-form > .btn { align-self: flex-start; width: auto; }
.study-plan-row { display: flex; flex-wrap: wrap; gap: 10px; }
/* 작은 캡션 크기는 <span>에만 준다 — label에 두면 위 `font: inherit`을 타고 값 입력칸까지 13px로
   끌어내려, 같은 폼의 다른 칸(18px)과 글씨 크기가 어긋난다. 13px은 이름표의 크기이지 값의 크기가 아니다. */
.study-plan-row label { display: flex; flex-direction: column; gap: 4px; }
.study-plan-row label > span { font-size: 13px; color: var(--muted); }
.study-plan-row input { width: 100%; max-width: 180px; }
.study-plan-preview {
    border: 1px solid var(--border); border-radius: 2px; padding: 10px 12px; background: var(--sage-soft);
}
.study-plan-heading { margin: 0 0 6px; font-size: 13px; color: var(--muted); }
.study-plan-week + .study-plan-week { margin-top: 8px; }
.study-plan-week-label { margin: 0 0 2px; font-size: 13px; font-weight: 500; color: var(--muted); }
.study-plan-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 3px; }
.study-plan-list li { display: flex; gap: 8px; align-items: baseline; }
.study-plan-date { flex: 0 0 auto; font-variant-numeric: tabular-nums; color: var(--muted); font-size: 13px; }
.study-plan-task { overflow-wrap: anywhere; }
.study-plan-replace { margin-top: 10px; }
.study-plan-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.study-plan-actions .btn { width: auto; flex: 0 0 auto; }

/* 테마 토글 — theme.js가 header.brand / header.auth-brand 끝에 꽂는다. 가는 선 원 아이콘 버튼.
   width를 고정하는 것은 전역 `button { width: 100% }`를 상쇄하기 위한 것이다. */
.theme-toggle {
    width: 32px;
    height: 32px;
    flex: 0 0 auto;
    margin-left: auto;      /* .brand가 flex라 우측으로 민다 */
    align-self: center;     /* .brand의 align-items: baseline 상쇄 — 아이콘엔 baseline이 없다 */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--card-bg);
    color: var(--accent-hover);
    cursor: pointer;
}
.theme-toggle:hover { background: var(--nav-hover-bg); border-color: var(--nav-hover-border); }
.theme-toggle:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
.theme-toggle svg { width: 18px; height: 18px; }

/* ── 세로 바(side rail) — 설계 claude-docs/plans/2026-09-15-web-side-rails.md · 2026-09-17-single-rail-mode-switch.md ──
   로그인 사용자 화면의 페이지 이동 단일 출처(fragments/side-rails). 왼쪽 바 하나 — 안의 독서·공부 nav 중
   #side-rails[data-mode]가 가리키는 쪽만 보인다(공부면 .is-study 토큰을 #side-rails가 상속으로 준다).
   오른쪽 여백 124는 바가 없어도 대칭으로 둔다 — 본문 중앙 정렬과 아래 2열 경계 1100(바 여백 248에서 유도)을 지킨다.
   평소 92px 접힘. 펼침(232px, 본문 위에 덮음)은 `.is-open`(rail.js — 데스크톱 머묾·태블릿 탭)과
   `:focus-within`(키보드) 한 벌뿐이다. `.rail:hover` 펼침 규칙은 두지 않는다 — hover로 펼치면 안의 가로 배치가
   즉시 뒤집혀 스치기만 해도 글자가 깨져 보인다(머묾 지연은 rail.js 타이머가 맡는다).
   z-index 95 = 첫 오버레이(100) 아래. 접힌 바는 면 + 오른쪽 가는 선, 펼친 바는 떠 있는 것(종이 + 잉크 1px). */
body.has-rails { padding-left: 124px; padding-right: 124px; }   /* 16 + 92 + 16 */

/* ── 본문 폭(바 있는 화면) — 설계 claude-docs/plans/2026-09-15-web-wider-body.md
   웹은 데스크톱·태블릿 전용이라 바가 붙는 화면은 기본이 넓다(1160 — 1440 창의 가용 폭 1192에 딱 든다).
   목록·폼·글 한 열짜리 화면만 .narrow-page(720)다 — 1160이면 「팔로우」 버튼·시간이 1100px 밖으로 떨어진다.
   바 없는 화면(에러·약관·비밀번호·온보딩·관리자)은 위 .container 460 그대로 — 이 절은 body.has-rails 접두를 벗지 않는다.
   페이지별 .container max-width는 여기 말고 두지 않는다(ContainerWidthTest가 허용 목록으로 막는다).
   예외 하나: body.history-page.history-wide .container 940 — JS split(layout.ts)과 짝이라 남긴다(0,3,1이라 이 기본 0,2,1을 이긴다).
   데스크톱 경계 1100 = 바 여백 248을 뺀 852가 2열(책장 340+목록 2열 · 책방 360+메인 · 기록 1.45fr/1fr)이 서는 최소 폭.
   books @media · profile isWide(ProfileApp.vue) · history SPLIT_MIN_WIDTH(layout.ts) · 대시보드 안쪽 경계가 전부 이 수다.
   폼 상한 620은 넓은 화면에서만 — 입력 한 칸이 1100px이면 되레 쓰기 나쁘다. 좁은 단은 카드 안쪽 672라 걸면 아래 목록과 어긋난다. */
body.has-rails .container { max-width: 1160px; }
body.has-rails .container.narrow-page { max-width: 720px; }
body.has-rails .container:not(.narrow-page) .book-search-form,
body.has-rails .container:not(.narrow-page) .book-manual-form,
body.has-rails .container:not(.narrow-page) .study-day-form,
body.has-rails .container:not(.narrow-page) .study-plan-form { max-width: 620px; }
/* 본문으로 건너뛰기 — 평소엔 화면 위로 밀어 두고 포커스를 받을 때만 내려온다.
   .sr-only는 포커스해도 1px로 남아 쓸 수 없다. 색은 전부 토큰이라 독서등(body.study-lamp가 --card-bg·--text·
   --accent·--focus-ring을 덮는다)에서도 따라온다. z-index 100 = 바(95) 위 — 포커스 순간 바에 가리면 안 된다. */
.skip-link {
    position: fixed;
    top: -80px;
    left: 16px;
    z-index: 100;
    padding: 10px 18px;
    border-radius: 2px;
    background: var(--card-bg);
    border: 1px solid var(--accent);
    color: var(--text);
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
}
.skip-link:focus { top: 16px; outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }

.rail {
    position: fixed;
    top: 16px;
    bottom: 16px;
    left: 16px;
    width: 92px;
    z-index: 95;
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    overflow-x: hidden;   /* 펼침 전이 중 가로 넘침만 자른다 */
    overflow-y: auto;     /* 짧은 창·확대 배율에서 아래 메뉴(사용자 검색)가 잘리지 않고 스크롤된다 */
    padding: 18px 8px;
    border-radius: 0;
    background-color: var(--card-bg);
    border: 0;
    border-right: 1px solid var(--border);
    transition: width .18s ease;
}
/* 지금 모드의 메뉴만 — 속성 부재 = 독서(JS 꺼짐·저장소 예외에서도 독서 메뉴가 뜬다). 반대쪽은 display:none이라 접근성 트리에서도 빠진다 */
#side-rails[data-mode="study"] .rail-nav-reading, #side-rails:not([data-mode="study"]) .rail-nav-study { display: none; }
.rail nav { display: flex; flex-direction: column; gap: 6px; }
.rail-pill { align-self: center; margin-bottom: 8px; padding: 5px 12px; border-radius: 999px; font-size: 13px; white-space: nowrap; background: var(--sage-soft); color: var(--accent-hover); }
.rail-item { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 10px 4px; border-radius: 2px; border: 1px solid transparent; color: var(--text); font-size: 13px; line-height: 1.3; text-align: center; white-space: nowrap; text-decoration: none; }
.rail-item svg { width: 22px; height: 22px; flex: 0 0 auto; color: var(--accent-hover); }
.rail-item[aria-current="page"] { background: none; border-color: transparent; color: var(--text); font-weight: 500; box-shadow: inset 2px 0 0 var(--text); }
@media (hover: hover) and (pointer: fine) { .rail-item:hover:not([aria-current]) { background: var(--nav-hover-bg); text-decoration: none; } }
.rail-item:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
/* 펼침 — 데스크톱 머묾·태블릿 탭(둘 다 rail.js의 is-open)·키보드(focus-within) 셋이 같은 모양 */
/* 펼친 바 = 떠 있는 것(본문 위에 덮는다) — 종이 + 잉크 1px */
#side-rails .rail.is-open, #side-rails .rail:focus-within {
    width: 232px;
    padding: 18px 12px;
    background: var(--card-bg);
    border: 1px solid var(--text);
    border-radius: 2px;
}
.rail.is-open .rail-item, .rail:focus-within .rail-item { flex-direction: row; gap: 12px; padding: 10px 14px; font-size: 15px; line-height: 1.6; text-align: left; }
.rail.is-open .rail-pill, .rail:focus-within .rail-pill { align-self: flex-start; margin-left: 8px; }
@media (prefers-reduced-motion: reduce) { .rail { transition: none; } }
/* ponytail: <640px엔 이동 수단이 브랜드 홈 링크뿐 — 폰 웹을 지원하기로 바뀌면 하단 탭바를 여기 단다(웹=데스크톱·태블릿, 2026-09-07 방침) */
@media (max-width: 639px) { .rail { display: none; } body.has-rails { padding-left: 16px; padding-right: 16px; } }

/* ── 다크 테마 ────────────────────────────────────────────
   `:root`의 색 토큰만 덮는다(raw 색 래칫 — darkTokens.test.ts — 이 토큰 밖 리터럴을 막는다). 사용자 토글(theme.js)이 켠다.

   ⚠️ `@media not print`로 통째로 감싼다 — 종이엔 항상 라이트가 나가야 한다. 다크로 인쇄하면
   잉크를 통째로 붓는 꼴이고, 대부분의 프린터 드라이버는 배경을 아예 안 그려 글자만 흰색으로 남긴다.

   특이성 메모: `[data-theme]`가 붙어 라이트 `:root`(0,1,0)보다 한 단 위(0,2,0)라 선언 순서에
   기대지 않는다. 그래도 파일 끝에 두는 것은 아래 `.is-study` 값 오버라이드들이 자기가 덮는
   라이트 규칙 '뒤'에 오게 하려는 것이다 — 나중에 누가 특이성을 같게 만들어도 순서가 받쳐준다. */
@media not print {
:root[data-theme="dark"], body.study-lamp {   /* 둘째 항목 = 독서등(공부 측정 중 홈의 밤) — 테마와 무관하게 이 팔레트 */
    /* 폼 컨트롤·스크롤바·`<input type=date>` 달력까지 네이티브 다크로 넘긴다.
       동시에 크롬 Auto Dark Theme의 표적에서도 벗어난다 — 이미 다크를 그리는 페이지는 안 뒤집는다. */
    color-scheme: dark;

    /* 에디토리얼 밤 = 「밤 책상」(D2=① — 미니앱 독서등 main 블록과 같은 값, 설계 §5-3). 낮과 1:1 짝이다(darkTokens.test.ts가
       양방향으로 센다). 면 없음 — 카드 면 = 책상이고 덩어리는 선과 여백이 가른다. 대비는 책상 #1C1A17 기준이다. */
    /* S 면 — 책상 */
    --bg: #1C1A17;
    --card-bg: #1C1A17;
    --surface: #1C1A17;
    --paper-1: #1C1A17;
    --paper-1-2: #1C1A17;
    --paper-1-3: #1C1A17;
    --paper-4: #1C1A17;
    --paper-4-2: #1C1A17;
    /* F 옅은 면 — 그 위 글자 12.40 · 흐린 5.26 */
    --sage-soft: #2C2925;
    --sage-soft-2: #2C2925;
    --paper-2: #2C2925;
    --paper-3: #2C2925;
    --paper-2-2: #2C2925;
    --paper-2-3: #2C2925;
    --info-soft: #2C2925;
    --info-soft-2: #2C2925;
    --info-soft-3: #2C2925;
    --info-soft-4: #2C2925;
    --ok-soft: #2C2925;
    --ok-soft-2: #2C2925;
    --ok-soft-3: #2C2925;
    --ok-soft-4: #2C2925;
    --ok-soft-5: #2C2925;
    --warn-bg: #2C2925;
    --warn-bg-2: #2C2925;
    --warn-bg-3: #2C2925;
    --warn-bg-4: #2C2925;
    /* H 호버 면 — 밝은 잉크 8%. 별칭을 다시 적는다 — 독서등(body.study-lamp)은 body에서 토큰을 다시 깔아
       html에서 라이트로 계산된 별칭이 그대로 상속된다(밤 바 hover 대비 1.09, 리뷰 실측). */
    --sage-hover: rgba(242, 237, 227, .08);
    --sage-hover-2: rgba(242, 237, 227, .08);
    --nav-hover-bg: var(--sage-hover);
    /* L 가는 선(장식 1.45) */
    --border: #3A3630;
    --border-2: #3A3630;
    --border-3: #3A3630;
    --border-4: #3A3630;
    --line-1: #3A3630;
    --line-1-2: #3A3630;
    --line-1-3: #3A3630;
    --line-1-4: #3A3630;
    --line-1-5: #3A3630;
    --line-1-6: #3A3630;
    --line-1-7: #3A3630;
    --line-2: #3A3630;
    --line-2-2: #3A3630;
    --sage-line: #3A3630;
    --sage-line-2: #3A3630;
    --ok-line: #3A3630;
    --ok-line-2: #3A3630;
    --ok-line-3: #3A3630;
    --warn-border: #3A3630;
    --warn-border-2: #3A3630;
    --warn-border-3: #3A3630;
    --warn-border-4: #3A3630;
    --nav-hover-border: #3A3630;
    --nav-hover-border-2: #3A3630;
    /* I 밝은 잉크 — 글자이자 강조(14.88). 밝은 알약 위 글자는 책상색(--on-accent). */
    --text: #F2EDE3;
    --accent: #F2EDE3;
    --accent-hover: #F2EDE3;
    --accent-fill: #F2EDE3;
    --accent-hover-2: #F2EDE3;
    --ok: #F2EDE3;
    --ok-fill: #F2EDE3;
    --ok-ink: #F2EDE3;
    --ok-ink-2: #F2EDE3;
    --info-ink: #F2EDE3;
    --warn-fg: #F2EDE3;
    --warn-fg-2: #F2EDE3;
    --warn-fg-3: #F2EDE3;
    --warn-fg-4: #F2EDE3;
    --warn-fg-5: #F2EDE3;
    /* T 보조(11.21) · M 흐린(6.31 — 입력칸 경계 3:1 이상) */
    --ink-2: #D6CFC2;
    --muted: #A39B8E;
    --muted-2: #A39B8E;
    --muted-3: #A39B8E;
    --neutral-3-2: #A39B8E;
    --neutral-3-3: #A39B8E;
    /* N 비글자 단계 — 1.98 / 3.70 / 6.31 */
    --neutral-1: #4F4A42;
    --sage-1: #4F4A42;
    --sage-2: #4F4A42;
    --sage-3: #4F4A42;
    --sage-4: #4F4A42;
    --neutral-2: #7A7367;
    --sage-5: #7A7367;
    --sage-6: #7A7367;
    --neutral-3: #A39B8E;
    --sage-7: #A39B8E;
    --sage-8: #A39B8E;
    --graphite: #A39B8E;
    /* O 밝은 알약 위 글자 — 책상색(14.88) */
    --on-accent: #1C1A17;
    /* R 빨강 — 옛 다크 값 유지(이미 AA). 밤 #E5766B(5.90)는 미니앱 독서등 --adaptiveRed500과 같은 값. */
    --danger: #E5766B;
    --danger-ink: #E5766B;
    --danger-ink-2: #E5766B;
    --danger-hover: #F0918A;
    --danger-ink-deep: #F0918A;
    --danger-ink-deep-2: #F0918A;
    --danger-ink-deep-3: #F0918A;
    --danger-ink-deep-4: #F0918A;
    --danger-soft: #33201D;
    --danger-soft-2: #33201D;
    --danger-soft-3: #33201D;
    --danger-soft-4: #33201D;
    --danger-soft-5: #33201D;
    --danger-line: #5A3A34;
    --danger-line-2: #5A3A34;
    --danger-line-3: #5A3A34;
    --danger-line-4: #5A3A34;
    /* G 잔디 — 밤엔 달성 쪽으로 갈수록 '밝아진다'(낮은 진해진다). 이웃 단 1.65 / 1.87 / 1.71 / 2.36. */
    --grass-0: #2C2925;
    --grass-1: #4F4A42;
    --grass-2: #7A7367;
    --grass-3: #A39B8E;
    --grass-4: #F2EDE3;
    /* X 포커스 링(밝은 잉크 50% — 합성 4.65) · 딤(어두운 화면 위에선 딤이 더 진해야 층이 보인다 — 옛 다크 값 유지) */
    --focus-ring: rgba(242, 237, 227, .5);
    --scrim: rgba(0, 0, 0, .62);
    --scrim-soft: rgba(0, 0, 0, .5);
    --scrim-2: rgba(0, 0, 0, .62);
    --scrim-3: rgba(0, 0, 0, .62);
}

/* 공부 잉크 다크 — `.is-study`가 갈아 끼우는 10개(강조 6 + 잔디 4)의 밤판. 강조 = #8FA9BE(책상 7.10, 그 위 책상색 7.10). */
:root[data-theme="dark"] .is-study, body.study-lamp .is-study,
:root[data-theme="dark"] #side-rails[data-mode="study"], body.study-lamp #side-rails[data-mode="study"] {
    --accent: #8FA9BE; --accent-hover: #8FA9BE; --ok: #8FA9BE;
    --accent-fill: #8FA9BE; --accent-hover-2: #8FA9BE; --ok-fill: #8FA9BE;
    --grass-1: #34495A;
    --grass-2: #4A6A80;
    --grass-3: #6F92AA;
    --grass-4: #A0BED0;
}

/* ── 독서등(공부) — 측정 중 홈이 밤 책상이 되고 합쳐진 카드만 종이 한 장으로 남는다(설계 2026-09-15-study-focus-lamp ·
   에디토리얼 §5-4). 밤 = 위 다크 팔레트 그대로(목록에 body.study-lamp), 종이 = 라이트 목록의 `body.study-lamp .lamp-page`.
   에디토리얼엔 광원이 없다 — 옛 불빛(::after 방사 그라데이션)·글로우를 걷었다(이펙트 0).
   ⚠️ 움직이지 않는다(T-176). 켜고 끄는 전환은 View Transition의 root 크로스페이드가 맡는다.
   ⚠️ 이 자리(다크 절 안)여야 한다 — 상속 color는 body 계산값(밤 글자)이 내려오므로 낮 토큰으로 다시 계산시킨다(시안 실측). */
body.study-lamp .lamp-page {
    color: var(--text);
}
}
