/*
 * 성경 단어 빈도 통계 다이얼로그
 * 설계 문서: docs/bible/word-frequency-design.md §10
 *
 * 색상은 전부 theme.css 토큰으로 참조한다(raw hex 금지).
 *
 * 클라우드와 목록은 같은 데이터를 두 번 보여 주는 것이 아니라 역할이 다르다.
 * 클라우드는 인상(무엇이 이 장을 지배하는가), 목록은 사실(정확히 몇 번인가)이다.
 * 그래서 목록에는 **빈도 비례 막대**를 깔았다. 워드클라우드는 글자 길이가 크기 인식에
 * 섞여 들어 '하나님(30)' 과 '땅(18)' 의 차이를 제대로 못 읽게 하는데, 막대는 길이 하나로만
 * 인코딩하므로 그 약점을 정확히 메운다.
 */

.word-stats-dialog {
    /* 목록 막대. 글자를 가리지 않을 만큼만 옅게. */
    --word-stats-bar: color-mix(in srgb, var(--color-accent) 15%, transparent);
    --word-stats-bar-top: color-mix(in srgb, var(--color-accent) 26%, transparent);

    width: min(680px, calc(100vw - 24px));
    max-height: min(82vh, 820px);
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: 14px;
    background-color: var(--color-bg-base);
    color: var(--color-text-primary);
    box-shadow: 0 10px 30px var(--color-shadow);
    overflow: hidden;
}

/*
 * **display 는 반드시 [open] 에만 건다.**
 * 브라우저 기본 스타일의 `dialog:not([open]) { display: none }` 은 UA 스타일이라
 * 작성자 스타일에 진다. `.word-stats-dialog { display: flex }` 로 두면 닫힌 다이얼로그가
 * 문서 흐름에 그대로 그려져, 페이지 하단에 헤더만 잘린 채 노출된다.
 *
 * 높이는 다이얼로그만 정하고 본문은 남는 만큼 채운다. 예전에는 본문에도
 * calc(86vh - 60px) 를 따로 걸어 뒀는데, 헤더 높이를 60px 로 가정한 값이라 실제와
 * 어긋나면 본문이 다이얼로그를 넘어 overflow: hidden 에 잘렸다.
 */
.word-stats-dialog[open] {
    display: flex;
    flex-direction: column;
}

/* 열릴 때 프로그램적으로 포커스를 받는 컨테이너다. tabindex="-1" 이라 Tab 으로는 닿지 않으므로
   테두리를 지워도 키보드 사용자가 위치를 잃지 않는다. */
.word-stats-dialog:focus {
    outline: none;
}

.word-stats-dialog::backdrop {
    background-color: rgba(0, 0, 0, 0.45);
}

.word-stats-header {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--color-border);
    background-color: var(--color-bg-elevated);
}

.word-stats-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
}

.word-stats-body {
    flex: 1 1 auto;
    min-height: 0;               /* 이게 없으면 flex 항목이 줄어들지 않아 스크롤이 생기지 않는다 */
    padding: 14px 16px 20px;
    overflow-y: auto;
}

.word-stats-status {
    margin: 24px 0;
    text-align: center;
    color: var(--color-text-secondary);
    font-size: 0.9rem;
}

/* ---------- 요약 ---------- */

.word-stats-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 2px 12px;
    margin-bottom: 12px;
}

