/* BookTimer — 공통 스타일 (종이톤+세이지 디자인 리프레시: 입구부터 미감 통일) */

/* 본문 폰트 — 기능 글자가 기본값(고운돋움), 장식이 opt-in.
   손글씨 '개구'(Gaegu)는 2026-09-03에 걷었다. 미니앱이 「또렷한 연필」에서 먼저 내린 결론을
   옮긴 것이고, 근거 전문은 miniapp/src/global.css의 `html body` 주석에 있다
   (그쪽 '값'을 여기 베껴 적지 않는다 — 한쪽만 고치면 나머지가 조용히 거짓이 된다).
   ⚠️ Gaegu는 폴백으로도 남기지 않는다. 남기면 고운돋움이 못 그리는 글리프만 손글씨로 떨어져
   한 단어 안에서 서체가 갈린다 — 시스템 한글 폰트로 떨어지는 쪽이 덜 이상하다.
   웹의 장식 축은 손글씨가 아니라 고운바탕(Gowun Batang)이다 — 표지·아바타 이니셜,
   여백 글·인용, 명언 각주가 전부 그 서체를 '명시'한다(상속에 기대는 자리를 두지 않는다). */
@import url('https://fonts.googleapis.com/css2?family=Gowun+Batang:wght@400;700&family=Gowun+Dodum&display=swap');

:root {
    /* 브라우저 강제 다크(크롬 Auto Dark Theme) 거부. `only`가 핵심이다 — `light`만 쓰면 그건
       「라이트만 그린다」는 사실 진술이라, UA가 보기엔 여전히 「다크를 지원하지 않는 페이지」다.
       사용자가 다크를 켜면 아래 블록이 color-scheme: dark로 덮어 이 opt-out을 스스로 푼다. */
    color-scheme: only light;
    /* 종이톤 + 세이지 그린 팔레트. 이름은 유지(무파괴), 값만 교체 → 전역 리프레시. */
    --bg: #F7F2E8;          /* 종이 배경(따뜻한 크림) — 위에 결이 옅게 얹히는 것까지 감안한 값 */
    --card-bg: #FCFAF5;     /* 카드 표면(종이톤 화이트) */
    --text: #2C2A24;        /* 잉크(따뜻한 차콜) */
    --muted: #6F6A5E;       /* 흐린 글자 */
    --accent: #6E8A6A;      /* 세이지(악센트/CTA) */
    --accent-hover: #4F6B4C;/* 딥 세이지(hover/강조·아이콘) */
    --danger: #dc2626;
    --danger-hover: #b91c1c;
    --border: #E4DDD0;      /* 따뜻한 보더 */
    --ok: #2F8F6B;          /* 타이머 달성색 — 세이지와 변별되게 더 선명한 초록으로 톤 조정 */
    --radius: 14px;
    --radius-sm: 8px;       /* 버튼·칩용 작은 라운드 */
    --shadow: 0 1px 2px rgba(60, 50, 30, .05), 0 8px 24px rgba(60, 50, 30, .06);
    /* 보조 토큰 — 랜딩부터 점진 적용(전역 강제 아님) */
    --sage-soft: #E7EEE2;   /* 연한 세이지 fill */
    /* nav hover — 대시보드 QuickNav 타일과 footer .link-row 버튼이 공유하는 hover 상태(단일 출처).
       한쪽 색만 바꿔 둘이 어긋나는 drift를 막는다. */
    --nav-hover-bg: var(--sage-soft);   /* hover 배경 = 연녹 채움(#E7EEE2) */
    --nav-hover-border: #CFE0C2;        /* hover 테두리 = 연녹 */
    /* 포커스 링 — 입력칸 focus·강조 hover가 공유(세이지 #6E8A6A=rgb(110,138,106) 기반).
       #287 토큰 교체가 못 건드린 raw 인디고 잔재를 토큰화해 전역 일관 유지. */
    --focus-ring: rgba(110, 138, 106, .30);

    /* ── 의미 토큰 — 규칙에 흩어져 있던 색 리터럴 158개의 집합소 ─────────────
       다크는 `:root`를 갈아끼워 동작하므로, 규칙에 hex를 직접 적으면 그 자리만 다크에서
       크림색으로 남는다. 그래서 자리마다 `[data-theme]` 오버라이드를 다는 대신(= 규칙마다
       두 벌을 유지하게 된다) 값을 여기로 끌어올렸다. 라이트 값은 옮겨온 리터럴 그대로다 —
       근처의 1~2단계 차이(#FBF8F1과 #FAF7EF 같은)만 한 토큰으로 합쳤다.
       ⚠️ 여기에 토큰을 더하면 아래 다크 블록에도 반드시 짝을 넣는다(darkTokens.test.ts가 운다). */
    --surface: #fff;        /* 폼·패널의 흰 표면 — 종이(--card-bg)보다 한 겹 위 */
    --on-accent: #fff;      /* accent·danger 채움 위의 글자·아이콘 */
    --paper-1: #FAF7EF;     /* 카드 안의 한 단 옅은 면(책방 카드·대시보드 패널) */
    --line-1: #EDE7DA;      /* 옅은 구분선·스켈레톤 채움 */
    --line-2: #D8CDB9;      /* 또렷한 구분선·점 */
    --sage-hover: #DDE7D8;  /* 세이지 채움의 hover */
    --sage-line: #C4D3BC;   /* 세이지 테두리 */
    --ok-soft: #E0EFE6;     /* 달성·공개 배지 채움 */
    --ok-line: #C9E3D4;
    --ok-ink: #2F5D3E;      /* 달성 문구(--ok보다 가라앉은 초록) */
    --warn-bg: #F6ECD9;     /* 주의 배너·읽고싶음 배지 */
    --warn-border: #E6D3AE;
    --warn-fg: #8A6D3B;
    --danger-soft: #F6E7E4; /* 위험 카드·오류 alert 채움 */
    --danger-line: #E4C6C2;
    --danger-ink: #C0524A;  /* 테라코타 — 인증(#B0524A)과 설정(#C0524A)에 갈려 있던 것을 합쳤다 */
    --danger-ink-deep: #A5443C; /* 그 위 한 단 진한 쪽(버튼 hover·긴 오류 문구) */
    --info-soft: #E8F0FE;   /* 파랑 정보 배지(태그·피드백 상태) */
    --info-ink: #1D4ED8;
    --ink-2: #4A463D;       /* 본문(--text)과 흐린 글자(--muted) 사이 */
    --scrim: rgba(20, 19, 16, .55);      /* 시트·모달 뒤 딤 */
    --scrim-soft: rgba(34, 32, 26, .34);

    /* ── 계열 변종 — 라이트 값은 옮기기 전 리터럴 그대로다 ────────────────────
       근접값 통합을 하지 않는다(사용자 결정 2026-09-10): 요청은 다크모드 도입이지 라이트
       재색칠이 아니다. 그래서 1/255 차이라도 제 토큰을 준다 — 「미세하니 괜찮다」를 한 번
       허용하면 라이트가 조용히 다른 화면이 된다. 숫자 접미사는 같은 계열의 서로 다른 라이트
       값이고, **다크에선 계열 대표값 하나로 모인다**(그쪽은 이번에 새로 잡은 팔레트라 통합이
       설계 의도다 — 아래 다크 블록의 같은 이름들이 전부 같은 값인 이유). */
    --warn-bg-2: #FFFBEB;        /* .cap-badge · .alert-warn */
    --warn-bg-3: #FFF6E5;        /* .warn-box */
    --warn-bg-4: #F0E8DB;        /* .shop-badge-want · 책 상태 배지(읽고싶음) */
    --warn-border-2: #FCD34D;    /* .cap-badge */
    --warn-border-3: #FDE68A;    /* .alert-warn */
    --warn-border-4: #F1D48A;    /* .warn-box */
    --warn-fg-2: #92400E;        /* .alert-warn · .btn-inline-link */
    --warn-fg-3: #B45309;        /* .cap-badge */
    --warn-fg-4: #8A6A1C;        /* .warn-box */
    --warn-fg-5: #B06A2C;        /* .missed-debt */
    --ok-soft-2: #ECFDF5;        /* .goal-badge · .alert-ok */
    --ok-soft-3: #E2F0E8;        /* .dash-pill-ok */
    --ok-soft-4: #E9F2EB;        /* .dash-state-achieved */
    --ok-soft-5: #E7F6EC;        /* .fb-resolved */
    --ok-line-2: #A7F3D0;        /* .alert-ok */
    --ok-line-3: #CFE4D6;        /* .dash-state-achieved */
    --ok-ink-2: #15803D;         /* .fb-resolved */
    --danger-soft-2: #FEF2F2;    /* .alert-error */
    --danger-soft-3: #F7ECEA;    /* .shelf-load-error */
    --danger-soft-4: #FFF0EE;    /* .shop-menu-item-danger:hover */
    --danger-soft-5: #F7E3E0;    /* .set-alert-error */
    --danger-line-2: #FECACA;    /* .alert-error · .danger-zone */
    --danger-line-3: #ECD6D2;    /* .shelf-load-error */
    --danger-line-4: #E4B7B1;    /* .set-alert-error */
    --danger-ink-2: #B0524A;     /* 인증 화면 오류(설정의 #C0524A와 갈려 있던 쪽) */
    --danger-ink-deep-2: #A6584F; /* .shelf-load-error */
    --danger-ink-deep-3: #9A3A32; /* .set-alert-error */
    --danger-ink-deep-4: #B03A2E; /* .story-composer-count.over */
    --info-soft-2: #EEF2FF;      /* .book-status-badge · .reason-chip */
    --info-soft-3: #E6F0FF;      /* .fb-read */
    --info-soft-4: #EEF5FF;      /* .fb-reply-shown */
    --line-1-2: #EFE9DC;         /* .grass-legend */
    --line-1-3: #EFE9DD;         /* 책 상세 기록 행 */
    --line-1-4: #EFEADD;         /* 스켈레톤 · 책 상태 배지 폴백 */
    --line-1-5: #F0EBDF;         /* .missed-list li */
    --line-1-6: #E9E2D4;         /* .pbti-divider · .pbti-help-note--muted */
    --line-1-7: #E8E0D2;         /* .shop-cover-ph 줄무늬 */
    --line-2-2: #D8CFBE;         /* .shelf-empty 점선 */
    --paper-1-2: #FBF8F1;        /* .shelf-empty */
    --paper-1-3: #F6F2E9;        /* .book-sheet-panel */
    --paper-2-2: rgba(0, 0, 0, .05);  /* .fb-type */
    --paper-2-3: rgba(0, 0, 0, .06);  /* .fb-submitted */
    --paper-4-2: #F2EEE4;        /* .skeleton-line.w55 */
    --border-2: rgba(0, 0, 0, .15);   /* 피드백 폼 입력칸 */
    --border-3: rgba(0, 0, 0, .08);   /* .fb-item */
    --border-4: rgba(0, 0, 0, .12);   /* .fb-filter a */
    --muted-2: rgba(0, 0, 0, .55);    /* .fb-submitted 글자 */
    --neutral-3-2: #9A917F;      /* 잔디 요일·월 라벨 */
    --neutral-3-3: #8A857A;      /* 설정 배지·부가안내·스위치 노브 */
    --sage-hover-2: #DCE8D2;     /* .shop-tag-click:hover */
    --sage-line-2: #C9D3C2;      /* .personality-badge-cand */
    --scrim-2: rgba(0, 0, 0, .45);        /* .shop-report-modal-overlay */
    --scrim-3: rgba(128, 128, 128, .45);  /* .settings-page .set-card-overlay */

    /* ── 채움 전용 토큰 — `.is-study`가 갈아끼우지 않는다 ────────────────────
       공부 카드는 --accent·--ok·--sage-soft를 파랑으로 덮는다. 그런데 origin/main은 아래 자리들을
       세이지 **리터럴**로 적어 둬서 공부 카드 안에서도 초록이었다 — 토큰으로 옮기는 순간 파랑을
       따라가 라이트 화면이 바뀐다. 그래서 같은 값의 별도 토큰을 둔다: 라이트는 어디서나 세이지,
       다크에서는 테마를 따라간다(아래 다크 블록 + 다크 `.is-study`가 짝을 맞춘다). */
    --accent-fill: #6E8A6A;        /* 연한 accent 채움(색 혼합의 원료) */
    --accent-hover-2: #4F6B4C;     /* .shop-badge-reading 글자 */
    --ok-fill: #2F8F6B;            /* 완독 배지·달성 아이콘 */
    --sage-soft-2: #E7EEE2;        /* 대시보드 칩·트랙 채움 */
    --nav-hover-border-2: #CFE0C2; /* .shop-tag-click 테두리 */
    --muted-3: #7A7566;            /* .hist-tab 비활성 글자 */
    /* 랜딩 확장 팔레트 — raw hex 산재 금지; 시안에서 추출한 중간 음영 토큰 */
    --paper-2: #EAE9DD;
    --paper-3: #ECE6D8;
    --paper-4: #F1EEE6;
    --sage-1: #E3E4D4;
    --sage-2: #D8E2D4;
    --sage-3: #D6DDC8;
    --sage-4: #B9C3A8;
    --sage-5: #B6C9AE;
    --sage-6: #A9C0A2;
    --sage-7: #8FAE86;
    --sage-8: #7E8A6E;
    --neutral-1: #CFC6B4;
    --neutral-2: #C4BCAC;
    --neutral-3: #9A9486;
    /* 잔디 5단계 — 이제 소비자는 /history·/study/history의 .grass-cell.level-* 하나다
     (대시보드 잔디는 2026-09-07에 걷었다).
       값 바꾸면 둘 다 반영(발견 7: 대비 강화). 미달→달성 순으로 진해진다. */
    --grass-0: #EAE4D7;
    --grass-1: #C3D9B0;
    --grass-2: #94BE7F;
    --grass-3: #5E9250;
    --grass-4: #35662F;

    /* ── 종이·연필 테마 (A안) ──────────────────────────────────
       흑연(연필심) 색. 기존 --border(#E4DDD0)는 남겨 두되, 테두리를 그리는 주체는
       아래 --pencil-frame으로 옮겨간다. */
    --graphite: #55504A;

    /* 연필 테두리 — 필터를 넣은 SVG를 data URI로 박아 border-image로 쓴다.
       ⚠️ 인라인 <svg>의 filter를 참조하지 않는 이유: 이 앱엔 공통 레이아웃이 없어
       36개 템플릿에 전부 <svg>를 심어야 하고, 새 페이지마다 잊으면 테두리가 사라진다.
       data URI는 CSS 한 곳으로 끝나고, 필터도 이미지 디코드 때 1회만 계산돼 더 싸다.
       (% 는 URL 인코딩과 충돌하므로 %25 로 이스케이프한다.) */
    --pencil-frame: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='a' x='-20%25' y='-20%25' width='140%25' height='140%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.5' numOctaves='4' seed='5' result='g'/%3E%3CfeColorMatrix in='g' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.55 0 0 0 0.62' result='m'/%3E%3CfeComposite in='SourceGraphic' in2='m' operator='in'/%3E%3C/filter%3E%3Cfilter id='b' x='-20%25' y='-20%25' width='140%25' height='140%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.5' numOctaves='4' seed='23' result='g'/%3E%3CfeColorMatrix in='g' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0 0 0 0.25' result='m'/%3E%3CfeComposite in='SourceGraphic' in2='m' operator='in'/%3E%3C/filter%3E%3Crect x='1.6' y='1.6' width='296.8' height='296.8' rx='7' fill='none' stroke='%2355504A' stroke-width='1.9' filter='url(%23a)'/%3E%3Crect x='2.4' y='2.4' width='295.2' height='295.2' rx='7' fill='none' stroke='%236B655C' stroke-width='1.4' filter='url(%23b)'/%3E%3C/svg%3E");
    /* 흐린 연필선 — 보조 구획(입력칸 등)이 카드와 같은 무게로 튀지 않게 */
    --pencil-frame-soft: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='a' x='-20%25' y='-20%25' width='140%25' height='140%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.5' numOctaves='4' seed='13' result='g'/%3E%3CfeColorMatrix in='g' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0 0 0 0.55' result='m'/%3E%3CfeComposite in='SourceGraphic' in2='m' operator='in'/%3E%3C/filter%3E%3Crect x='1.7' y='1.7' width='296.6' height='296.6' rx='7' fill='none' stroke='%238C857A' stroke-width='1.6' filter='url(%23a)'/%3E%3C/svg%3E");
    /* 쓰는 법: `border-image: var(--pencil-frame) 8 / 8px stretch;`
       `<slice> / <width>` 문법이 핵심이다 — slice(8)는 SVG 타일에서 잘라낼 폭, width(8px)는 화면에
       그릴 폭이고, 이 둘은 요소의 실제 `border-width`와 **독립**이다. 그래서 border-width는 1px로 두고
       그림만 8px로 그리면 테두리가 두꺼워져도 레이아웃이 1px도 밀리지 않는다(패딩 안쪽으로 그려진다).
       기존 `border: 1px solid var(--border)` 선언을 건드리지 않고 얹을 수 있는 이유가 이것이다.
       ⚠️ 선을 휘게 하는 필터(feDisplacementMap)를 쓰지 않는다 — border-image는 300px 타일을
       요소 폭에 맞춰 늘이고 줄이는데, 좁은 버튼에서는 3배 넘게 압축된다. 굴곡이 있으면 파장도 같은 배율로
       짧아져 변위가 선 두께를 넘어서고, 그 순간 선은 휘는 게 아니라 가장자리가 깎여 「픽셀이 깨진 선」이
       된다(실측 반려). 연필선의 정체는 흔들림이 아니라 **흑연이 종이 결에 걸려 생기는 농도 얼룩**이라,
       고주파 노이즈를 선의 알파에 곱해 진하기만 들쑓날롭하게 만든다. 고주파 입자는 압축돼도
       고와질 뿐이라 굴곡과 달리 지글거리지 않는다.

       ⚠️ repeat은 `stretch`다. `round`(타일 반복)를 쓰면 농도 얼룩이 타일 경계에서 어긋나
       이음매마다 줄이 보인다(feTurbulence에 stitchTiles를 안 쓴다).
       ⚠️ 이 한 벌을 `--pencil` 같은 변수로 묶어 `border-image: var(--pencil)`로 쓰면 안 된다 —
       축약형에 var()를 통째로 넣으면(그 변수가 또 var를 품으면) Chrome이 선언 전체를 무효로 버린다
       (실측: slice가 기본값 100%로 남아 테두리가 통째로 안 그려진다). slice·width·repeat은 리터럴로.

       ⚠️ 안쪽으로 그려지는 7px 띠를 배경 있는 자식·<img> 콘텐츠가 덮으면 선이 얇아진다(자식은 부모 테두리
       위에 그려진다). 선은 바깥 가장자리 0.65~3.1px에만 사니 불투명한 것은 4px 이상 띄우거나(padding·margin),
       띄울 수 없는 세그먼트류는 ::after 오버레이로 프레임을 자식 위에 얹는다(.shelf-filter-chips).
       검사: frontend/e2e/pencil-frame.spec.ts(로컬 bootRun 후 npm --prefix frontend run test:e2e). */

    /* 종이 결 — feTurbulence 노이즈 2겹(알갱이·섬유결). 이미지 파일도 요청도 0건.

       ⚠️ 노이즈를 색이 아니라 **알파**로 얹는다. 한때 무채색 회색 rect를 30% 불투명도로 깔았는데,
       그건 결이 아니라 안개다 — 회색을 30% 섞는 것은 밑에 깔린 검정을 회색으로 들어올리는 일이라,
       종이 배경 위에서는 결로 보여도 책 표지 사진 위에서는 한 겹 바랜 것처럼 반투명해진다
       (사용자 반려 2026-08-18, T-191). 글자는 대비가 커서 버티는 탓에 웹·목 모드 검증을 모두
       통과했고 표지에서만 티가 났다. feColorMatrix의 알파 행으로 옮기면(`0.9*R - 0.42`, 음수는
       0으로 클램프) 대부분의 픽셀이 완전투명이라 밑의 색을 건드리지 않고 드문 입자만 어둡게
       얹힌다 — 연필선을 「흔든 선」에서 「농도 얼룩」으로 고친 것과 같은 수법이다(T-190).

       큰 얼룩(mottle) 겹은 뺐다: 알파로 옮기면 결이 아니라 넓은 어두운 반점(때)이 된다.

   ⚠️ 알파로 옮기는 것만으로는 부족하고 **밀도**도 결의 일부다. 한때 입자가 픽셀의 61%를 덮었는데,
   그러면 종이색 토큰을 아무리 밝혀도 눈에 들어오는 건 합성 결과라 종이가 칙칙해진다 — #F3EEE4를
   깔아도 실제로 보이는 색은 #E5E0D6이었다(사용자 반려 2026-08-19, T-193). 표지도 다시 뿌예진다:
   입자색은 중간 어둠이라 표지의 가장 어두운 부분보다 밝고, 그런 입자를 많이 깔면 검정을 들어올린다
   (T-191과 같은 병이고 이번엔 원인이 opacity가 아니라 밀도다). 그래서 알파 오프셋을 올려 켜지는
   픽셀을 25%로 줄이고 입자색도 한 단계 올렸다.
   ⚠️ 세기를 고칠 땐 캔버스로 합성색을 재서 판정한다 — 눈으로는 종이색 변화와 구별이 안 된다. */
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.26 0 0 0 0 0.24 0 0 0 0 0.20 0.7 0 0 0 -0.40'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
    --fiber: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='440' height='440'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008 0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.28 0 0 0 0 0.26 0 0 0 0 0.21 0.4 0 0 0 -0.26'/%3E%3C/filter%3E%3Crect width='440' height='440' filter='url(%23f)'/%3E%3C/svg%3E");
}