.word-stats-summary-main {
    font-size: 0.9rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.word-stats-summary-meta {
    font-size: 0.75rem;
    color: var(--color-text-muted);
}

/* ---------- 워드 클라우드 ---------- */

.word-stats-cloud-wrap {
    margin-bottom: 18px;
    padding: 12px 10px 8px;
    border: 1px solid var(--color-border);
    border-radius: 12px;
    background-color: var(--color-bg-elevated);
}

.word-stats-cloud {
    display: block;
    width: 100%;
    height: auto;
    max-height: 300px;
    overflow: visible;
    /* **word-stats.js 의 CLOUD_FONT_FAMILY 와 반드시 같아야 한다.**
       충돌 박스는 캔버스로 재고 그리기는 여기서 하므로, 다르면 글자가 겹치거나 헛되이 벌어진다. */
    font-family: system-ui, -apple-system, "Segoe UI", Roboto,
        "Malgun Gothic", "Apple SD Gothic Neo", sans-serif;
}

/* 누를 수 있다는 신호. 클라우드 글자에는 밑줄·테두리를 상시로 줄 수 없어 문구로 대신한다. */
.word-stats-cloud-hint {
    margin: 10px 0 0;
    text-align: center;
    font-size: 0.74rem;
    color: var(--color-text-muted);
}

/*
 * 색은 빈도에 따라 **연속으로** 보간한다. `--t` 는 JS 가 넣는 0~1 값이고,
 * 글자 크기를 정한 것과 같은 값이라 색과 크기가 서로 어긋나지 않는다.
 *
 * 4단계로 끊었을 때는 6회와 5회 사이에 설명할 수 없는 색 절벽이 생겼다.
 *
 * 양 끝점을 --color-accent 와 --color-text-secondary 로 잡은 것이 대비 안전장치다.
 * 두 토큰 모두 라이트·다크에서 본문 대비를 통과하므로 그 사이 어떤 혼합도 안전하다.
 * 예전에 가장 흐린 단계를 --color-text-muted 까지 내렸다가 되돌린 적이 있다.
 * #adb5bd 를 카드 배경(#f8f9fa) 위에 얹으면 대비가 2:1 남짓이라 WCAG 를 통과하지 못한다.
 */
.word-stats-cloud-word {
    --t: 0;

    font-weight: 700;
    cursor: pointer;
    fill: var(--color-text-secondary);   /* color-mix 미지원 환경 대비 */
    fill: color-mix(in srgb, var(--color-accent) calc(var(--t) * 100%), var(--color-text-secondary));
}

/* ---------- 빈도 목록 (접근성의 본체) ---------- */

.word-stats-section-title {
    margin: 0 0 8px;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--color-text-secondary);
}

/* 다이얼로그 폭 680px 에서 2열, 모바일에서 1열. 3열까지 가면 막대가 너무 짧아져
   길이 비교라는 목적을 잃는다. */
.word-stats-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
    gap: 2px 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.word-stats-item {
    display: block;
}

.word-stats-link {
    --ratio: 0;

    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding: 5px 9px;
    border-radius: 7px;
    text-decoration: none;
    color: var(--color-text-primary);
    /* 빈도 비례 막대. 배경으로 깔아 DOM 요소를 늘리지 않는다. */
    background-image: linear-gradient(
        to right,
        var(--word-stats-bar) calc(var(--ratio) * 100%),
        transparent calc(var(--ratio) * 100%)
    );
    background-repeat: no-repeat;
}

/* 크기 차이는 클라우드가 이미 표현했다. 목록은 막대가 정량을 맡으므로
   글자 크기를 좁게 유지해 행 리듬을 지킨다. */
.word-stats-link.tier-1 {
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-accent);
    background-image: linear-gradient(
        to right,
        var(--word-stats-bar-top) calc(var(--ratio) * 100%),
        transparent calc(var(--ratio) * 100%)
    );
}

.word-stats-link.tier-2 { font-size: 0.96rem; font-weight: 600; }
.word-stats-link.tier-3 { font-size: 0.92rem; }
.word-stats-link.tier-4 { font-size: 0.88rem; color: var(--color-text-secondary); }

.word-stats-term {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.word-stats-count {
    flex: none;
    font-size: 0.78em;
    color: var(--color-text-secondary);
    /* 자릿수가 달라도 오른쪽 끝이 흔들리지 않게 */
    font-variant-numeric: tabular-nums;
}

.word-stats-link:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 1px;
}

.word-stats-footnote {
    margin: 14px 0 0;
    padding: 8px 10px;
    border-radius: 8px;
    background-color: var(--color-bg-elevated);
    font-size: 0.78rem;
    color: var(--color-text-secondary);
}

/* ---------- 단어 팝오버 ---------- */

.word-stats-popover {
    position: absolute;
    left: 16px;
    right: 16px;
    bottom: 16px;
    max-width: 420px;
    margin-inline: auto;
    padding: 12px 14px;
    border: 1px solid var(--color-border);
    border-radius: 12px;
    background-color: var(--color-bg-elevated-bright);
    box-shadow: 0 6px 18px var(--color-shadow);
}

.word-stats-popover-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 6px;
}

.word-stats-popover-heading {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
}

.word-stats-popover-count {
    font-size: 0.8rem;
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
}

.word-stats-popover-desc {
    margin: 0 0 10px;
    font-size: 0.86rem;
    line-height: 1.5;
    color: var(--color-text-secondary);
    max-height: 6.5em;
    overflow-y: auto;
}

.word-stats-popover-desc:empty {
    margin: 0;
}

.word-stats-popover-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

/* ---------- 반응형 ---------- */