* { 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;   /* 종이 결(body::before)의 위치 기준 — 없으면 결이 첫 화면만 덮는다 */
    background: var(--bg);
    color: var(--text);
    font-family: "Gowun Dodum", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
    /* 400을 '명시'한다 — 미지정으로 두면 결과가 UA에 맡겨진다. 고운돋움은 400 단일 face라
       700을 걸면 전면 합성 볼드가 되어 본문/강조를 가르는 굵기 축이 통째로 죽는다. */
    font-weight: 400;
    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; }

/* 종이 결 — 본문 전체를 덮는 레이어.

   ⚠️ `absolute`다. `fixed`로 두면 결이 **뷰포트에 못 박혀**, 종이는 스크롤되는데 결만 제자리에
   남는다 — 결이 종이가 아니라 화면에 낀 유리처럼 보인다(사용자 반려 2026-08-18, T-192).
   결은 종이의 성질이니 종이와 함께 움직여야 한다. 그래서 위 `body`에 `position: relative`가
   짝으로 필요하다 — 기준이 없으면 초기 컨테이닝 블록(뷰포트 크기)에 걸려 첫 화면 높이만 덮는다.

   ⚠️ z-index는 **떠 있는 것들 아래**다(이 앱의 고정 오버레이는 100·150·200·9999).
   결이 고정 요소를 덮으면 스크롤할 때 그 위를 무늬가 미끄러져, 위 어색함이 뒤집힌 형태로 재발한다.
   본문 최대 z-index는 61이므로 90이면 「본문 위 · 떠 있는 것 아래」가 성립한다.

   ⚠️ mix-blend-mode를 쓰지 않는다. blend는 매 프레임 backdrop과 다시 섞어야 해서 스크롤 내내
   전면 재합성을 강제한다(T-176 발광 box-shadow와 같은 클래스). 값이 변하지 않는 타일 배경은
   페이지 래스터에 한 번 그려지고 끝이라 스크롤해도 재계산이 없다. */
body::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 90;
    background-image: var(--grain), var(--fiber);
    background-size: 300px 300px, 440px 440px;
}

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

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

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

/* 헤더 로고 책 아이콘 — footer·QuickNav와 통일한 라인아트 책 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: 'Gowun Batang', serif;
    font-size: 31px;
    font-weight: 700;
    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;
}

/* 내 책장 인사말 — 고운바탕 serif 제목 + 요약통계 한 줄(시안 My Shelf).
   history-greeting 과 같은 '화면 전용 분리' 패턴(전역 .greeting 영향 0). */
.shelf-greeting { margin: 0 0 20px; }
.shelf-greeting h1 {
    font-family: 'Gowun Batang', serif;
    font-size: 30px;
    font-weight: 700;
    color: var(--text);
    margin: 0;
    letter-spacing: -.01em;
    word-break: keep-all;
}
.shelf-greeting .leaf { font-size: 20px; }
.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: 700; }

/* ── 온보딩 강화 (발견 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: 600;
    color: var(--accent-hover);
    word-break: keep-all;
}
.entry-accordion > summary::-webkit-details-marker { display: none; }
.entry-accordion > summary::after { content: " ▾"; font-size: .7rem; }
.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: 700; }

/* 불변 아이디 경고(발견 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: 700; }

/* 하루 목표 프리셋 칩(발견 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: var(--surface);
    border: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: var(--radius-sm);
    color: var(--text);
    cursor: pointer;
}
.onb-preset-chip:hover { background: var(--sage-soft); }
.onb-preset-chip.is-active {
    background: var(--sage-soft);
    border-color: var(--accent);
    color: var(--accent-hover);
    font-weight: 700;
}

/* 실시간 미리보기 카드(발견 12) — "다른 사람에게 이렇게 보여요". 종이톤 카드로 폼 흐름 안에 둔다. */
.onb-preview-mount:empty { display: none; }   /* 아일랜드 미마운트(JS 비활성) 시 빈 자리 숨김 */
.onb-preview {
    margin: 0 0 16px;
    padding: 12px 14px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: var(--radius-sm);
}
.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: var(--sage-soft); color: var(--accent-hover);
    font-family: 'Gowun Batang', serif;
    font-size: 1.1rem; font-weight: 700; flex: none;
}
.onb-preview-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.onb-preview-name { font-size: .95rem; font-weight: 700; 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;
}

/* 카드 — 테두리를 연필선으로 교체.
   border-width(8px)만큼 padding에서 뺀다(24 → 16). border-radius는 border-image 렌더링에는
   무시되지만 배경 클리핑에는 그대로 먹으므로 배경 모서리를 위해 남긴다.
   그림자는 뺀다 — 종이에 연필로 그린 면에 드롭섀도가 얹히면 둘 다 가짜로 보인다. */
.card {
    background: var(--card-bg);
    border: 1px solid transparent;
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: var(--radius);
    box-shadow: none;   /* 종이에 연필로 그린 면에 드롭섀도가 얹히면 둘 다 가짜로 보인다 */
    padding: 24px;
    margin-bottom: 16px;
}

.card h2 {
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--accent-hover);
    margin: 0 0 12px;
}

/* 큰 타이머 숫자 */
.timer-display {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
    font-size: 3rem;
    font-weight: 700;
    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: 600;
    color: var(--text);
}

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

/* 누적 상한 도달 경고 (호박색) */
.cap-badge {
    margin: 12px 0 0;
    padding: 10px 12px;
    border-radius: 10px;
    background: var(--warn-bg-2);
    color: var(--warn-fg-3);
    border: 1px solid var(--warn-border-2);
    font-size: .9rem;
    font-weight: 600;
}

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

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

/* 책BTI 독서 종족 태그 칩 — 책장 요약 카드 상단, 결정적 규칙 기반 태그 */
.tag-chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.tag-chip {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--info-soft);
    color: var(--accent);
    font-size: .82rem;
    font-weight: 500;
    white-space: nowrap;
}
/* 클릭 가능한 태그 칩(장르 종족·한우물형) — 폭 태그와 구분되게 호버시 살짝 진해진다.
   <button>으로 렌더되므로 button 기본값(테두리·폰트)을 리셋해 비클릭 span 칩과 동일하게 보이게 한다. */
.tag-chip-click {
    cursor: pointer;
    text-decoration: none;
    border: none;              /* button 기본 테두리 제거 */
    font-family: inherit;      /* button 기본 폰트로 떨어지지 않게(size/weight는 .tag-chip이 지정) */
    line-height: inherit;
    width: auto;               /* 전역 button{width:100%} 상쇄 — 빠지면 칩이 가로 전체로 늘어남(#286 회귀 원인) */
    background: var(--accent);  /* 책 기반(근거 책 드릴다운 가능) 칩 = 진한 채움으로 강조 → 비클릭(복합) 칩과 색 구분(안 A) */
    color: var(--on-accent);
}
.tag-chip-click:hover { background: var(--accent-hover); }  /* 채움 칩이라 btn-primary와 동일 hover(배경만 진하게). 기존 filter+underline은 채움엔 과함 */

.tag-books-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.tag-books-head h3 { margin: 0; font-size: 1rem; }
.tag-books-head .btn-close { padding: 4px 10px; font-size: .85rem; }

/* 책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: 700; }
.timer-empty .btn { display: block; text-decoration: none; text-align: center; } /* a는 기본 inline이라 .btn의 width:100%가 안 먹음 → block으로 측정 시작 버튼처럼 풀폭 */

/* 버튼 */
button, .btn {
    font: inherit;
    font-weight: 700;
    border: 1px solid transparent;
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 10px;
    padding: 12px 18px;
    cursor: pointer;
    width: 100%;
    background: transparent;
    color: var(--accent-hover);
    transition: background-color .15s ease;
}

/* primary — 단색 채움 대신 색연필로 살짝 칠한 연한 세이지 면.
   한때 사선 해칭으로 칠했는데 사선이 글자를 가로질러 지저분했다(사용자 반려 2026-08-18).
   글자는 딥 세이지로 둔다(연한 채움 위에서 흰 글자는 읽히지 않는다). */
.btn-primary {
    background-color: color-mix(in srgb, var(--accent-fill) 20%, transparent);
    color: var(--accent-hover);
}
.btn-primary:hover {
    background-color: color-mix(in srgb, var(--accent-fill) 32%, transparent);
}

/* 비활성(disabled) 버튼 — '다시 분석' 일일 한도 소진 등으로 막혔을 때, 배경색을 명시한 버튼(.btn-primary)이
   그대로 눌리는 것처럼 보이던 문제를 막는다. 옅게 + 금지 커서로 "지금은 못 누름"을 시각화한다. */
button:disabled, .btn-primary:disabled { opacity: .5; cursor: not-allowed; }
.btn-primary:disabled:hover { background-color: color-mix(in srgb, var(--accent-fill) 20%, transparent); } /* 비활성 중엔 hover 색 변화도 끈다 */

.btn-danger {
    background-color: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--danger);
}
.btn-danger:hover {
    background-color: color-mix(in srgb, var(--danger) 20%, transparent);
}

/* ghost — 채움 없이 흐린 연필선만. 이게 primary(연한 채움)와의 위계를 만든다. */
.btn-ghost {
    background: transparent;
    color: var(--muted);
    border-image: var(--pencil-frame-soft) 8 / 8px stretch;
}
.btn-ghost:hover { background-color: var(--bg); }

/* 로그아웃 — 설정 바로가기와 너무 붙어 보여 간격을 띄우고(.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: var(--card-bg);
    color: var(--text);
    border: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
}
.btn-oauth-google:hover { background: var(--sage-soft); }
.oauth-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #4285f4;
    color: #fff;
    font-weight: 700;
    font-size: .85rem;
}

/* 폼 (회원가입 등) */
.field { margin-bottom: 16px; }
.field label {
    display: block;
    font-size: .85rem;
    font-weight: 600;
    margin-bottom: 6px;
}
.field input,
.field select {
    width: 100%;
    font: inherit;
    padding: 10px 12px;
    border: 1px solid transparent;
    border-image: var(--pencil-frame-soft) 8 / 8px stretch;
    border-radius: 10px;
    background: var(--card-bg);
}
.field select { appearance: auto; cursor: pointer; }
.field input:focus,
.field select:focus {
    outline: none;
    /* border-color는 border-image가 덮어 보이지 않는다 → 프레임을 진한 연필선으로 교체해 포커스를 표시.
       링(box-shadow)은 접근성상 남긴다. */
    border-image: var(--pencil-frame) 8 / 8px stretch;
    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: 10px;
    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: 700;
    text-decoration: underline;
    cursor: pointer;
}

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

/* 공용 하단 네비 — 대시보드 퀵 액션과 동일한 타일 양식(이것이 표준 양식).
   모든 페이지(검색/프로필/책장/기록/로그인 등)의 .link-row가 이 2열 타일을 공유한다.
   링크 수가 홀수면 마지막 타일이 전체폭(단일 링크 페이지=전체폭 버튼 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: var(--card-bg);
    border: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: var(--radius);
    color: var(--text);
    text-decoration: none;
    font-weight: 600;
    word-break: keep-all;
    transition: background .2s ease, border-color .2s ease, transform .05s;
}
/* hover 효과를 대시보드 QuickNav 타일과 통일 — 테두리 강조+그림자(떠오름) 대신
   연녹 채움(.dash-nav-tile:hover와 같은 --nav-hover-* 토큰 공유). */
.link-row a:hover { background: var(--nav-hover-bg); border-color: var(--nav-hover-border); text-decoration: none; }
.link-row a:active { transform: translateY(1px); }
.link-row a:last-child:nth-child(odd) { grid-column: 1 / -1; }
/* footer .link-row 내 라인 아이콘 — 전 페이지 공통(Vue NavIcon · Thymeleaf nav-icons fragment
   가 공유). 색은 대시보드 타일 아이콘과 동일한 딥세이지(accent-hover)로 통일 — 라벨(차콜)과
   분리되어 대시보드 QuickNav 타일과 같은 룩. 정렬·간격은 .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);
    box-shadow: var(--shadow);
    color: var(--text);
    text-decoration: none;
    transition: border-color .15s, box-shadow .15s, transform .05s;
}
.highlight-tile:hover { border-color: var(--accent-hover); box-shadow: 0 2px 6px rgba(110, 138, 106, .18), 0 8px 24px rgba(110, 138, 106, .12); }
.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: 700; 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: 600; }
.record-books {
    color: var(--muted);
    font-size: .85rem;
    word-break: keep-all;
    overflow-wrap: anywhere;
}
.record-time {
    color: var(--accent);
    font-weight: 700;
    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: 700;
    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(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: var(--radius-sm);
    background: var(--card-bg);
    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) { color: var(--accent); border-color: var(--accent); }
.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;
}

/* === 독서 잔디 (GitHub 컨트리뷰션 그래프 스타일) === */
/* 헤더: 제목 좌측 / 연속 일수 칩(「N일 연속 독서」) 우측 상단.
   h2의 아래 여백(12px)을 래퍼로 옮겨 요약문과의 간격을 그대로 유지한다. */
.grass-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 12px; }
.grass-head h2 { margin: 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: 700; 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: 700; 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: 9.5px;
    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: 10px;
    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: 3px;
    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); }
/* 직접 채운 날 — 대시보드와 동일 호박색 안쪽 테두리. */
.grass-cell.manual { box-shadow: inset 0 0 0 2px #C99A3A; }

.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: 12px;
    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(--text);
    color: var(--bg);
    font-size: 12px;
    padding: 6px 10px;
    border-radius: 7px;
    white-space: nowrap;
    pointer-events: none;
    z-index: 9999;
    box-shadow: 0 6px 16px -6px rgba(0, 0, 0, .5);
}
/* === 내 책장 (Book) === */
.muted { color: var(--muted); }

/* 내 책장 카드 소제목 — 시안 .lbl(작은 라벨·넓은 자간). 전역 .card h2를 books 페이지에서만 오버라이드. */
#books-app .card h2 {
    font-size: 12px;
    letter-spacing: .13em;
    color: var(--accent-hover);
    font-weight: 600;
    text-transform: none;
}

.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(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 8px;
    font-size: .95rem;
}
.book-manual-form select,
.book-add-form select, .book-actions select {
    padding: 7px 8px;
    border: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 8px;
    background: var(--surface);
}

/* 검색 폼: 검색 기준 칩을 위에 두고, 입력+버튼을 아래 한 줄로. */
.book-search-form { flex-direction: column; align-items: stretch; }
/* 검색 기준 칩 — 라디오 대신 제목/저자/출판사 토글(활성=세이지 채움). 시안 My Shelf. */
.search-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.search-chip {
    width: auto;                                   /* 전역 button{width:100%} 상쇄(#286 가드) */
    border: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    background: transparent;
    color: var(--muted);
    border-radius: 999px;
    padding: 6px 14px;
    font-size: .85rem;
    font-weight: 600;
    cursor: pointer;
    line-height: 1;
}
.search-chip:hover { border-color: var(--accent); color: var(--accent); }
.search-chip.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
/* 검색 바(넓게) 위 + 검색 버튼 아래로 세로 배치 — 버튼이 입력칸을 잡아먹지 않게. */
.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(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 8px;
    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: 600;
    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: 4px;
    flex-shrink: 0;
    background: var(--border);
}
/* 무표지 책 표지 플레이스홀더 — coverUrl 이 없을 때 색 배경 + 이니셜(고운바탕 serif).
   배경/글자색은 coverColor()가 결정적으로 골라 인라인 주입(시안 My Shelf 무표지 카드). */
.book-cover-ph {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'Gowun Batang', serif;
    font-weight: 700;
    font-size: 18px;
    line-height: 1;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .4), 0 2px 4px rgba(120, 100, 70, .18);
    user-select: none;
}
.book-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 220px; }
.book-title { font-weight: 600; 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; }
/* <img>는 자기 콘텐츠를 자기 테두리 **위에** 그려서 프레임 안쪽 띠(연필선)를 표지 그림이 덮는다.
   padding 4px로 그림을 선(바깥 ≤3.1px) 밖으로 물리고, 로딩 전 회색 배경(.book-cover의 --border)은
   content-box로 좁혀 패딩 링이 카드 배경 그대로 보이게 한다. 전역 box-sizing: border-box라 외곽은 84×120 그대로.
   ⚠️ 무표지 div.bd-cover-ph(class="book-cover bd-cover-ph")도 이 규칙을 받아 padding 4px가 생기지만
   겉모습은 안 바뀐다 — 이유가 페인트 순서가 아니라 **캐스케이드**다: `body.bookdetail-page .bd-cover-ph`의
   `background:` **단축** 선언(특이성 0,2,1 > 0,2,0)이 background-clip을 border-box로 되돌려 세이지 배경이
   border-box를 그대로 채운다(실측: ph는 border-box, img는 content-box). 이니셜은 flex 중앙이라 위치도 그대로.
   ⚠️ 그 줄을 `background-color:`로 바꾸면 단축의 리셋이 사라져 ph의 배경이 content-box로 좁아진다 — 이 규칙에
   의존이 걸려 있으니 같이 본다. */
.book-detail-head .book-cover { width: 84px; height: 120px; border-radius: 10px; border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; padding: 4px; background-clip: content-box; }
.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: 18px; }

/* 표지 플레이스홀더(무표지 책) — 책장 목록의 coverColor() 다색 랜덤과 달리 단일 상세라 고정 세이지 톤. */
body.bookdetail-page .bd-cover-ph {
    display: flex; align-items: center; justify-content: center;
    background: var(--sage-soft); color: var(--accent-hover);
    font-family: 'Gowun Batang', serif; font-weight: 700; font-size: 40px;
}