@media (max-width: 480px) {
    .word-stats-body { padding: 12px 12px 18px; }

    /*
     * 클라우드는 장식이다. 좁은 화면에서 280px 를 차지하면 다이얼로그를 연 첫 화면이
     * 거의 클라우드로만 채워져 정작 숫자가 한 줄도 보이지 않는다. 인상을 주기에는
     * 190px 로 충분하고, 남는 자리를 상위 몇 개 항목에 내준다.
     */
    .word-stats-cloud { max-height: 190px; }
    .word-stats-cloud-wrap { padding: 8px 6px 4px; margin-bottom: 12px; }
    .word-stats-cloud-hint { margin-top: 6px; font-size: 0.72rem; }

    /* 항목이 수십 개라 행 높이가 곧 전체 길이다. 다만 터치 목표를 해치지 않는 선까지만 줄인다. */
    .word-stats-link { padding: 6px 8px; }
    .word-stats-list { gap: 1px 8px; }
}

/* 터치 기기에서 hover 가 눌린 채 남는 문제 때문에 데스크톱에서만 적용한다 */
@media (hover: hover) and (pointer: fine) {
    .word-stats-link:hover {
        background-color: var(--color-bg-elevated-strong-hover);
    }

    /*
     * **SVG <text> 에 text-decoration 을 쓰지 않는다.**
     * 이 요소는 dominant-baseline: central 로 글자를 y 좌표 중앙에 맞추는데, 크롬은 밑줄을
     * 그 보정을 무시한 자리에 그린다. 글자 위를 지나는 줄이 생겨 밑줄이 아니라 오작동으로 보인다.
     * 위치 계산에 기대지 않는 색과 크기로 대신한다.
     */
    .word-stats-cloud-word:hover {
        fill: var(--color-accent);
        transform-box: fill-box;
        transform-origin: center;
        /* 충돌 박스의 여백(PADDING) 안에서만 커지도록 낮게 잡는다. 더 키우면 옆 단어를 침범한다. */
        transform: scale(1.06);
    }
}

@media (prefers-reduced-motion: no-preference) {
    .word-stats-cloud-word {
        transition: fill 0.15s ease, transform 0.15s ease;
    }

    .word-stats-link {
        transition: background-color 0.15s ease;
    }
}

/* ---------- 모바일: 바텀 시트 ---------- */

/*
 * 좁은 화면에서는 가운데 뜬 카드가 아니라 **아래에서 올라오는 시트**다.
 * 이 저장소에는 이미 같은 판단이 둘 있다(top-nav 계정 메뉴, 성경 역사 지도 상세 패널).
 * 기준 폭도 그쪽과 같은 599.98px 로 맞춘다.
 *
 * 데스크톱까지 시트로 바꾸지는 않는다. 680px 짜리 2열 목록을 화면 바닥에 붙이면
 * 클라우드와 목록이 시선에서 멀어지기만 하고 얻는 것이 없다.
 *
 * 이 블록은 파일 맨 뒤에 둔다. 위의 `@media (max-width: 480px)` 가 .word-stats-body 의
 * padding 을 단축 속성으로 덮어쓰므로, 안전 영역을 더한 아래 여백이 뒤에 와야 살아남는다.
 */

/* 그립은 시트일 때만 존재한다. 데스크톱 다이얼로그에는 잡을 가장자리가 없다. */
.word-stats-sheet-grip {
    display: none;
}