/* 책 제목 — 전역 .card h2(uppercase 라벨체) 대신 시안 크기로 격상. 카드 섹션 제목도 같은 세리프로 통일. */
body.bookdetail-page .bd-title {
    font-family: 'Gowun Batang', serif; font-weight: 700; 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: 'Gowun Batang', serif; font-weight: 700; 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: 12px; padding: 4px 11px; border: 1px solid transparent;
}
body.bookdetail-page .bd-status-reading { background: var(--sage-soft); color: var(--accent-hover); border-color: var(--sage-soft); }
body.bookdetail-page .bd-status-finished { background: color-mix(in srgb, var(--ok-fill) 12%, transparent); color: var(--ok); border-color: color-mix(in srgb, var(--ok-fill) 25%, transparent); }
body.bookdetail-page .bd-status-want { background: var(--paper-2); color: var(--muted); border-color: var(--border); }
body.bookdetail-page .bd-visibility-chip {
    display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--muted);
    border: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 999px; padding: 3px 9px; background: var(--paper-4);
}
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: 'Gowun Batang', serif; font-weight: 700; font-size: 17px; color: var(--accent-hover); }

/* 구매 버튼 — 전역 .btn-ghost(무채색) 대신 세이지 pill. 드롭다운은 세로 목록 + 종이톤 카드로. */
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: 14px;
    box-shadow: 0 4px 14px rgba(44, 42, 36, .1); 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: 10px; 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: 'Gowun Batang', serif; font-weight: 700; 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: 'Gowun Batang', serif; font-weight: 700; 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; }

/* 하단 이동 타일 — 세로 스택(아이콘 위/라벨 아래). 전역 .link-row(가로 배치)는 다른 페이지 그대로. */
body.bookdetail-page .link-row a { flex-direction: column; gap: 8px; padding: 20px 16px; border-radius: 18px; }
.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(--accent);
    background: var(--info-soft-2);
    padding: 1px 8px;
    border-radius: 999px;
}
.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: .72rem;
    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: .7rem; 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(--surface); border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,.08);
    min-width: max-content;
}
.buy-menu-items a {
    text-decoration: none; color: var(--muted); font-size: .85rem;
    padding: 6px 10px; border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 6px;
}
.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 { width: auto; padding: 6px 14px; font-size: .85rem; }

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

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

/* 인사말 헤더 — 제목·통계만. 페이지 이동은 모든 폭에서 하단 .link-row 타일이 담당. */
.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 h2 { margin: 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: 600; }
.shelf-public-hint a { color: var(--accent-hover); font-weight: 600; }

/* 빈 책장 — 점선 박스 + 🌱(시안). 필터 결과 0은 기존 .status-line 유지(다른 메시지). */
.shelf-empty {
    margin-top: 4px; text-align: center; padding: 26px 12px;
    border: 1px dashed var(--line-2-2); border-radius: 12px; background: var(--paper-1-2);
}
.shelf-empty-icon { font-size: 34px; }
.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: 600; 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: 5px; 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: 4px; 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 회피). ── */
@media (min-width: 880px) {
    .container.shelf-page { max-width: 1180px; }
    .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: 1px solid var(--border);
        border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 12px; background: var(--surface);
        padding: 14px; align-items: flex-start;
    }
    #books-app .shelf-list .book-row:last-child { border-bottom: 1px solid var(--border); }
}

.affiliate-note { font-size: 10.5px; color: var(--muted); text-align: left; opacity: .85; line-height: 1.5; margin: 6px 0 0; }
.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(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 14px; padding: 14px;
    box-shadow: 0 10px 28px -10px rgba(44, 42, 36, .28);
    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(--border); border-top: 1px solid var(--border);
    transform: rotate(45deg);
}
.affiliate-pop-item { margin: 0; font-size: 12px; 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 미지정분만 시안에 맞춰 보완.
   ───────────────────────────────────────────────────────────────────────── */
body.profile-page .container { max-width: 1160px; }  /* 와이드 2열 여유 — 데스크톱 빈 옆 공간 활용. 페이지 스코프 = 타 페이지 회귀 0 */

/* 내 책방(self) 상단 사용자 검색 진입점 — 검색 input처럼 보이되 실제론 /search 링크(트위터식).
   책방엔 슬림 진입점만, 무거운 검색 패널/추천은 전용 페이지로 위임(책방 비대화 방지).
   톤: .book-search-form input(테두리·라운드) + .dash-nav-tile(연베이지 채움·hover 토큰) 혼합. */
.shop-search-entry {
    display: flex; align-items: center; gap: 10px;
    padding: 11px 16px;
    border: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 999px;
    background: var(--paper-1); color: var(--muted);
    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: 'Gowun Batang', serif; font-weight: 700; 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: 12.5px; padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; color: var(--muted); 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; }
.shop-count strong { font-family: 'Gowun Batang', serif; font-weight: 700; 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: 10px; 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: 6px;
    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(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 12px;
    box-shadow: 0 4px 16px rgba(44, 42, 36, .12); 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: 8px; 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-radius: 18px; padding: 24px;
    width: 100%; max-width: 360px; box-shadow: 0 8px 32px rgba(44, 42, 36, .18);
    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: 600; color: var(--text); margin: 0; }
.shop-report-modal-close {
    background: none; border: none; cursor: pointer; padding: 4px; border-radius: 6px;
    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(--paper-1-3);                           /* 설계 §6.5 지정 시트 배경 */
    border-radius: 24px 24px 0 0;
    padding: 12px 20px calc(20px + env(safe-area-inset-bottom, 0px));
    width: 100%; max-width: 460px; box-shadow: 0 -8px 32px rgba(44, 42, 36, .18);
    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: 600; color: var(--text); margin: 0; }
.book-sheet-close {
    background: none; border: none; cursor: pointer; padding: 4px 8px; border-radius: 6px;
    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); }

/* 검색해서 담기 — 시트 안에서 카탈로그를 찾아 바로 책장에 담는다(책장 검색 재사용). */
.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(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 12px;
    background: var(--card-bg); 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: none; border-radius: 12px; background: var(--accent); color: var(--on-accent); cursor: pointer;
}
.book-sheet-search-btn svg { width: 18px; height: 18px; }
.book-sheet-search-btn:hover { background: var(--accent-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-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 999px;
    background: var(--card-bg); color: var(--muted); font-size: 13px; font-weight: 600; cursor: pointer;
}
.book-sheet-chip:hover:not(.active) { border-color: var(--accent); color: var(--accent); }
.book-sheet-chip.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* 책 목록 · 검색결과 — 표지 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: 12px;
    background: var(--card-bg); border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; color: var(--text);
}
.book-sheet-book { cursor: pointer; }
.book-sheet-book:hover { border-color: var(--accent); background: var(--sage-soft); }
.book-sheet-book:disabled { opacity: .5; cursor: default; }
.book-sheet-cover {
    width: 34px; height: 48px; border-radius: 4px; flex-shrink: 0; object-fit: cover;
    background: var(--border); display: flex; align-items: center; justify-content: center;
    font-family: 'Gowun Batang', serif; font-weight: 700; font-size: 15px; line-height: 1; user-select: none;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .4), 0 2px 4px rgba(120, 100, 70, .18);
}
.book-sheet-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.book-sheet-book-title { font-weight: 600; color: var(--text); font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.book-sheet-byline { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.book-sheet-badge { flex-shrink: 0; font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 999px; }
/* .book-sheet-owned 의 모양은 책장 배지와 한 규칙으로 묶여 있다 — 「이미 책장에 있음」 배지 절 참고. */
.book-sheet-add-btn {
    width: auto; flex-shrink: 0; padding: 8px 14px; border: none; border-radius: 10px;
    background: var(--ok); color: var(--on-accent); font-size: 13px; font-weight: 600; cursor: pointer;
}
.book-sheet-add-btn:hover { filter: brightness(.96); }
.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: 1px solid var(--line-2); border-radius: 18px; padding: 4px; box-shadow: 0 1px 2px rgba(44, 42, 36, .04); }
.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: var(--surface); border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; 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: 600; }

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

/* 드릴다운 */
.shop-drill { background: var(--paper-1); border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 12px; padding: 14px; }
.shop-drill-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.shop-drill-head h3 { font-family: 'Gowun Batang', serif; font-weight: 700; 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: 12.5px; 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; }
.shop-shelf-title { font-family: 'Gowun Batang', serif; font-weight: 700; font-size: 18px; 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: 12.5px; padding: 5px 13px; border-radius: 999px; border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; color: var(--muted); background: transparent; cursor: pointer; width: auto; }
.shop-filter button:hover { border-color: var(--accent); color: var(--accent); }
.shop-filter button.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
/* 완독 정렬 칩 행 — 완독 필터에서만 뜨는 둘째 행. 상태필터 칩(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열 풀폭으로 우아하게 강등(대시보드 .dash-grid-2col 관용구) */

/* 공개 책장 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; border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 14px; background: var(--paper-1); }

/* 책등 표지 + 줄무늬 종이결 폴백(회색 단색 금지) */
.shop-cover { flex: 0 0 auto; width: 54px; height: 78px; border-radius: 5px; display: flex; align-items: center; justify-content: center; object-fit: cover;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .4), 0 2px 5px rgba(120, 100, 70, .18); }
.shop-cover-ph { background: repeating-linear-gradient(var(--card-bg), var(--card-bg) 19px, var(--line-1-7) 20px);
    font-family: 'Gowun Batang', serif; font-weight: 700; font-size: 22px; color: color-mix(in srgb, var(--accent-fill) 85%, transparent); }

/* 책 메타 */
.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: 600; line-height: 1.4; }
.shop-book-author { font-size: 12.5px; color: var(--muted); }
.shop-book-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 2px; }

/* 상태 배지 3색 */
.shop-badge { font-size: 11.5px; font-weight: 600; padding: 3px 10px; border-radius: 999px; }
.shop-badge-finished { background: var(--ok-soft); color: var(--ok-fill); }
.shop-badge-reading  { background: var(--sage-soft); color: var(--accent-hover-2); }
.shop-badge-want     { background: var(--warn-bg-4); color: var(--warn-fg); }

/* 독서시간 / 구매 / 제휴 */
.shop-time { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--ok); font-weight: 600; }
.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: 12.5px; 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: 12.5px; color: var(--accent-hover); border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 8px; padding: 4px 10px; }
.shop-buy-menu > summary::-webkit-details-marker { display: none; }
.shop-buy-menu > summary:hover { background: var(--sage-soft); }
.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(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 10px; box-shadow: var(--shadow); 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: 7px; font-size: 12.5px; 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: 'Gowun Batang', serif; font-weight: 700; 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: 600; }
.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: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 10px; color: var(--muted); text-decoration: none; font-weight: 600; font-size: .9rem;
}
.follow-tabs a.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

.book-time { font-size: .8rem; color: var(--ok); font-weight: 600; }
/* 내 책장 필터 칩 — 상태/공개여부 토글(활성=세이지 채움). books 전용(프로필 .shelf-filter와 별개). 시안 My Shelf.
   두 칩 그룹(상태·공개여부)을 같은 모양으로 통일 — 기존 세그먼티드 '서브 필터' 룩 대신 시안의 단일 칩. */
/* 필터 묶음 = 세그먼트 토글 바(한 덩어리) — 상태/공개여부 두 묶음을 개별 덩어리로 분리 */
.shelf-filter-chips {
    display: flex; width: fit-content; flex-wrap: nowrap;     /* flex=block레벨→세로 적층, fit-content=내용폭 */
    position: relative;                                       /* ::after 오버레이 기준 */
    border: 1px solid transparent;                            /* 선은 아래 ::after가 그린다 — 1px 레이아웃만 유지 */
    border-radius: var(--radius-sm); overflow: hidden;        /* radius-sm(8px)=각진 세그먼트, overflow=셀 모서리 클립 */
    margin: 0 0 9px;
}
/* 프레임을 자식 위에 얹는다 — 세그먼트는 셀이 가장자리에 붙는 것이 모양이라 padding으로 띄울 수 없고,
   active·hover 배경과 셀 구분선(border-left)이 부모의 border-image 안쪽 띠를 덮어 첫 셀이 활성이면
   왼쪽 선이 통째로 사라졌다. inset:-1px로 오버레이의 border-box를 컨테이너의 border-box와 맞춰
   스트로크 위치를 옛것과 동일하게 둔다. overflow:hidden이 패딩 박스로 클립하므로 border-box 바깥
   1px 링에 걸친 스트로크 0.35px이 잘리지만 서브픽셀이라 안 보인다(실측 게이트 U-4). */
.shelf-filter-chips::after {
    content: ""; position: absolute; inset: -1px; pointer-events: none;
    border: 1px solid transparent;
    border-image: var(--pencil-frame) 8 / 8px stretch;
}
.shelf-filter-chips + .shelf-filter-chips { margin-bottom: 18px; }
.filter-chip {
    width: auto;                                   /* 전역 button{width:100%} 상쇄(#286 가드) */
    border: 0; border-radius: 0;                   /* 전역 button{border-radius:10px} 상쇄 — 모서리는 컨테이너 overflow가 8px로 클립(없으면 active 셀이 10px라 겉 박스와 어긋남) */
    background: transparent; color: var(--muted);
    padding: 6px 14px; font-size: .8rem; font-weight: 600;
    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-soft); color: var(--accent-hover); }
.filter-chip.active { background: var(--accent); color: var(--on-accent); }
/* 팔로우 스코프 인기 카운트(§7.4) — 책 메타 안 작은 배지 */
.follow-popularity { font-size: .78rem; color: var(--accent); font-weight: 600; 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 color-mix(in srgb, var(--accent-fill) 50%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent-fill) 18%, transparent);
  font-size: .78rem;
  font-weight: 600;
  color: var(--accent-hover);
}

/*
 * ⚠️ 책장 쪽 배지는 `.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: 600; }

/* 이번 주 빠뜨린 날 (독서 기록 화면 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: 600; }
.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: 600;
    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시켜 다음 형제 .link-row(block grid)가 stretch 폭을 못 받고 min-content로 짓눌린다.
   (#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일 때만 컨테이너를 넓혀 2단이 안 찌그러지게(전역 .container max-width:460 무손상). */
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: pill 탭 2개(활성=세이지 채움/흰 글자, 비활성=투명+보더) + 선택 패널 하나 */
.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: 600;
    padding: 9px 16px;
    border-radius: 999px;
    border: 1px solid transparent;
    background: transparent;
    color: var(--muted-3);
    cursor: pointer;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.hist-tab:not(.active) { border-color: var(--border); }
.hist-tab:not(.active):hover { color: var(--text); }
.hist-tab.active { background: var(--accent); color: var(--on-accent); }
.hist-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hist-panel { padding-top: 14px; }

/* 일자별 시간 색 — 시안 #4F6B4C(딥 세이지). 책장 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: .7rem;
    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;
    /* soft 변종은 범용 폼 필드(.field input/select)가 쓰는 것과 같다 — 같은 계열이라 그쪽을 따른다
       (진한 --pencil-frame은 설정 화면의 .set-input 몫). */
    border: 1px solid var(--border-2); border-image: var(--pencil-frame-soft) 8 / 8px stretch;
    border-radius: 8px; font: inherit; box-sizing: border-box;
}
.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: 1px solid var(--border-3); border-radius: 10px; padding: 0.8rem 0.9rem; }
.fb-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.fb-type { font-size: 0.78rem; font-weight: 700; background: var(--paper-2-2); border-radius: 6px; padding: 0.12rem 0.45rem; }
.fb-author { font-size: 0.8rem; opacity: 0.65; margin-left: auto; }
.fb-title { font-weight: 700; 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: 700; 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-4); border-radius: 999px; color: inherit;
}
.fb-filter a.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }

.fb-reply-shown { margin: 0.5rem 0; padding: 0.55rem 0.7rem; background: var(--info-soft-4); border-radius: 8px; }
.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: 700; 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(--border-2);
    border-image: var(--pencil-frame-soft) 8 / 8px stretch;
    border-radius: 8px; font: inherit; box-sizing: border-box; resize: vertical;
}
.fb-reply-form button { align-self: flex-start; }

/* ═══════════════════════════════════════════════════════════════════════
   책BTI 페이지 재스킨 (/personality) — Claude Design 이식.
   스코프: .pbti-* 신규 클래스 + personality 전용 .personality-* 와 .carousel-*
   (이 둘은 personality 페이지에서만 쓰여 재스킨해도 회귀 0). 공유 클래스
   (.card · .greeting · .status-line · .tag-chip · .btn-* · .record-* · .link-row)는 미접촉.
   토큰: --bg #F7F2E8 · --card-bg #FCFAF5 · --text #2C2A24 · --muted #6F6A5E
        · --accent #6E8A6A · --accent-hover #4F6B4C · --border #E4DDD0 · --sage-soft #E7EEE2
   ═══════════════════════════════════════════════════════════════════════ */

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

/* 데스크톱(태블릿+): 책BTI 페이지만 컨테이너를 넓혀 분석 카드가 가로로 펴지게 한다.
   앱 기본은 모바일-우선 .container max-width:460px라, 큰 화면에선 긴 AI 서술이 좁은 460px
   칸에 갇혀 세로로 길쭉했다(모바일은 이 폭이 적절해 무변경). 캐러셀 슬라이드(80% peek)·도트·
   스크롤 로직은 그대로 두고 폭만 키우면 같은 글이 더 적은 줄로 흘러 카드 높이가 준다
   (실측 narrative 232→440px, 17줄→9줄). dashboard와 동일한 페이지-스코프 패턴이라
   body.personality-page 한정 → 다른 페이지 회귀 0. min-width 가드라 모바일(<600px)은 무손상.
   카드 폭은 PersonalityCarousel의 step()/dotIndex가 실측 폭에서 역산하므로 JS 변경 불필요. */
@media (min-width: 600px) {
    body.personality-page .container { max-width: 720px; }
}

/* 페이지 제목 — 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: 11px; 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: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 18px;
    padding: 22px 20px;
    box-shadow: 0 1px 2px rgba(44, 42, 36, .03), 0 8px 20px -14px rgba(44, 42, 36, .16);
    display: flex; flex-direction: column; gap: 16px;
}
.pbti-card-title { font-family: 'Gowun Batang', serif; font-size: 18px; font-weight: 700; color: var(--text); margin: 0; }

/* "내 독서 성향" 카드 헤더 — 제목(좌) + ? 헬프 버튼(우) 행, 팝오버 앵커(position:relative) */
.pbti-card-head { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.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(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 14px; padding: 14px;
    box-shadow: 0 10px 28px -10px rgba(44, 42, 36, .28);
    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(--border); border-top: 1px solid var(--border);
    transform: rotate(45deg);
}
.pbti-help-note { display: flex; gap: 9px; align-items: flex-start; }
.pbti-help-note span { font-size: 12.5px; line-height: 1.6; color: var(--accent-hover); word-break: keep-all; }
.pbti-help-note a { color: var(--accent-hover); font-weight: 700; 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: 14px; 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: 12px; color: var(--muted); }
.pbti-summary-value { font-size: 15px; color: var(--text); word-break: keep-all; }
.pbti-meta { font-size: 12px; color: var(--muted); margin: 0; word-break: keep-all; }
/* 강조 수치(완독·저자·장르 수, 남은 횟수) — 시안: 고운바탕 딥세이지 굵게 */
.pbti-num { font-family: 'Gowun Batang', serif; color: var(--accent-hover); font-weight: 700; }

/* 성향 안내 블록 — 「다시 분석」 버튼이 있던 자리(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: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 14px; padding: 13px;
}
.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(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    background: var(--card-bg);
    color: var(--accent-hover);
    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(--bg); }
.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 var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 16px;
    padding: 18px;
    box-shadow: 0 2px 8px rgba(44, 42, 36, 0.07);
}
/* 대표(선택) 카드 — sage 테두리 + 은은한 sage 리프트로 한눈에 구분 */
.personality-entry.is-selected {
    border-color: var(--accent);
    box-shadow: 0 2px 10px rgba(110, 138, 106, 0.18);
}
.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: 12px; 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: 600; }
.personality-badge-cand { background: transparent; border: 1px solid var(--sage-line-2); color: var(--accent-hover); padding: 5px 12px; }
.personality-time { font-size: 12px; color: var(--muted); flex: 0 0 auto; }
.personality-narrative {
    font-family: 'Gowun Batang', 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)은 task1 와이드(.container 720px)로 이미 짧아 무변경 — 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: 14px; 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: 14px; 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: 14px; padding: 10px;
    font-family: inherit; font-size: 14px; font-weight: 600;
    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);
    /* 카드 테두리: 연필선 — 묶음끼리 명시적 구분 (대시보드 전용, 전역 --border 무변경).
       ⚠️ 종이·연필 테마의 일괄 적용은 「`.card`이거나 `border: 1px solid var(--border)`인 것」을 기준으로
       돌아서, 자체 색으로 테두리를 선언한 이 클래스는 통째로 빠져 있었다 — 홈의 카드 4개와 책방 카드가
       전부 매끈한 선이었고, 정작 그 안의 .dash-state-panel·.dash-nav-tile엔 연필선이 있어 한 화면에서
       두 양식이 갈렸다(2026-08-25 실측). 색은 border-image가 로드 안 될 때의 폴백으로 남긴다. */
    border: 1px solid var(--line-2);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 18px;
    padding: clamp(18px, 2.4vw, 26px);
    box-shadow: 0 1px 2px rgba(44, 42, 36, .04);
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.dash-pill {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--sage-soft-2);
    color: var(--accent-hover);
    font-size: 12.5px;
    padding: 5px 12px;
    border-radius: 999px;
    width: auto;
}
.dash-pill-ok { background: var(--ok-soft-3); color: var(--ok); font-weight: 700; }

/* 제목(pill/head)을 본문에서 띄워 섹션 분리감 — 카드 안 본문은 촘촘히, 제목 아래만 여유 */
.dash-nav > .dash-pill,
.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: 'Gowun Batang', serif;
    font-style: italic;
    color: var(--muted);               /* 카드 시절(--text)보다 톤 다운 — 약화 취지 */
    text-align: center;                /* 중앙정렬 각주 */
}
/* 페이드-디바이더: 짧은 중앙 헤어라인. 중앙이 세이지톤으로 살짝 진하고 좌우 끝으로 갈수록
   완전 투명 → 딱딱한 직선 대신 종이톤 배경에 유기적으로 녹는다. 명언 있을 때만 렌더. */