@media (max-width: 599.98px) {
    .word-stats-dialog {
        /*
         * **max-width 를 반드시 none 으로 되돌린다.**
         * UA 스타일의 `dialog:modal` 은 `max-width: calc(100% - 6px - 2em)` 을 걸어 두므로,
         * width: 100% 만 써 두면 좌우에 32px 남짓한 틈이 남아 바닥에 붙지 않은 카드가 된다.
         */
        width: 100%;
        max-width: none;
        max-height: 85vh;
        max-height: 85dvh;
        /* 위는 auto 로 밀고 아래는 0 — UA 의 `inset: 0 + margin: auto`(가운데 정렬)를 바닥 정렬로 바꾼다 */
        margin: auto auto 0;
        /*
         * 화면 끝에서 끝까지 붙는 시트라 좌·우·아래 테두리는 그릴 자리가 없다.
         * 남겨 두면 border-box 가 아닐 때 좌우로 1px 씩 삐져나가기까지 한다.
         */
        border-inline: 0;
        border-bottom: 0;
        border-radius: 16px 16px 0 0;
        box-shadow: 0 -8px 28px var(--color-shadow);
        /* 손을 떼면 제자리로 돌아가는 스냅백 */
        transition: transform 220ms cubic-bezier(0.32, 0.72, 0, 1);
    }

    /*
     * 들어오는 애니메이션은 **한 번만** 재생되어야 한다.
     *
     * `[open]` 에 걸면 안 된다. 아래 `.is-dragging` 이 `animation: none` 으로 애니메이션을
     * 취소하는데, 손을 뗄 때 그 클래스가 빠지면서 `animation-name` 이 되살아나면
     * **브라우저가 애니메이션을 새로 만든다.** [open] 은 계속 참이므로 조건이 늘 맞고,
     * 결국 시트를 한 번 건드릴 때마다 화면 밖에서 다시 올라온다.
     *
     * 그래서 여는 순간에만 붙였다가 `animationend` 에서 떼는 일회용 클래스로 건다
     * (word-stats.js 의 SHEET_OPEN_ANIMATION).
     */
    .word-stats-dialog[open].is-opening {
        animation: word-stats-sheet-in 260ms cubic-bezier(0.32, 0.72, 0, 1);
    }

    /*
     * 내려가며 닫히는 구간. `forwards` 가 없으면 마지막 프레임에서 시트가 제자리로 튀어
     * 올랐다가 사라진다. 지속 시간은 word-stats.js 의 SHEET_CLOSE_MS 와 같아야 한다.
     */
    .word-stats-dialog[open].is-closing {
        animation: word-stats-sheet-out 220ms cubic-bezier(0.32, 0.72, 0, 1) forwards;
    }

    /* 손가락을 따라가는 동안에는 애니메이션·트랜지션을 모두 끈다. 남겨 두면 손보다 늦게 따라온다. */
    .word-stats-dialog[open].is-dragging {
        animation: none;
        transition: none;
    }

    .word-stats-dialog[open].is-opening::backdrop {
        animation: word-stats-backdrop-in 260ms ease;
    }

    .word-stats-dialog[open].is-closing::backdrop {
        animation: word-stats-backdrop-out 220ms ease forwards;
    }

    /*
     * 끌어내리는 손잡이.
     *
     * `::before` 가 아니라 실제 요소인 이유가 있다. 의사 요소를 누르면 이벤트의 target 이
     * **다이얼로그 자신**이 되는데, 이 다이얼로그는 바깥 클릭을 `target === dialog` 로
     * 판정한다(word-stats.js). 그립을 살짝 건드리기만 해도 배경을 누른 것으로 오인해
     * 시트가 닫혀 버린다.
     */
    .word-stats-sheet-grip {
        display: flex;
        flex: none;
        align-items: center;
        justify-content: center;
        height: 20px;
        padding-top: 8px;
        background-color: var(--color-bg-elevated);
        /* 여기서 시작한 세로 드래그를 브라우저 스크롤에 빼앗기지 않게 한다 */
        touch-action: none;
        cursor: grab;
    }

    .word-stats-sheet-grip::after {
        content: "";
        width: 36px;
        height: 4px;
        border-radius: 999px;
        background-color: var(--color-border);
    }

    .word-stats-header {
        /* 그립이 위를 덮으므로 헤더 위쪽 여백을 줄여 시트 머리가 두꺼워지지 않게 한다 */
        padding-top: 8px;
    }

    .word-stats-body {
        /* 목록 끝에서 더 당겼을 때 뒤 페이지가 따라 움직이지 않게 */
        overscroll-behavior: contain;
        /* 홈 인디케이터에 마지막 항목이 가리지 않도록 */
        padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px));
    }

    .word-stats-popover {
        bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    }
}

@keyframes word-stats-sheet-in {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
}

/* --sheet-drag 는 JS 가 넣는 '손을 뗀 지점'이다. 끌어내린 자리에서 이어서 내려간다. */
@keyframes word-stats-sheet-out {
    from { transform: translateY(var(--sheet-drag, 0px)); }
    to { transform: translateY(100%); }
}

@keyframes word-stats-backdrop-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes word-stats-backdrop-out {
    from { opacity: 1; }
    to { opacity: 0; }
}

/*
 * 모션 최소화를 켠 사용자에게는 시트 레이아웃만 남기고 미끄러짐을 없앤다.
 * word-stats.js 도 같은 조건에서 닫기 애니메이션을 건너뛰고 바로 close() 한다.
 */
@media (prefers-reduced-motion: reduce) {
    .word-stats-dialog[open].is-opening,
    .word-stats-dialog[open].is-closing,
    .word-stats-dialog[open].is-opening::backdrop,
    .word-stats-dialog[open].is-closing::backdrop {
        animation: none;
    }

    .word-stats-dialog {
        transition: none;
    }
}