.brand-quote::before {
    content: "";
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: min(220px, 58%);
    height: 1px;
    pointer-events: none;
    background: linear-gradient(90deg,
        transparent 0%,
        color-mix(in srgb, var(--accent) 48%, var(--border)) 35%,
        color-mix(in srgb, var(--accent) 48%, var(--border)) 65%,
        transparent 100%);
}
.brand-quote-line {
    /* 본문+저자를 하나의 연속 텍스트 흐름으로(flex 아님) — 저자가 별도 줄을 차지하지 않고
       본문 끝에 이어 붙어, 본문이 2줄이어도 저자까지 2줄 안에 담긴다. width:100%로 부모 폭 확보,
       text-align:center는 .brand-quote에서 상속. */
    width: 100%;
    /* 긴 명언만 폰트 축소(--q-scale = BrandQuote.vue가 글자수로 계산 주입) — 2줄에도 넘칠 때
       잘림 없이 담기 위함. 상한=--bq-size, 하한 0.72rem 하드가드. font-size는 롤 트랜지션
       대상(transform·opacity)이 아니라 즉시 확정(깜빡임 없음). */
    font-size: clamp(0.72rem, 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: color-mix(in srgb, var(--accent) 55%, transparent);
}
.brand-quote-text::before { content: "\201C"; margin-right: 1px; }
.brand-quote-text::after  { content: "\201D"; margin-left: 1px; }
.brand-quote-author { font-size: .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: 22px;
    padding: clamp(22px, 3vw, 36px);
    box-shadow: 0 2px 4px rgba(44, 42, 36, .05), 0 18px 44px rgba(79, 107, 76, .10);
    flex-direction: row;
    flex-wrap: wrap;
    gap: clamp(22px, 3vw, 40px);
    align-items: center;
}
.dash-timer-left { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 16px; }
.dash-timer-num {
    font-family: 'Gowun Batang', serif;
    font-weight: 700;
    /* 상한 96 — 와이드(1160px) 히어로에서 숫자가 카드에 눌리지 않게. 8.5vw가 상한에 닿는 건
       ≥1129px라 모바일·태블릿은 하한 52px 그대로(무영향). */
    font-size: clamp(52px, 8.5vw, 96px);
    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; max-width: 420px; }
.dash-progress-track { height: 10px; border-radius: 999px; background: var(--sage-soft-2); overflow: hidden; }
.dash-progress-fill { height: 100%; background: var(--accent); border-radius: 999px; 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; }
/* 7일 자동 용서 안내 — 점선 상단 구분, 톤 다운(밀린 빚을 위협이 아니라 안심으로) */
.dash-forgive-note {
    margin: 2px 0 0;
    padding-top: 12px;
    border-top: 1px dashed var(--border);
    font-size: 12px;
    line-height: 1.5;
    color: var(--muted);
    max-width: 420px;          /* 진행바(.dash-progress-wrap)와 폭 정렬 — 형제 폭 불일치 제거 */
    word-break: keep-all;      /* 한글 어절(공백) 단위 개행 — 조사 중간 끊김 방지 */
    overflow-wrap: break-word; /* 긴 불가분 토큰 오버플로 안전장치 */
    text-wrap: pretty;         /* 마지막 줄 고아 단어 방지 (미지원 브라우저는 무시) */
}

.dash-timer-right { flex: 1 1 290px; min-width: 0; }

/* 상태 패널 */
.dash-state-panel {
    background: var(--paper-1);
    border: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 16px;
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.dash-state-row { display: flex; align-items: center; justify-content: space-between; }
.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: 'Gowun Batang', serif;
    font-weight: 700;
    font-size: 22px;
    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; }
.dash-kv-k { font-size: 13px; color: var(--muted); }
.dash-kv-v { font-family: 'Gowun Batang', serif; font-weight: 700; 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: 12px;
    border: 1.5px solid var(--accent);
    background: transparent;
    color: var(--accent-hover);
    font-family: inherit;
    font-size: 16px;
    cursor: pointer;
    transition: background .2s ease;
}
.dash-btn-outline:hover { background: var(--sage-soft-2); }
.dash-btn-fill {
    padding: 14px;
    border-radius: 12px;
    border: none;
    background: var(--accent);
    color: var(--card-bg);
    font-family: inherit;
    font-size: 16px;
    cursor: pointer;
    transition: background .2s ease;
}
.dash-btn-fill:hover { background: var(--accent-hover); }
.dash-btn-link { display: block; width: 100%; box-sizing: border-box; text-align: center; text-decoration: none; }

/* ACHIEVED */
.dash-state-achieved { background: var(--ok-soft-4); border-color: var(--ok-line-3); text-align: center; align-items: center; gap: 12px; }
.dash-achieved-emoji { font-size: 34px; }
.dash-achieved-title { margin: 0; font-family: 'Gowun Batang', serif; font-weight: 700; font-size: 19px; color: var(--ok); line-height: 1.4; }
.dash-achieved-sub { margin: 0; font-size: 13.5px; color: var(--muted); line-height: 1.5; }
/* 달성 패널에 측정 시작 폼이 함께 들어갈 때: 격려 텍스트는 가운데 유지, 폼 컨트롤은 풀폭으로
   (패널이 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-fill:disabled,
.dash-btn-outline:disabled { opacity: .6; 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 12px; border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 14px; background: var(--card-bg);
}
.dash-book-chip-cover {
    width: 30px; height: 42px; border-radius: 4px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    font-family: 'Gowun Batang', serif; font-weight: 700; font-size: 14px; line-height: 1; user-select: none;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .4), 0 2px 4px rgba(120, 100, 70, .18);
}
/* 실표지일 때 — 비율이 제각각이라 잘라 채운다. 로드 전·투명 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: 600; 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 12px; border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 999px;
    background: none; color: var(--muted); font-size: 13px; cursor: pointer;
}
.dash-book-chip-change:hover { border-color: var(--accent); color: var(--accent); }
.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: var(--sage-soft-2); color: var(--accent-hover);
    font-size: 13px; padding: 6px 13px; border-radius: 999px;
}
.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-fill {
    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;
}

/* 빠른 이동 */
.dash-nav { gap: 16px; }
.dash-nav-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.dash-nav-tile {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 9px; min-height: 96px; padding: 14px;
    border-radius: 14px; background: var(--paper-1); border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch;
    color: var(--accent-hover); text-decoration: none;
    transition: background .2s ease, border-color .2s ease;
}
.dash-nav-tile:hover { background: var(--nav-hover-bg); border-color: var(--nav-hover-border); }
.dash-nav-tile:last-child:nth-child(odd) { grid-column: 1 / -1; }
.dash-nav-label { font-size: 14.5px; color: var(--text); }

/* 좁은 폭: 히어로 2단을 세로로 */
@media (max-width: 520px) {
    .dash-timer-hero { flex-direction: column; align-items: stretch; }
    /* column 축에선 flex-basis(320/290px)가 height로 잡혀 좌블록이 과잉 높이 → 공백.
       basis를 auto로 풀어 콘텐츠 높이로 (N-118 부류 아님, flexbox 축 전환 함정) */
    .dash-timer-left, .dash-timer-right { flex: 0 0 auto; }
}

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

/* 와이드 레이아웃 (대시보드 전용 — 전역 .container max-width 460은 건드리지 않음).
   760 → 1160: 1440px 창에서 화면의 40%만 쓰던 것을 넓힌다. 웹의 주 사용처를 데스크톱·태블릿으로
   두기로 한 방침(모바일은 미니앱)에 맞춘 값이다. .container는 width:100%라 좁은 화면은 그대로 뷰포트에
   맞으므로 640px 경계는 손대지 않는다. */
@media (min-width: 640px) {
    body.dashboard-page .container { max-width: 1160px; }
}

/* 데스크톱 — 넓어진 카드에 안의 요소 크기도 맞춘다(폭만 키우면 카드가 비어 보인다).
   경계 1100px은 원래 잔디에서 나온 값이다(1년치가 16px 칸으로 스크롤 없이 들어가는 최소 폭). 잔디는
   2026-09-07에 걷었지만 경계는 그대로 둔다 — 3열 타일·백지복습 2열이 편해지는 폭이 마침 같은 자리다. */
@media (min-width: 1100px) {
    .dash-progress-wrap, .dash-forgive-note { max-width: none; }        /* 좌열 전체 폭 — 420px 제한은 460px 시절 값이다 */

    /* 홈 백지복습 — 본문을 왼쪽에 크게, 책·과목·범위를 오른쪽 좁은 열로. 안 그러면 한 줄짜리 「과목」
       입력이 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; }
    .dash-nav-grid { grid-template-columns: repeat(3, 1fr); }
    .dash-nav-tile:last-child:nth-child(odd) { grid-column: auto; }     /* 3열에선 「마지막 타일 전체폭」 규칙이 되레 어긋난다 */
}

/* 카드 사이 간격 — 공유 #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: 'Gowun Batang', serif; font-weight: 700; font-size: 16px; color: var(--text); }
.dash-header-name strong { color: var(--accent-hover); }
.dash-header-sub { font-size: 12px; color: var(--muted); }
/* 아바타 = 사용자 메뉴 토글 버튼(클릭 가능). 전역 button{width:100%}은 width:42px 고정(클래스 특이도)으로 상쇄. */
.dash-header-avatar {
    width: 42px; height: 42px; border-radius: 50%; flex-shrink: 0;
    background: var(--accent); color: var(--card-bg);
    display: flex; align-items: center; justify-content: center;
    font-family: 'Gowun Batang', serif; font-weight: 700; font-size: 18px;
    box-shadow: inset 0 0 0 3px var(--card-bg), 0 0 0 1px var(--border);
    padding: 0; border: none; cursor: pointer; appearance: none;
    overflow: hidden;   /* 작가 스프라이트를 원형으로 클립 */
    transition: filter .15s ease;
}
.dash-header-avatar:hover { filter: brightness(1.05); }
.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(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 12px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, .12);
    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: 8px;
    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); }

/* 2단 그리드 — auto-fit이라 자식이 하나면 전체폭으로 선다 */
.dash-grid-2col {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
    gap: clamp(16px, 2.2vw, 22px);
    align-items: start;
}
.dash-card-link { font-size: 13.5px; color: var(--accent-hover); text-decoration: none; }
.dash-card-link:hover { text-decoration: underline; }
/* 모드 토글 — pill과 한 줄(.dash-timer-head). 전역 button{width:100%}를 width:auto로 상쇄한다
   (안 하면 알약이 풀폭으로 늘어 머리줄이 깨진다). */
.dash-timer-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* 알약은 줄이지 않는다 — 힌트가 뜨면 토글 wrap이 2행으로 벌어지고, flex가 형제인 알약을 max-content
   아래로 짜부라뜨려 "오늘 읽은 시 / 간"처럼 단어 중간에서 쪼갠다(독서·공부 둘 다). */
.dash-timer-head .dash-pill { white-space: nowrap; }
.dash-mode-toggle-wrap { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.dash-mode-toggle { display: inline-flex; padding: 2px; border-radius: 999px; background: color-mix(in srgb, var(--text) 6%, transparent); }
.dash-mode-toggle button {
    width: auto; padding: 3px 10px; border: 0; border-radius: 999px;
    background: transparent; color: var(--muted); font: inherit; font-size: 12.5px; cursor: pointer;
}
.dash-mode-toggle button[aria-pressed="true"] { background: var(--sage-soft); color: var(--accent-hover); font-weight: 700; }
.dash-mode-toggle.is-locked { opacity: .4; }
.dash-mode-toggle.is-locked button { cursor: not-allowed; }
.dash-mode-hint { font-size: 12px; color: var(--muted); }

/* 공부 잉크 — 카드 스코프 토큰 스왑(미니앱 body.study-mode의 카드 한정판, 값은 그쪽과 같다).
   대시보드 카드(.dash-card)와 /study/history의 .card가 같은 클래스를 쓴다 — 규칙 하나가 두 화면을 덮는다.
   is-study가 없는 독서 카드엔 한 줄도 안 닿고, 카드 밖(브랜드 헤더 등)의 --accent도 그대로다.
   --nav-hover-*·--ok까지 덮는 이유: :root에서 var()로 해석된 값이라 --sage-soft만 덮어선 hover·요약 강조가
   세이지로 남는다. --ok가 닿는 곳은 공부 카드 안에선 .grass-summary strong뿐이다(.dash-*-ok는 독서 달성 전용). */
.is-study {
    --accent: #5F7E96; --accent-hover: #47657C; --sage-soft: #E6ECF0;
    --nav-hover-bg: #E6ECF0; --nav-hover-border: #D6E0E7;
    --ok: #47657C;
    /* 잔디 사다리 — 파랑 200·400·600·800(미니앱 --grass1~4). 0단(기록 없음)은 종이색 그대로 */
    --grass-1: #AFC4D2; --grass-2: #83A0B4; --grass-3: #536F85; --grass-4: #3A5266;
    /* 채움 전용 토큰은 공부 카드에서도 라이트 값 그대로다(:root와 같은 값) — origin/main 픽셀 보존.
       다크판만 아래 `:root[data-theme="dark"] .is-study`에서 파랑으로 간다. */
    --accent-fill: #6E8A6A; --accent-hover-2: #4F6B4C; --ok-fill: #2F8F6B;
    --sage-soft-2: #E7EEE2; --nav-hover-border-2: #CFE0C2;
}
.dash-timer-hero.is-study { background: #EFF3F6; }   /* 푸른 종이는 히어로만(미니앱 --heroCardBg) */
.is-study .dash-pill, .is-study .grass-streak,   /* 연속일 칩은 독서 카드에만 있어 .dash-streak-chip은 뺐다 */
.is-study .dash-progress-track,
.is-study .dash-btn-outline:hover { background: #E6ECF0; }   /* 리터럴 #E7EEE2 자리들 */
.is-study .dash-timer-num { color: #47657C; }
/* .btn-primary의 채움은 :root 토큰이 아니라 세이지 리터럴 rgba(110,138,106,…)이라 위 스왑이 안 닿는다 —
   공부 카드 안에서만 초록 버튼이 남아 「파랑 카드 + 파랑 글자 + 초록 버튼」이 됐다(/study/books가 첫 자리).
   hover는 :not(:disabled)로 좁힌다 — 안 그러면 .btn-primary:disabled:hover(같은 특이성·앞선 위치)를 눌러
   비활성 버튼까지 hover에 반응한다. 스코프가 공부 전용이라 독서 화면엔 한 줄도 안 닿는다. */
.is-study .btn-primary { background-color: var(--sage-soft); }
.is-study .btn-primary:hover:not(:disabled) { background-color: #D6E0E7; }  /* --nav-hover-border와 같은 한 단 짙은 파랑 */

/* 공부 서재(/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: 20px; font-size: 12px;
    background: var(--sage-soft); color: var(--accent-hover);
}
.study-count-actions { display: flex; gap: 6px; align-items: center; }

/* 공부 하루 목표 — 히어로 인라인 편집(설계 §2.3-ⓑ). 전부 공부 카드 안 클래스라 독서엔 0줄이다.
   전역 button{width:100%; padding:12px 18px; border-image:연필테}보다 특이성이 한 단 위(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: 12.5px;
    text-decoration: underline; cursor: pointer;
}
/* .dash-bookless의 align-self:center를 좌열(=.dash-timer-left, flex column)에선 왼쪽 정렬로 되돌린다. */
.dash-goal-set { align-self: flex-start; }
.dash-goal-edit { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; max-width: 420px; }
.dash-goal-edit input[type="number"] { width: 5.5em; }
/* 전역 button{width:100%} 상쇄 — 한 줄에 나란히 세운다(보조 둘은 .dash-bookless가 이미 width:auto). */
.dash-goal-edit .dash-btn-fill { width: auto; padding: 9px 16px; }

/* ============================================================
   인증 화면(로그인·회원가입) — 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'(Gowun Batang 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: 'Gowun Batang', 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;
}

/* 회원가입 히어로 — 'Gowun Batang' 25px 제목 + 서브카피(나머지는 Gowun Dodum) */
.auth-page .auth-hero { margin: 0 0 22px; }
.auth-page .auth-hero-title {
    font-family: 'Gowun Batang', 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: 1px solid var(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 18px;
    box-shadow: 0 1px 2px rgba(44, 42, 36, .05);
    padding: 26px 24px;
}

/* 필드 */
.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(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 12px;
    background: var(--card-bg);
    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(--accent);
    box-shadow: 0 0 0 3px var(--focus-ring);
}
/* 필드 에러 — 입력 테두리·링을 테라코타로(서버 검증 실패 시 th:classappend로 토글) */
.auth-page .auth-input.is-error,
.auth-page .auth-select.is-error {
    border-color: var(--danger-ink-2);
    box-shadow: 0 0 0 3px rgba(176, 82, 74, .18);
}

/* 셀렉트 — 기본 화살표 제거 + 커스텀 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: 12px;
    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: 12px;
    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 transparent;
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 12px;
    background-color: color-mix(in srgb, var(--accent-fill) 20%, transparent);
    color: var(--accent-hover);   /* 연한 채움 위에서 흰 글자는 읽히지 않는다 */
    font-family: inherit;
    font-weight: 700;
    font-size: 16px;
    cursor: pointer;
    transition: background .15s ease;
}
.auth-page .auth-btn-primary:hover { background-color: color-mix(in srgb, var(--accent-fill) 32%, transparent); }

/* 구분선 '또는' */
.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: 12.5px;
    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(--border);
    border-image: var(--pencil-frame) 8 / 8px stretch;
    border-radius: 12px;
    background: var(--card-bg);
    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(--bg); }
.auth-page .auth-btn-google svg { flex: 0 0 auto; }

/* 토스 코드 로그인 — 접힘 섹션(네이티브 <details>, JS 없음). 세 번째 선택지라 기본은 접어 둔다. */
.auth-page .auth-details {
    margin-top: 14px;
    border-top: 1px solid var(--border);
    padding-top: 14px;
}
.auth-page .auth-details > summary {
    cursor: pointer;
    font-size: 13.5px;
    color: var(--muted);
    list-style: none;          /* 기본 삼각형 제거(아래 ▸로 대체) */
    padding: 2px 0;
}
.auth-page .auth-details > summary::-webkit-details-marker { display: none; }
.auth-page .auth-details > summary::before {
    content: "▸";
    display: inline-block;
    margin-right: 6px;
    color: var(--accent);
    transition: transform .15s ease;
}
.auth-page .auth-details[open] > summary::before { transform: rotate(90deg); }
.auth-page .auth-details > form { margin-top: 12px; }

/* 알림 배너 — 에러/성공/로그아웃 (아이콘 + 텍스트) */
.auth-page .auth-alert {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 11px 14px;
    border-radius: 10px;
    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); }  /* 로그아웃만 아이콘 색≠텍스트 색(세이지 강조) */

/* 하단 링크 — 중앙정렬 세로 스택 */
.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(시안값).
   .btn-push-toggle 는 설정 전용(JS·구조 의존)이라 여기서 스위치로 재정의한다. ============================================================ */

/* 셸 — 시안 프레임 폭(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: 'Gowun Batang', serif; font-weight: 700; 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: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 18px; padding: 24px; margin-bottom: 16px; box-shadow: 0 1px 2px rgba(44, 42, 36, .05); }
/* ⚠️ 색만 바꾸고 `border` 단축은 쓰지 않는다 — 단축은 border-image를 initial로 리셋해서, 이 카드
   하나만 .set-card의 연필선을 잃고 매끈하게 남았다(2026-08-25 실측). 바로 아래 .set-input-danger가
   같은 이유로 이미 border-color만 쓰고 있다. 위험 신호는 제목·버튼의 빨강이 진다. */
.settings-page .set-card-danger { border-color: var(--danger-ink); box-shadow: 0 1px 2px rgba(192, 82, 74, .08); margin-bottom: 20px; }
.settings-page .set-card-title { font-family: 'Gowun Batang', serif; font-weight: 700; font-size: 17px; margin: 0 0 18px; color: 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: 12.5px; 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: 600;
    color: var(--text);
}

/* 필드 */
.settings-page .set-field { margin-bottom: 16px; }
.settings-page .set-label { display: block; font-size: 13px; font-weight: 700; margin-bottom: 7px; color: var(--text); }
.settings-page .set-input,
.settings-page .set-select {
    width: 100%; background: var(--surface); border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 14px;
    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(--accent); box-shadow: 0 0 0 3px var(--focus-ring); }
.settings-page .set-input-danger { border-color: var(--danger-line); }
.settings-page .set-input-danger:focus { border-color: var(--danger-ink); box-shadow: 0 0 0 3px rgba(192, 82, 74, .18); }

/* 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: 12.5px; color: var(--muted); line-height: 1.5; word-break: keep-all; }
.settings-page .set-field-error { display: block; margin-top: 7px; font-size: 12.5px; color: var(--danger-ink); line-height: 1.5; }

/* 저장 버튼(우측 정렬 pill) / 위험 버튼(전체폭 pill) */
.settings-page .set-actions { display: flex; justify-content: flex-end; margin-top: 20px; }
.settings-page .set-btn-save { width: auto; background: var(--accent); color: var(--on-accent); border: none; border-radius: 999px; padding: 11px 24px; font-family: inherit; font-size: 14px; font-weight: 700; cursor: pointer; transition: background .15s; }
.settings-page .set-btn-save:hover { background: var(--accent-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: var(--danger-ink); color: var(--on-accent); border: none; border-radius: 999px; padding: 12px 24px; font-family: inherit; font-size: 14px; font-weight: 700; cursor: pointer; transition: background .15s; }
.settings-page .set-btn-danger:hover { background: var(--danger-ink-deep); }

/* 커스텀 체크박스(밀린시간 합산 / 복귀 메일) — 실제 <input>은 숨기고 박스 span으로 그린다 */
.settings-page .set-check { display: flex; align-items: flex-start; gap: 11px; cursor: pointer; }
.settings-page .set-check--card { background: var(--sage-soft); border: 1px solid var(--sage-line);
    border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 14px; padding: 14px; }
.settings-page .set-check input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0; }
.settings-page .set-check-box {
    flex-shrink: 0; width: 22px; height: 22px; border-radius: 7px; 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 { opacity: 0; }
.settings-page .set-check input:checked ~ .set-check-box { background: var(--accent); }
.settings-page .set-check input:checked ~ .set-check-box svg { opacity: 1; }
.settings-page .set-check 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: 700; 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: 12.5px; color: var(--muted); line-height: 1.5; word-break: keep-all; }

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

/* 플래시(아이콘 + 텍스트) */
.settings-page .set-alert { display: flex; align-items: center; gap: 10px; border-radius: 14px; 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: 14px; 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: 700; 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: 700; 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: 12.5px; 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: 11.5px; 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; }

/* 스위치(푸시 토글) — .btn-push-toggle(JS가 .is-on 토글). 전역 button{width:100%}를 스코프로 덮는다. */
.settings-page .btn-push-toggle {
    flex-shrink: 0; position: relative; width: 52px; height: 30px; margin-top: 2px;
    border: none; border-radius: 999px; padding: 0; background: var(--line-2); cursor: pointer;
    transition: background .2s;
}
.settings-page .btn-push-toggle.is-on { background: var(--accent); }
.settings-page .btn-push-toggle:disabled { opacity: .5; cursor: not-allowed; }
.settings-page .set-switch-knob {
    position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: 999px;
    background: var(--surface); display: flex; align-items: center; justify-content: center;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .25); color: var(--neutral-3-3); transition: transform .2s;
}
.settings-page .btn-push-toggle.is-on .set-switch-knob { transform: translateX(22px); color: var(--accent-hover); }
/* 리마인더: 켜짐=종, 꺼짐=종끄기(모양 교체). 마케팅: 확성기 1개(색만 knob color로 변함). */
.settings-page .set-switch-ico { display: block; }
.settings-page .set-switch-ico-on { display: none; }
.settings-page .btn-push-toggle.is-on .set-switch-ico-on { display: block; }
.settings-page .btn-push-toggle.is-on .set-switch-ico-off { display: none; }
/* ═══════════════ 여백 (책에 딸린 자리 — 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: 6px;
    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 #FAF7EF;
}
/* 「여백」 손잡이 — 상태 배지 줄(.shop-book-foot)의 작은 칩 버튼 */
.shop-margin-btn {
    width: auto; /* 전역 button width:100% 상쇄 */
    background: none; border: 1px solid var(--border);
 border-image: var(--pencil-frame) 8 / 8px stretch; border-radius: 999px;
    color: var(--accent-hover); font-size: 11.5px; font-weight: 600;
    padding: 3px 10px; cursor: pointer; appearance: none;
}
.shop-margin-btn:hover { background: var(--sage-soft); }

/* ── 배경 팔레트 — 닫힌 코드 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; }

/* ── 여백 패널 (책 하나의 글 목록 오버레이 — 옛 풀스크린 뷰어 자리) ── */
.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-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: 700; color: var(--text); line-height: 1.4; }
.margin-book-sub { font-size: 12.5px; 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: 12.5px; color: var(--muted); }
.margin-compose { justify-content: center; }
.margin-empty { margin: 8px 0 0; font-size: 14px; color: var(--muted); line-height: 1.6; }
.margin-cards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.margin-card { border-radius: 12px; padding: 16px; }
.margin-card-text {
    margin: 0; font-family: 'Gowun Batang', 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: 'Gowun Batang', 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: 12px; 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: 12px; 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: 12px; 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: 12px; 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-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: 700; font-size: 16px; }
.story-composer-preview { border-radius: 12px; padding: 14px; }
.story-composer-input {
    width: 100%; background: none; border: none; resize: vertical;
    color: inherit; font-family: 'Gowun Batang', 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: 11px; 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: 12px; 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: 12px; 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: 12px; color: var(--muted);
    background: var(--bg); border-radius: 8px; 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: 700; 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: 12px; 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: 10px;
    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: 700; }
/* 미래 칸 — 일정은 보이되 지킴 표시만 잠근다(탭하면 그날이 열리기만 한다) */
.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: 10px; color: var(--muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.study-flags { display: flex; gap: 3px; }
.study-flag {
    font-size: 9px; line-height: 1.4; padding: 0 3px; border-radius: 4px;
    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: 12px; 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)이 쓰는 것과 같은 연필선 재료다. 새 값을 만들지 않는다.
   ⚠️ 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 transparent;
    border-image: var(--pencil-frame-soft) 8 / 8px stretch;
    border-radius: 10px;
    background: var(--card-bg);
    color: var(--text);
}
.study-day input:focus,
.study-day textarea:focus,
.study-day select:focus {
    outline: none;
    /* border-color는 border-image가 덮어 안 보인다 → 프레임을 진한 연필선으로 갈아 포커스를 표시하고,
       접근성용 링은 그대로 남긴다(.field input:focus와 같은 처방). */
    border-image: var(--pencil-frame) 8 / 8px stretch;
    box-shadow: 0 0 0 3px var(--focus-ring);
}
.study-day ::placeholder { color: var(--muted); opacity: .75; }

/* 책 고르기 — 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: 12px; 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: 12px; 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; }

/* 백지복습 — 쓰는 자리가 화면의 주인공이라 본문 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 transparent;
    border-image: var(--pencil-frame-soft) 8 / 8px stretch;
    border-radius: 10px;
    background: var(--card-bg);
    color: var(--text);
    padding-top: 4px;   /* 연필선(바깥 ≤3.1px)이 툴바 배경 아래로 들어가지 않게. 4~8px 띠는 투명이라 4면 충분 */
}
/* 포커스 링은 안쪽 contenteditable이 받으므로 상자가 대신 표시한다(.study-day input:focus와 같은 처방). */
.study-editor:focus-within {
    border-image: var(--pencil-frame) 8 / 8px stretch;
    box-shadow: 0 0 0 3px var(--focus-ring);
}
/* 폰에서 키보드가 올라와도 툴바가 남게 sticky — 스크롤되는 것은 글이지 도구가 아니다.
   좌우 4px margin도 같은 이유(연필선 보호)다. 툴바 배경이 편집기와 같은 --card-bg라 그 4px은 안 보이고,
   sticky로 붙었을 때 옆 4px 띠에는 편집기 세로 연필선만 지나간다(본문은 .ProseMirror padding 12px 안쪽).
   위쪽은 margin-top이 아니라 부모 padding-top으로 띄운다 — sticky 요소의 위 margin이 top:0 계산에
   끼는지는 구현 디테일이라, 확실히 안 끼는 부모 패딩으로 둔다. */
.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: 10px 10px 0 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: 8px; 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); opacity: .75; pointer-events: none;
}
.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; }
.study-editor .ProseMirror h1 { font-size: 19px; }
.study-editor .ProseMirror h2 { font-size: 16px; }
.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: 3px; 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; }

/* 슬래시 메뉴 — 캐럿 좌표는 컴포넌트가 인라인 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(--border); border-radius: 10px;
    background: var(--card-bg); box-shadow: 0 6px 20px rgba(0, 0, 0, .12);
}
.study-editor-slash-item {
    display: block; width: 100%; padding: 7px 10px; text-align: left;
    border: 0; border-radius: 7px; 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: 600; }
.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: 12px; 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: 10px; padding: 10px 12px; background: var(--sage-soft);
}

/* 채점 기준 카드 — 「무엇과 대조해 구멍을 찾는가」. 결과 카드(.study-recall-result)와 같은 결이되
   바탕을 깔지 않는다: 이건 입력 쪽 정보라 옆의 책·주제·범위와 한 묶음으로 읽혀야 한다. */
.study-recall-reference { border: 1px solid var(--border); border-radius: 10px; 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); }

/* 필기 — 좌우 배선(.study-recall-split/side/main)은 백지복습 것을 그대로 쓴다. 여기 있는 것은
   좌측 목록과 상태줄뿐이다. 상태줄은 이 화면에서 저장 버튼을 대신하므로 비어 있어도 자리를
   차지한다(min-height) — 글자가 들고 날 때마다 편집기가 위아래로 뛰면 쓰던 자리를 잃는다. */
.study-notes { display: flex; flex-direction: column; gap: 8px; }
.study-notes input, .study-notes .study-recall-book { width: 100%; }
.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: 8px;
    background: transparent; color: inherit; font: inherit; cursor: pointer;
}
.study-notes-item.is-active { border-color: var(--accent); background: var(--sage-soft); }
.study-notes-label { overflow-wrap: anywhere; }
.study-notes-meta { font-size: 12px; 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`을 타고 값 입력칸까지 12px로
   끌어내려, 같은 폼의 다른 칸(18px)과 글씨 크기가 어긋난다. 12px은 이름표의 크기이지 값의 크기가 아니다. */
.study-plan-row label { display: flex; flex-direction: column; gap: 4px; }
.study-plan-row label > span { font-size: 12px; color: var(--muted); }
.study-plan-row input { width: 100%; max-width: 180px; }
.study-plan-preview {
    border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; background: var(--sage-soft);
}
.study-plan-heading { margin: 0 0 6px; font-size: 12px; color: var(--muted); }
.study-plan-week + .study-plan-week { margin-top: 8px; }
.study-plan-week-label { margin: 0 0 2px; font-size: 12px; font-weight: 600; 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: 12px; }
.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; }

/* ── 데스크톱 와이드 페이지 (/study 셸 — 일정·기록·공부 서재) ──
   달력과 책 목록은 460px에서 답답하다(달력은 한 칸이 60px, 긴 책 제목은 3줄로 접힌다).
   홈과 같은 1160px을 쓰되 **폼은 따라 늘리지 않는다** — 입력 한 칸이 1100px이면 되레 쓰기 나쁘다.
   `/search`(사용자 검색)를 여기 넣지 않은 것도 같은 이유다: 그 화면은 폼과 한 줄짜리 결과가 전부라
   넓히면 「팔로우」 버튼만 저 멀리 떨어진다(넓혀서 손해인 화면은 넓히지 않는다). */
@media (min-width: 900px) {
    .container.wide-page { max-width: 1160px; }
    .container.wide-page .book-search-form,
    .container.wide-page .book-manual-form,
    .container.wide-page .study-day-form,
    .container.wide-page .study-plan-form { max-width: 620px; }
}

/* 테마 토글 — theme.js가 header.brand / header.auth-brand 끝에 꽂는다(아직 다크런치라 안 꽂힌다).
   `border` 단축 선언이 전역 `button`의 border-image를 initial로 되돌리는 것을 그대로 이용한다 —
   32px 원형에 300px 연필 타일을 8px로 눌러 넣으면 결이 뭉개진다(.margin-card-btn과 같은 이유).
   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; }

/* ── 다크 테마 ────────────────────────────────────────────
   `:root`의 색 토큰만 덮는다. 토큰이 안 닿는 raw 리터럴 규칙(설정 배너·상태 배지·흰 채움 등)은
   아직 크림색으로 남아 있고, 그래서 이 단계는 다크런치다 — 토글을 안 꽂았으므로 저장값을
   손으로 넣지 않는 한 아무도 이 블록을 보지 못한다(theme.js 끝 주석).

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

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

    --bg: #1E1C18;          /* 어두운 종이(따뜻한 차콜) */
    --card-bg: #26231E;     /* 카드 표면 — 배경보다 한 단 밝게 */
    --text: #E8E2D6;        /* 잉크 반전 — 순백이 아니라 종이색 계열이라 눈이 덜 시리다 */
    --muted: #A8A196;
    --accent: #8FAE86;      /* = 라이트 --sage-7. 다크에선 원래 세이지(#6E8A6A)가 너무 가라앉는다 */
    --accent-hover: #B6C9AE;/* 다크는 hover가 '더 밝은' 쪽이다 — 라이트와 방향이 반대 */
    --danger: #E5766B;      /* 라이트의 #dc2626은 다크 위에서 대비가 안 난다 */
    --danger-hover: #F0918A;
    --border: #3A362F;      /* 장식선(실제 테두리는 연필 프레임이 그린다) */
    --ok: #5FBF95;
    --shadow: 0 1px 2px rgba(0,0,0,.35), 0 8px 24px rgba(0,0,0,.40);
    --sage-soft: #2E3A2C;
    --nav-hover-border: #45563F;    /* --nav-hover-bg는 var(--sage-soft) 별칭이라 자동으로 따라온다 */
    --focus-ring: rgba(143, 174, 134, .40);

    /* 의미 토큰 다크판 — 라이트 짝과 1:1이다(darkTokens.test.ts가 양방향으로 센다).
       채움은 어두운 쪽으로, 글자는 밝은 쪽으로 뒤집는다. 채움 위 글자 대비는 전부 AA(4.5) 이상으로
       잡았고, 그중 --on-accent는 테스트가 직접 계산해 지킨다 — 밝은 세이지 채움 위에 흰 글자를
       그대로 두면 2.45라, 이 한 자리가 다크에서 유일하게 AA를 못 넘던 곳이었다. */
    --surface: #2C2823;
    --on-accent: #1E1C18;   /* 밝은 accent 채움 위엔 어두운 글자다(라이트와 방향이 반대) */
    --paper-1: #24211C;
    --line-1: #33302A;
    --line-2: #4A4538;
    --sage-hover: #3A4A36;
    --sage-line: #45563F;
    --ok-soft: #22392F;
    --ok-line: #35544A;
    --ok-ink: #8FD5B4;
    --warn-bg: #3A3222;
    --warn-border: #5A4A2A;
    --warn-fg: #E0B86A;
    --danger-soft: #33201D;
    --danger-line: #5A3A34;
    --danger-ink: #E5766B;
    --danger-ink-deep: #F0918A;
    --info-soft: #232E3B;
    --info-ink: #8FB4E8;
    --ink-2: #C6BFB2;
    --scrim: rgba(0, 0, 0, .62);        /* 어두운 화면 위에선 딤이 더 진해야 층이 보인다 */
    --scrim-soft: rgba(0, 0, 0, .5);

    /* 계열 변종의 다크판 — 라이트에서 갈라진 값들이 여기선 계열 대표값 하나로 모인다.
       라이트를 「지금 그대로」 두느라 토큰이 늘었을 뿐, 다크 팔레트는 갈라질 이유가 없다.
       (같은 계열 안에서 값이 전부 같은 것은 실수가 아니라 의도다 — 대표값을 조정할 땐 함께 옮긴다.) */
    --warn-bg-2: #3A3222;
    --warn-bg-3: #3A3222;
    --warn-bg-4: #3A3222;
    --warn-border-2: #5A4A2A;
    --warn-border-3: #5A4A2A;
    --warn-border-4: #5A4A2A;
    --warn-fg-2: #E0B86A;
    --warn-fg-3: #E0B86A;
    --warn-fg-4: #E0B86A;
    --warn-fg-5: #E0B86A;
    --ok-soft-2: #22392F;
    --ok-soft-3: #22392F;
    --ok-soft-4: #22392F;
    --ok-soft-5: #22392F;
    --ok-line-2: #35544A;
    --ok-line-3: #35544A;
    --ok-ink-2: #8FD5B4;
    --danger-soft-2: #33201D;
    --danger-soft-3: #33201D;
    --danger-soft-4: #33201D;
    --danger-soft-5: #33201D;
    --danger-line-2: #5A3A34;
    --danger-line-3: #5A3A34;
    --danger-line-4: #5A3A34;
    --danger-ink-2: #E5766B;
    --danger-ink-deep-2: #F0918A;
    --danger-ink-deep-3: #F0918A;
    --danger-ink-deep-4: #F0918A;
    --info-soft-2: #232E3B;
    --info-soft-3: #232E3B;
    --info-soft-4: #232E3B;
    --line-1-2: #33302A;
    --line-1-3: #33302A;
    --line-1-4: #33302A;
    --line-1-5: #33302A;
    --line-1-6: #33302A;
    --line-1-7: #33302A;
    --line-2-2: #4A4538;
    --paper-1-2: #24211C;
    --paper-1-3: #24211C;
    --paper-2-2: #2A2722;
    --paper-2-3: #2A2722;
    --paper-4-2: #24211C;
    --border-2: #3A362F;
    --border-3: #3A362F;
    --border-4: #3A362F;
    --muted-2: #A8A196;
    --neutral-3-2: #9A9486;
    --neutral-3-3: #9A9486;
    --sage-hover-2: #3A4A36;
    --sage-line-2: #45563F;
    --scrim-2: rgba(0, 0, 0, .62);
    --scrim-3: rgba(0, 0, 0, .62);
    --accent-fill: #8FAE86;
    --accent-hover-2: #B6C9AE;
    --ok-fill: #5FBF95;
    --sage-soft-2: #2E3A2C;
    --nav-hover-border-2: #45563F;
    --muted-3: #A8A196;
    --paper-2: #2A2722;
    --paper-3: #2E2A24;
    --paper-4: #24211C;
    --sage-1: #2F332A;
    --sage-2: #2C3A2E;
    --sage-3: #33392B;
    --sage-4: #4A5540;
    --sage-5: #4E6247;
    --sage-6: #5C7456;
    --sage-7: #7E9C76;
    --sage-8: #93A184;
    --neutral-1: #4A4538;
    --neutral-2: #5A5346;
    --neutral-3: #9A9486;
    /* 잔디 — 미달에서 달성으로 갈수록 '밝아진다'(라이트는 진해진다). 어두운 종이 위에서
       진해지는 사다리는 배경에 먹혀 0단계와 4단계가 구별되지 않는다. */
    --grass-0: #2C2A25;
    --grass-1: #3E5A34;
    --grass-2: #55804A;
    --grass-3: #7BAA6B;
    --grass-4: #A6D293;
    --graphite: #B8B1A6;

    /* 연필선·종이 결 — 라이트 URI에서 '선 색'과 '입자 색'만 갈아끼운 같은 그림이다.
       필터 계수(알파 행·baseFrequency·seed)는 건드리지 않는다: 결의 정체는 색이 아니라 밀도이고,
       25% 밀도는 라이트에서 사용자 반려 두 번을 거쳐 정해진 값이다(T-191·T-193).
       어두운 종이 위에선 어두운 입자가 안 보이므로 입자만 밝은 쪽으로 뒤집는다. */
    --pencil-frame: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='a' x='-20%25' y='-20%25' width='140%25' height='140%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.5' numOctaves='4' seed='5' result='g'/%3E%3CfeColorMatrix in='g' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.55 0 0 0 0.62' result='m'/%3E%3CfeComposite in='SourceGraphic' in2='m' operator='in'/%3E%3C/filter%3E%3Cfilter id='b' x='-20%25' y='-20%25' width='140%25' height='140%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.5' numOctaves='4' seed='23' result='g'/%3E%3CfeColorMatrix in='g' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0 0 0 0.25' result='m'/%3E%3CfeComposite in='SourceGraphic' in2='m' operator='in'/%3E%3C/filter%3E%3Crect x='1.6' y='1.6' width='296.8' height='296.8' rx='7' fill='none' stroke='%23B8B1A6' stroke-width='1.9' filter='url(%23a)'/%3E%3Crect x='2.4' y='2.4' width='295.2' height='295.2' rx='7' fill='none' stroke='%23A19A8E' stroke-width='1.4' filter='url(%23b)'/%3E%3C/svg%3E");
    --pencil-frame-soft: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='a' x='-20%25' y='-20%25' width='140%25' height='140%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.5' numOctaves='4' seed='13' result='g'/%3E%3CfeColorMatrix in='g' type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0 0 0 0.55' result='m'/%3E%3CfeComposite in='SourceGraphic' in2='m' operator='in'/%3E%3C/filter%3E%3Crect x='1.7' y='1.7' width='296.6' height='296.6' rx='7' fill='none' stroke='%23847D72' stroke-width='1.6' filter='url(%23a)'/%3E%3C/svg%3E");
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.82 0 0 0 0 0.78 0 0 0 0 0.70 0.7 0 0 0 -0.40'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
    --fiber: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='440' height='440'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008 0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.84 0 0 0 0 0.80 0 0 0 0 0.72 0.4 0 0 0 -0.26'/%3E%3C/filter%3E%3Crect width='440' height='440' filter='url(%23f)'/%3E%3C/svg%3E");
}

/* 공부 잉크 다크 — `.is-study`가 파랑 리터럴로 덮는 토큰들의 다크판.
   이게 없으면 공부 화면만 다크에서 세이지로 튄다(라이트에선 파랑인데 다크에선 초록이 되는 셈). */
:root[data-theme="dark"] .is-study {
    --accent: #8FA9BE;
    --accent-hover: #AFC4D2;
    --sage-soft: #27323B;
    --nav-hover-bg: #27323B;
    --nav-hover-border: #3A4C5A;
    --ok: #AFC4D2;
    --accent-fill: #8FA9BE; --accent-hover-2: #AFC4D2; --ok-fill: #AFC4D2;
    --sage-soft-2: #27323B; --nav-hover-border-2: #3A4C5A;
    --grass-1: #34495A;
    --grass-2: #4A6A80;
    --grass-3: #6F92AA;
    --grass-4: #A0BED0;
}
/* `.is-study`가 토큰이 아니라 값으로 직접 칠한 자리들 — 토큰 스왑이 안 닿아 따로 덮는다. */
:root[data-theme="dark"] .dash-timer-hero.is-study { background: #222A30; }
:root[data-theme="dark"] .is-study .dash-pill,
:root[data-theme="dark"] .is-study .grass-streak,
:root[data-theme="dark"] .is-study .dash-progress-track,
:root[data-theme="dark"] .is-study .dash-btn-outline:hover { background: #27323B; }
:root[data-theme="dark"] .is-study .dash-timer-num { color: #AFC4D2; }
:root[data-theme="dark"] .is-study .btn-primary:hover:not(:disabled) { background-color: #3A4C5A; }
}
