/* 관리 화면 공통 스타일 — 데스크톱 우선 */

:root {
    --c-bg: #ffffff;
    --c-fg: #1c1e21;
    --c-muted: #6b7280;
    --c-line: #e3e6ea;
    --c-accent: #2563eb;
    --c-danger: #dc2626;
    --c-ok: #059669;
    --radius: 6px;

    /*
     * 면과 배너 — **다크모드를 위한 의미 토큰.**
     *
     * 예전에는 `var(--c-surface)`(표 머리)·`var(--c-tint-ok)`(성공 배너) 같은 밝은 값이 규칙마다
     * 직접 박혀 있었다. 그래서 다크에서 밝은 배경 위에 밝은 글씨가 얹혀 읽히지
     * 않는 자리가 생겼다. 색을 이름으로 부르면 아래 다크 블록에서 한 번에 뒤집힌다.
     */
    --c-surface: #f8f9fb;      /* 표 머리·배지 등 한 단계 들어간 면 */
    --c-tint-ok: #ecfdf5;      /* 성공 배너 배경 */
    --c-tint-warn: #fff7ed;    /* 경고 배너 배경 */
    --c-tint-error: #fef2f2;   /* 오류 배너 배경 */
    --c-tint-info: #eff6ff;    /* 안내 배너 배경 */
    /*
     * 성공·오류 **글씨**. 배경으로도 쓰이는 `--c-ok`·`--c-danger` 와 일부러
     * 나눠 두었다 — 그쪽은 흰 글씨를 얹는 버튼·배지라 진하게 하면 안 된다.
     *
     * 연한 배너 바탕에서 읽히도록 한 단계 진한 값을 쓴다. 예전에는 버튼과 같은
     * `#059669`·`#dc2626` 이었는데 대비가 3.58·4.41 로 기준(4.5)에 못 미쳤다 —
     * 화면에서 **가장 안 읽히는 글씨가 알림 띠**인 상태였다. 햇빛 아래 노트북·
     * 색약에서 특히 걸린다.
     */
    --c-on-ok: #047857;        /* 배너 5.21 : 1 · 흰 바탕 5.48 : 1 */
    --c-on-error: #b91c1c;     /* 배너 5.91 : 1 · 흰 바탕 6.47 : 1 */
    --c-on-warn: #9a3412;      /* 경고 배너 글씨 */
    --c-on-info: #1d4ed8;      /* 안내 배너 글씨 */
    --c-warn: #d97706;         /* 주의 표시(중복 소속·간격 위반) 테두리·글씨 */

    /*
     * 브라우저에게 두 테마를 다 지원한다고 알린다. 이 한 줄이 없으면
     * `<select>` · `<input type="date">` · 스크롤바가 **밝은 기본 모습으로
     * 남아** 어두운 화면에 흰 덩어리로 뜬다. CSS 로는 못 고치는 부분이다.
     */
    color-scheme: light dark;
}

* { box-sizing: border-box; }


body {
    margin: 0;
    background: var(--c-bg);
    color: var(--c-fg);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans KR",
                 "Noto Sans JP", Roboto, "Helvetica Neue", sans-serif;
    font-size: 14px;
    line-height: 1.6;
}

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

/* 헤더 */
.app-header {
    display: flex;
    align-items: center;
    gap: 24px;
    padding: 0 20px;
    height: 52px;
    border-bottom: 1px solid var(--c-line);
    position: relative;
}
.app-brand { font-weight: 700; font-size: 16px; color: var(--c-fg); }

/*
 * 서랍 껍데기 — 넓은 화면에서는 **없는 것처럼** 둔다.
 *
 * `display: contents` 는 상자를 만들지 않고 자식만 남긴다. 그래서 .app-nav 와
 * .app-utils 가 헤더의 직계 flex 칸으로 그대로 서고, 아래 `margin-left: auto`
 * 도 예전처럼 먹는다. 좁은 화면에서만 진짜 상자가 되어 오른쪽에서 열린다.
 */
.app-drawer { display: contents; }

.app-nav { display: flex; gap: 16px; }
.app-utils { margin-left: auto; display: flex; align-items: center; gap: 14px; }

/* 서랍 뒤를 덮는 막 — 좁은 화면에서만 쓴다 */
.app-scrim { display: none; }
.app-user { color: var(--c-muted); }
/* 개발 문서 링크 — 관리자에게만 보인다. 새 창으로 열린다. */
.app-docs-link { font-size: 13px; color: var(--c-muted); }
.app-docs-link:hover { color: var(--c-accent); }

/* 좁은 화면에서만 나타나는 메뉴 토글 — 데스크톱 기준으로 기본은 숨김 */
.app-nav-toggle {
    display: none;
    width: 32px; height: 32px; padding: 0;
    border: 0; background: none; cursor: pointer;
    flex-direction: column; align-items: center; justify-content: center; gap: 5px;
}
.app-nav-toggle span { display: block; width: 20px; height: 2px; background: var(--c-fg); }

/* 언어 전환 */
.lang-select {
    padding: 5px 8px; border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg); font-size: 13px;
}
/*
 * 테마 전환 버튼 — 아이콘 + 고른 모드 이름.
 *
 * 언어 선택(.lang-select) 옆에 서므로 높이·테두리를 맞춘다. 글자 폭이 언어마다
 * 달라(‘어둡게’ vs ‘跟随系统’) 고정 폭을 주지 않는다.
 */
.theme-toggle {
    padding: 5px 10px;
    border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg);
    font-size: 13px; line-height: 1.4; cursor: pointer;
    white-space: nowrap;
}
.theme-toggle:hover { border-color: var(--c-accent); }

.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;
}

/* 본문 */
.app-main { max-width: 1600px; margin: 0 auto; padding: 24px 20px 60px; }
.lead { color: var(--c-muted); }

/* 메인 화면 진입 카드 (대진표 작성 / 대회 운영 / 공개 대회 보기) */
.cta-cards { list-style: none; padding: 0; margin: 20px 0 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.cta-card {
    display: block; padding: 20px; border: 1px solid var(--c-line); border-radius: var(--radius);
    color: inherit; text-decoration: none; transition: border-color 0.15s ease;
}
.cta-card:hover { border-color: var(--c-accent); text-decoration: none; }
.cta-card h2 { margin: 0 0 6px; font-size: 16px; }
.cta-card p { margin: 0; color: var(--c-muted); font-size: 13px; }

/* 플래시 메시지 */
.flash { padding: 10px 14px; border-radius: var(--radius); margin: 0 0 16px; }
.flash-ok { background: var(--c-tint-ok); color: var(--c-on-ok); }
.flash-error { background: var(--c-tint-error); color: var(--c-on-error); }

/* 표 — 넓은 표는 자체 스크롤 컨테이너 안에 둔다 */
.table-scroll { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; }
th, td { padding: 8px 10px; border-bottom: 1px solid var(--c-line); text-align: left; }
th { background: var(--c-surface); font-weight: 600; white-space: nowrap; }

.app-footer {
    border-top: 1px solid var(--c-line);
    padding: 16px 20px;
    color: var(--c-muted);
}

/*
 * 좁은 화면 — 헤더 메뉴를 토글 뒤로 숨긴다.
 *
 * `.app-nav`가 항목 2개일 때는 그냥 flex 로 버텨도 됐지만, 화면 폭이 좁으면서
 * 오른쪽의 언어 선택·로그인 상태까지 한 줄에 다 있으면 브랜드 글자가 잘리거나
 * 줄바꿈되어 52px 헤더가 깨진다. 항목이 늘어날 것도 고려해 토글로 미리 뺀다.
 */
/* ------------------------------------------------------------------ */
/* 좁은 화면 — 메뉴는 오른쪽에서 열리는 서랍이 된다                      */
/* ------------------------------------------------------------------ */

@media (max-width: 720px) {
    /* 헤더에는 이름과 ☰ 만 남는다. 나머지는 전부 서랍 안으로 들어간다. */
    .app-nav-toggle {
        display: inline-flex; margin-left: auto;
        position: relative; z-index: 60;   /* 서랍 위에 떠 있어야 눌러서 닫는다 */
    }

    /*
     * ⚠️ 닫혔을 때 `visibility: hidden` 이 **꼭 필요하다.** 화면 밖으로 밀어
     *    두기만 하면 링크가 여전히 탭 순서에 남아, 키보드로 넘기다 보이지 않는
     *    메뉴에 초점이 빠진다. 전환이 끝난 뒤 숨기려고 visibility 만 지연시킨다.
     */
    .app-drawer {
        display: flex; flex-direction: column; gap: 20px;
        position: fixed; top: 0; right: 0; bottom: 0;
        width: min(280px, 82vw);
        padding: 64px 20px 24px;
        background: var(--c-bg); border-left: 1px solid var(--c-line);
        box-shadow: -8px 0 24px rgb(0 0 0 / 12%);
        overflow-y: auto; z-index: 50;
        visibility: hidden; transform: translateX(100%);
        transition: transform 0.2s ease, visibility 0s linear 0.2s;
    }
    .app-drawer.is-open {
        visibility: visible; transform: translateX(0);
        transition: transform 0.2s ease;
    }
    /* 열 때 초점을 받는 자리다. 서랍 전체에 테두리를 두를 이유는 없다 */
    .app-drawer:focus { outline: none; }

    .app-nav { flex-direction: column; gap: 0; }
    .app-nav a { padding: 12px 0; border-bottom: 1px solid var(--c-line); }

    /*
     * 도구도 세로로 쌓는다. `margin-left: auto` 는 가로로 밀어내는 값이라
     * 세로 서랍에서는 뜻이 없다 — 되돌리지 않으면 위쪽에 빈 틈이 생긴다.
     */
    .app-utils {
        flex-direction: column; align-items: stretch; gap: 12px;
        margin-left: 0;
    }
    .app-utils > a { padding: 4px 0; }
    .theme-toggle, .lang-select { width: 100%; text-align: left; }

    .app-scrim {
        display: block; position: fixed; inset: 0;
        background: rgb(0 0 0 / 40%); z-index: 45;
    }
    .app-scrim[hidden] { display: none; }

    /* 서랍이 열린 동안 뒤 화면이 따라 스크롤되지 않게 */
    body.is-nav-open { overflow: hidden; }

    /* ☰ → ✕. 열렸다는 것을 버튼 스스로 말한다 */
    .app-nav-toggle span { transition: transform 0.2s ease, opacity 0.2s ease; }
    .app-nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
    .app-nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
    .app-nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

    .cta-cards { grid-template-columns: 1fr; }
}

/* 움직임을 줄여 달라고 한 사람에게는 미끄러뜨리지 않는다 */
@media (prefers-reduced-motion: reduce) {
    .app-drawer, .app-nav-toggle span { transition: none; }
}

/* ------------------------------------------------------------------ */
/* 어두운 팔레트 — 두 가지 방법으로 켜진다                              */
/* ------------------------------------------------------------------ */

/*
 * 1) 시스템이 어두울 때. 단 사용자가 **밝게 고정**했으면 빠진다.
 * 2) 사용자가 **어둡게 고정**했을 때. 시스템 설정과 무관하다.
 *
 * ⚠️ 두 블록의 내용은 **글자 그대로 같아야 한다.** 미디어 쿼리 안과 밖은 한
 *    규칙으로 합칠 수 없어 어쩔 수 없이 두 벌인데, 한쪽만 고치면 "시스템 다크"
 *    와 "수동 다크" 의 색이 갈린다. `DarkModeCssTest` 가 둘이 같은지 지킨다.
 *
 * 개별 규칙은 덮어쓰지 않는다 — 토큰만 뒤집으면 `th`·`.flash-*` 가 따라온다.
 * 예전에는 규칙마다 색을 다시 적었는데, 그러면 화면을 만들 때마다 그 목록에 한
 * 줄씩 더해야 하고 빠뜨리면 그 화면만 밝게 남았다.
 */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --c-bg: #16181c;
        --c-fg: #e7e9ea;
        --c-muted: #8b949e;
        --c-line: #2a2e35;
        /* 위 :root 의 의미 토큰을 어두운 값으로 뒤집는다. */
        --c-surface: #1c1f25;
        --c-tint-ok: #05291f;
        --c-tint-warn: #2b1a06;
        --c-tint-error: #2c1416;
        --c-tint-info: #1e2a4a;
        --c-on-ok: #6ee7b7;
        --c-on-error: #fca5a5;
        --c-on-warn: #fdba74;
        --c-on-info: #93c5fd;
        --c-warn: #fbbf24;
    }
}

:root[data-theme="dark"] {
    /* 폼 컨트롤·스크롤바까지 함께 어두워지도록 팔레트와 한 규칙에 둔다. */
    color-scheme: dark;

    --c-bg: #16181c;
    --c-fg: #e7e9ea;
    --c-muted: #8b949e;
    --c-line: #2a2e35;
    /* 위 :root 의 의미 토큰을 어두운 값으로 뒤집는다. */
    --c-surface: #1c1f25;
    --c-tint-ok: #05291f;
    --c-tint-warn: #2b1a06;
    --c-tint-error: #2c1416;
    --c-tint-info: #1e2a4a;
    --c-on-ok: #6ee7b7;
    --c-on-error: #fca5a5;
    --c-on-warn: #fdba74;
    --c-on-info: #93c5fd;
    --c-warn: #fbbf24;
}

/*
 * 밝게 고정 — 팔레트는 `:root` 기본값 그대로라 `color-scheme` 만 못 박으면 된다.
 * 이게 없으면 시스템이 어두울 때 폼 컨트롤만 어둡게 남는다.
 */
:root[data-theme="light"] { color-scheme: light; }

/* 로그인 · 회원가입 */
.auth-box { max-width: 380px; margin: 40px auto; }
.auth-box h1 { font-size: 20px; margin: 0 0 20px; }
.auth-box label { display: block; margin-bottom: 14px; }
.auth-box label > span { display: block; margin-bottom: 4px; font-size: 13px; color: var(--c-muted); }
.auth-box input {
    width: 100%;
    padding: 9px 11px;
    border: 1px solid var(--c-line);
    border-radius: var(--radius);
    background: var(--c-bg);
    color: var(--c-fg);
    font-size: 14px;
}
.auth-box input:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }
.field-error { display: block; margin-top: 4px; color: var(--c-on-error); font-size: 12px; font-style: normal; }

/*
 * 동의 — 약관·방침(필수)과 마케팅(선택).
 *
 * ⚠️ 체크박스는 `.auth-box input` 의 `width:100%` 를 물려받으면 안 된다. 그러면
 *    한 줄을 통째로 차지해 글씨가 밀린다. 여기서 되돌린다.
 */
.agree {
    margin: 4px 0 18px; padding: 12px 14px;
    border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-surface);
}
.agree legend { padding: 0 6px; font-size: 13px; color: var(--c-muted); }

/*
 * ⚠️ **선택자를 `.auth-box` 로 감싼다.**
 *
 * `.auth-box label` 은 `display:block`, `.auth-box label > span` 도 `block` 이다.
 * 그냥 `.agree-row` 로 쓰면 선택자가 하나뿐이라 **저쪽이 이겨서** 체크박스와
 * 글자가 줄바꿈된다. 실제로 그렇게 나왔다.
 */
.auth-box .agree-row {
    display: flex; align-items: center; gap: 8px;
    margin: 0 0 8px; font-size: 13px;
}
.auth-box .agree-row:last-child { margin-bottom: 0; }
.auth-box .agree-row input[type="checkbox"] {
    /* 위 span 과 같은 이유 — `.auth-box input` 의 width:100% 를 되돌린다 */
    width: auto; flex: 0 0 auto; margin: 0;
}
/* 글자가 한 줄에 오도록 block 을 되돌린다 */
.auth-box .agree-row > span { display: inline; flex: 1 1 auto; margin-bottom: 0; }
.agree-link { flex: 0 0 auto; font-size: 12px; }

/* 선택 항목은 살짝 죽여 필수와 구분한다 */
.auth-box .agree-row.is-optional > span { color: var(--c-muted); }

/* 선택 표시 — 라벨 옆 작은 글씨 */
.opt { font-style: normal; font-size: 11px; color: var(--c-muted); }

/* 필수 표시 — 라벨 옆의 작은 배지 */
.req {
    display: inline-block; margin-left: 4px; padding: 1px 5px;
    border-radius: 3px; background: var(--c-danger); color: #fff;
    font-size: 10px; font-style: normal; font-weight: 600; vertical-align: 1px;
}
.btn-primary {
    width: 100%;
    padding: 10px;
    border: 0;
    border-radius: var(--radius);
    background: var(--c-accent);
    color: #fff;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}
.btn-primary:hover { filter: brightness(1.08); }
.auth-alt { margin-top: 16px; text-align: center; font-size: 13px; }

/* 목록·폼 공통 */
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 18px; }
.page-head h1 { margin: 0; font-size: 20px; }
.page-sub { margin: 4px 0 0; color: var(--c-muted); font-size: 13px; }
.btn-inline { width: auto; display: inline-block; padding: 8px 16px; text-decoration: none; }

/*
 * 대회 안 이동 메뉴 — layout/partials/contest_nav.php
 *
 * ⚠️ **클래스 이름에 `.tab` 을 쓰지 않는다.** 아래쪽 `.tabs`/`.tab` 은 요강
 *    화면의 화면 내 탭 위젯이고, 그 화면 JS 가 `querySelectorAll('.tab')` 으로
 *    전부 잡는다. 이름이 겹치면 이 링크들이 위젯에 말려들어 요강/게임 탭이
 *    깨진다.
 *
 * 모양은 popup.css 의 `.popup-tabs` 를 따른다. 두 내비가 서로 다르게 생기면
 * 관리 화면과 팝업이 다른 서비스처럼 보인다.
 */
.contest-nav {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 12px;
    border-bottom: 1px solid var(--c-line);
    margin-bottom: 18px;
}
.contest-nav ul {
    display: flex;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
    /* 좁은 화면에서 항목이 줄바꿈되지 않고 옆으로 밀린다 */
    overflow-x: auto;
    scrollbar-width: none;
}
.contest-nav ul::-webkit-scrollbar { display: none; }
.contest-nav a {
    display: block;
    padding: 9px 16px;
    color: var(--c-muted);
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}
.contest-nav a:hover { color: var(--c-fg); }
.contest-nav .is-active a { color: var(--c-accent); border-bottom-color: var(--c-accent); }

/* 운영 — 팝업으로 열린다. 페이지 이동인 탭들과 눈으로 구분되어야 한다. */
.contest-nav-open {
    flex-shrink: 0;
    align-self: center;
    padding: 6px 14px !important;
    margin-bottom: 6px !important;
    border: 1px solid var(--c-line) !important;
    border-radius: var(--radius);
    color: var(--c-fg) !important;
    font-size: 13px !important;
}
/* 참가자 링크 — 요강의 공개 설정 안 */
.share-link { margin-top: 16px; }
.share-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 6px; }
.share-row input {
    flex: 1 1 260px;
    min-width: 0;
    padding: 8px 11px;
    border: 1px solid var(--c-line);
    border-radius: var(--radius);
    background: var(--c-surface);
    color: var(--c-fg);
    font-size: 13px;
}
.share-row .btn-inline { flex-shrink: 0; }

.contest-nav-open::after {
    /* 새 창으로 나간다는 표시 */
    content: "↗";
    margin-left: 5px;
    font-size: 11px;
    color: var(--c-muted);
}
/*
 * .btn-cancel 은 **되돌아가는 링크** 전용이다 — 취소·이전·목록으로.
 * 옅은 테두리에 채움이 없어 "누를 것이 아니다" 로 읽히는 것이 의도다.
 *
 * ⚠️ 실행 버튼(자동 배정·조 다시 섞기 등)에 쓰지 말 것. 채워진 .btn-primary
 *    옆에 놓이면 **꺼진 버튼처럼 보인다.** 실제로 그런 제보를 받았다.
 *    실행 버튼은 아래 .btn-secondary 를 쓴다.
 */
.btn-cancel {
    display: inline-block; padding: 9px 16px; border: 1px solid var(--c-line);
    border-radius: var(--radius); color: var(--c-fg); text-decoration: none; font-size: 14px;
}

/*
 * 보조 실행 버튼 — 주 동작(.btn-primary)은 아니지만 **누르면 무언가 일어난다.**
 * 강조색 테두리·글자와 손가락 커서로 "동작"임을 드러내고, 채움이 없어
 * 주 동작과는 구분된다.
 */
.btn-secondary {
    display: inline-block; padding: 9px 16px;
    border: 1px solid var(--c-accent); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-accent);
    text-decoration: none; font-size: 14px; font-weight: 600; cursor: pointer;
}
.btn-secondary:hover { background: var(--c-accent); color: #fff; }
.btn-secondary:disabled { border-color: var(--c-line); color: var(--c-muted); background: var(--c-bg); cursor: default; }
.btn-secondary:disabled:hover { background: var(--c-bg); color: var(--c-muted); }
/*
 * 링크처럼 보이는 버튼.
 *
 * ⚠️ **이 규칙이 없으면 `<button class="btn-link">` 만 회색 네이티브 버튼으로
 *    튄다.** 같은 클래스를 `<a>` 에도 쓰는데 `<a>` 는 기본 링크 색을 받아
 *    그럭저럭 보이므로, 규칙이 없다는 사실이 오래 안 드러났다. 실제로 일자·장소
 *    화면에서 「저장」만 버튼, 옆의 「종목선택」·「삭제」는 텍스트로 나와
 *    한 칸 안에서 모양이 갈렸다.
 *
 * 그래서 `<a>` 와 `<button>` 이 **같아 보이게** 맞춘다.
 */
.btn-link {
    border: 0; background: none; padding: 0;
    color: var(--c-accent); font-size: 13px; font-family: inherit;
    cursor: pointer; text-decoration: none;
}
.btn-link:hover { text-decoration: underline; }

.btn-link-danger { border: 0; background: none; color: var(--c-on-error); cursor: pointer; font-size: 13px; padding: 0; font-family: inherit; }
.btn-link-danger:hover { text-decoration: underline; }
/* super 전용 관리자 액션 — 일반 링크와 구분되도록 강조한다 */
.link-super { color: var(--c-on-error); font-weight: 700; }
/* 팀 칸 아래 작게 붙는 보조 링크 (경기별 선수 변경 등) */
.cell-link { display: block; font-size: 12px; margin-top: 2px; }
/*
 * 줄마다 붙는 조작 — **텍스트로 통일한다.**
 *
 * 한 칸에 다섯 개(저장·종목선택·대진확인·타임테이블·삭제)까지 들어가므로
 * 채워진 버튼으로 만들면 행이 두꺼워져 표를 읽을 수 없다. 참가자 목록의
 * 수정·삭제도 이미 텍스트다.
 *
 * 크기를 여기서 못박아 `<a>` 와 `<button>` 이 나란히 서도 어긋나지 않게 한다.
 */
.row-actions { display: flex; gap: 10px; align-items: center; white-space: nowrap; }
.row-actions form { display: inline; }
.row-actions a, .row-actions button { font-size: 13px; line-height: 1.4; }
.muted { color: var(--c-muted); font-size: 13px; }
.empty { color: var(--c-muted); text-align: center; padding: 40px 0; }
.hint { color: var(--c-muted); font-size: 13px; margin: 4px 0; }
.hint.warn { color: var(--c-on-error); }

/*
 * 코트 범위 — `[3] 코트부터 [6] 코트까지`
 *
 * 입력칸 둘과 사이의 말이 한 줄에 붙어야 읽힌다. 표 안(수정 줄)에서도 같은
 * 클래스를 쓰므로 <label> 과 <td> 양쪽에 걸린다.
 */
/*
 * 표 안에서 바로 고치는 줄 — 일자·장소 화면.
 *
 * ⚠️ **표 안의 input 은 아무 스타일도 물려받지 못한다.** 이 저장소의 입력
 *    스타일은 전부 `.form-box input` · `.upload-box input` 처럼 **컨테이너에
 *    매여 있어서**, 표에 클래스를 안 붙이면 브라우저 기본 모양으로 나온다.
 *    위쪽 「일자·장소 추가」 폼과 같은 화면인데 칸 모양이 달라 보였다.
 *
 *    `.set-table` 이 있길래 그것이 이 표인 줄 알기 쉬운데, 그쪽은 운영 팝업의
 *    **세트 점수 표**다. 이름이 비슷할 뿐 무관하다.
 */
.edit-table input {
    padding: 9px 11px; border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg); font-size: 14px; font-family: inherit;
    max-width: 100%;
}
.edit-table input:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }
.edit-table input[type="text"] { width: 100%; min-width: 140px; }
.edit-table td { vertical-align: middle; }

.court-range { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.court-range > span { flex: 0 0 100%; }          /* 라벨은 한 줄 위로 */
.court-range input[type="number"] { width: 4.5em; }
.court-range em { font-style: normal; color: var(--c-muted); font-size: 13px; }

/*
 * 선택지별 설명 — 고른 것 하나만 보여준다.
 *
 * 넷을 한꺼번에 늘어놓으면 읽히지 않아, 서버가 지금 값에 `is-on` 을 붙이고
 * 바뀔 때마다 스크립트가 옮긴다. **JS 가 없어도 한 줄은 보인다.**
 */
.hint-cases { list-style: none; margin: 4px 0 0; padding: 0; }
.hint-cases > li { display: none; }
.hint-cases > li.is-on {
    display: block;
    color: var(--c-muted);
    font-size: 13px;
    line-height: 1.5;
    padding: 8px 10px;
    border-left: 3px solid var(--c-line);
    /* 소프트 배경 토큰이 없다. 반투명 회색이라 라이트·다크 어디서도 성립한다. */
    background: rgba(127, 127, 127, .08);
    border-radius: 0 var(--radius) var(--radius) 0;
}

.form-box { max-width: 520px; margin: 0 auto; }
.form-box-wide { max-width: 900px; }
.form-box h1 { font-size: 20px; margin: 0 0 4px; }
.form-box label { display: block; margin-bottom: 14px; }
.form-box label > span { display: block; margin-bottom: 4px; font-size: 13px; color: var(--c-muted); }
.form-box input, .form-box select {
    width: 100%; padding: 9px 11px; border: 1px solid var(--c-line);
    border-radius: var(--radius); background: var(--c-bg); color: var(--c-fg); font-size: 14px;
}
.form-box input:focus, .form-box select:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }
.field-row { display: flex; gap: 12px; flex-wrap: wrap; }
.field-row > label { flex: 1 1 150px; }
.field-row > label > span { display: block; margin-bottom: 4px; font-size: 13px; color: var(--c-muted); }
.field-row input, .field-row select {
    width: 100%; padding: 9px 11px; border: 1px solid var(--c-line);
    border-radius: var(--radius); background: var(--c-bg); color: var(--c-fg); font-size: 14px;
}
.field-row input:focus, .field-row select:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }
.form-actions { display: flex; gap: 10px; align-items: center; margin-top: 20px; }
.form-actions .btn-primary { width: auto; padding: 10px 22px; }

.player-set { border: 1px solid var(--c-line); border-radius: var(--radius); padding: 12px 14px; margin-bottom: 16px; }
/*
 * 요강 화면은 fieldset 이 여덟 개다. legend 가 본문과 같은 무게면 어디서
 * 한 덩어리가 끝나는지 안 보인다.
 */
.player-set legend { padding: 0 6px; font-size: 13px; font-weight: 600; color: var(--c-fg); }

/* 엑셀 업로드 */
.upload-box { border: 1px solid var(--c-line); border-radius: var(--radius); padding: 14px 16px; margin-bottom: 20px; }
.upload-box h2 { margin: 0 0 6px; font-size: 15px; }
.upload-box form { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; margin-top: 10px; }
.upload-box label { display: block; margin: 0; }
.upload-box label > span { display: block; margin-bottom: 4px; font-size: 13px; color: var(--c-muted); }
.upload-box input {
    padding: 9px 11px; border: 1px solid var(--c-line);
    border-radius: var(--radius); background: var(--c-bg); color: var(--c-fg); font-size: 14px;
}
.upload-box input:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }

/*
 * 업로드 줄의 칸과 버튼은 **높이가 같아야** 한다.
 *
 * 그냥 두면 셋이 다 다르게 나온다. `<button>` 은 테두리가 없고 행간이
 * `normal` 인데, `<a>` 는 1px 테두리에 본문 행간(1.6)을 물려받아 5px 쯤 더
 * 크다. **padding 을 같게 줘도 안 맞는 이유가 이것이다** — 그래서 높이를
 * 못박고 글자를 가운데 둔다.
 */
.upload-box form > .btn-primary,
.upload-box form > .btn-secondary {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 38px; padding: 0 16px;
}
/* 파일 칸은 안쪽에 브라우저가 그리는 버튼이 있어 높이를 강제하면 잘린다.
   폼이 `align-items: flex-end` 라 밑변은 이미 맞는다. */
.upload-box input[type="text"] { width: 180px; }
.upload-box input[type="date"] { width: 160px; }
.upload-box input[type="number"] { width: 90px; }

/* 시트 오류 목록 */
.sheet-errors { border: 1px solid var(--c-danger); border-radius: var(--radius); padding: 12px 16px; margin-bottom: 18px; }
.sheet-errors-head { margin: 0 0 8px; color: var(--c-on-error); font-weight: 600; }
.sheet-errors ul { margin: 0; padding-left: 18px; font-size: 13px; }
.sheet-errors li { margin-bottom: 3px; }
.sheet-errors strong { color: var(--c-on-error); margin-right: 6px; }

/* 대진표 작성 단계 바 — old 의 _nav.php 에 해당 */
.mb-steps { margin: 0 0 20px; border-bottom: 1px solid var(--c-line); }

.mb-steps ol {
    display: flex;
    gap: 2px;
    margin: 0;
    padding: 0 0 10px;
    list-style: none;
    overflow-x: auto;
    scrollbar-width: none;
}
.mb-steps ol::-webkit-scrollbar { display: none; }

.mb-steps li { flex: 0 0 auto; }

.mb-steps a,
.mb-steps li > span {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 7px 13px;
    border: 1px solid var(--c-line);
    border-radius: var(--radius);
    font-size: 13px;
    white-space: nowrap;
    text-decoration: none;
    color: var(--c-fg);
}

.mb-step-no {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--c-line);
    color: var(--c-muted);
    font-size: 11px;
    font-weight: 700;
}

/* 완료 — 눌러서 되돌아갈 수 있다 */
.mb-steps .is-done a { border-color: var(--c-ok); }
.mb-steps .is-done .mb-step-no { background: var(--c-ok); color: #fff; }

/* 현재 */
.mb-steps .is-current > span {
    border-color: var(--c-accent);
    background: var(--c-accent);
    color: #fff;
    font-weight: 600;
}
.mb-steps .is-current .mb-step-no { background: rgba(255, 255, 255, 0.25); color: #fff; }

/* 아직 안 한 단계지만 열려 있음 */
.mb-steps .is-open a { border-style: dashed; }

/* 잠김 — a 가 아니라 span 이라 클릭되지 않는다 */
.mb-steps .is-locked > span {
    opacity: 0.4;
    cursor: not-allowed;
}

.mb-steps a:hover { border-color: var(--c-accent); text-decoration: none; }

@media (max-width: 720px) {
    .mb-steps a, .mb-steps li > span { padding: 6px 10px; font-size: 12px; }
    .mb-step-label { display: none; }
    .mb-steps .is-current .mb-step-label { display: inline; }
}

/* ------------------------------------------------------------------ */
/* 종목 선택·병합 (3단계)                                              */
/* ------------------------------------------------------------------ */

.join-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px; }
.join-cols h2 { font-size: 14px; margin: 0 0 8px; }

.event-pool, .event-merged { list-style: none; margin: 0 0 10px; padding: 0; }

/*
 * ── 긴 목록에서도 끌 수 있게 ──
 *
 * 종목이 100개에 가까운 대회가 있다. 그냥 두면 목록이 4,000px 를 넘어 페이지
 * 자체가 하나의 긴 스크롤이 되고, 아래쪽 종목을 위쪽 그룹으로 끌려면 **드롭
 * 대상이 화면 밖**이다. 양쪽에 높이 상한을 주고 각자 스크롤하게 한다.
 *
 * ⚠️ 오른쪽 칸의 `align-self: start` 가 없으면 **sticky 가 먹지 않는다.**
 *    그리드 칸이 세로로 늘어나 붙을 여백이 사라진다. 빠뜨리기 쉬운 한 줄이다.
 */
.event-pool { max-height: 60vh; overflow-y: auto; }
.join-cols > section:last-child { position: sticky; top: 16px; align-self: start; }
.event-merged { max-height: 60vh; overflow-y: auto; }

/* 고르기 줄 — 「선택한 종목 합치기」 */
.ev-tools { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.ev-picked { font-size: 12px; color: var(--c-accent); font-weight: 600; }
.ev-clear {
    border: 0; background: none; color: var(--c-muted);
    font-size: 12px; padding: 0; cursor: pointer;
}
.ev-clear:hover { color: var(--c-accent); }

/* 연령 묶음 — 종목이 많으면 접힌 채로 연다 */
.ev-age { margin-bottom: 6px; }
.ev-age > summary {
    padding: 6px 8px; border-radius: var(--radius); background: var(--c-surface);
    font-size: 13px; font-weight: 600; cursor: pointer;
}
.ev-age > summary::marker { color: var(--c-muted); }
.ev-age[open] > summary { margin-bottom: 5px; }
.ev-age-left { margin-left: 6px; color: var(--c-muted); font-style: normal; font-weight: 400; font-size: 12px; }
.ev-age > ul { list-style: none; margin: 0; padding: 0; }

/* 체크한 종목 */
.ev-pick { flex-shrink: 0; margin: 0; cursor: pointer; }
.event-pool > .ev-age li.is-picked { border-color: var(--c-accent); background: var(--c-tint-info); }

/*
 * 왼쪽 원본 종목 — 끌어다 놓을 수 있다.
 *
 * ⚠️ 선택자가 둘인 이유: 병합 화면은 항목을 연령 묶음(`.ev-age > ul`) 안에
 *    넣어 **직계 자식이 아니고**, 대진 생성 화면(bracket/edit.php)은 같은 틀을
 *    평평한 `ul > li` 로 쓴다. 한쪽만 적으면 다른 화면의 테두리가 사라진다.
 */
.event-pool > li,
.event-pool .ev-item {
    position: relative;
    display: flex; align-items: center; gap: 8px;
    padding: 7px 10px; border: 1px solid var(--c-line); border-radius: var(--radius);
    margin-bottom: 5px; font-size: 13px;
    cursor: grab;
}
.event-pool .ev-item.is-drag { opacity: 0.4; }
.event-pool .ev-count { margin-left: auto; color: var(--c-muted); font-style: normal; font-size: 12px; }

/* 대진 생성 화면의 체크박스 목록도 같은 틀을 쓴다 */
.event-pool label { display: flex; align-items: center; gap: 8px; width: 100%; margin: 0; cursor: pointer; }
.event-pool label + em, .event-pool em:not(.ev-count) {
    margin-left: auto; color: var(--c-muted); font-style: normal; font-size: 12px;
}

/* ⓘ 참가팀 보기 */
.ev-info {
    border: 0; background: none; color: var(--c-muted);
    font-size: 15px; line-height: 1; padding: 2px 4px; cursor: pointer;
}
.ev-info:hover { color: var(--c-accent); }

.ev-teams {
    list-style: none; margin: 6px 0 0; padding: 8px 10px; width: 100%;
    border-top: 1px dashed var(--c-line); font-size: 12px;
}
.ev-teams li { padding: 2px 0; }
.ev-teams b { display: inline-block; min-width: 2em; color: var(--c-muted); font-weight: 500; }
.event-pool .ev-item:has(.ev-teams) { flex-wrap: wrap; }

/* 오른쪽 병합 그룹 */
.event-merged-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.event-merged-head h2 { margin: 0; }
.event-merged-head .btn-cancel { padding: 4px 10px; font-size: 12px; }

.event-merged {
    min-height: 120px; padding: 8px;
    border: 1px dashed var(--c-line); border-radius: var(--radius);
}

.mg-group {
    border: 1px solid var(--c-line); border-radius: var(--radius);
    padding: 10px; margin-bottom: 8px; background: var(--c-bg);
}
.mg-group.is-over { border-color: var(--c-accent); background: rgba(37, 99, 235, 0.05); }

/* 종별이 갈려 EE(기타)가 된 그룹 */
.mg-group.is-mixed .mg-sex { color: var(--c-on-error); }
/* 3팀 미만 — 대진이 성립하지 않는다 */
.mg-group.is-thin { border-color: var(--c-danger); }
.mg-group.is-thin .mg-total { color: var(--c-on-error); font-weight: 600; }

.mg-codes { display: flex; align-items: flex-end; gap: 6px; margin-bottom: 8px; }
.mg-codes label { display: flex; flex-direction: column; gap: 2px; margin: 0; flex: 1; }
.mg-codes span { font-size: 11px; color: var(--c-muted); }
.mg-codes input {
    width: 100%; padding: 4px 6px; font-size: 13px;
    border: 1px solid var(--c-line); border-radius: var(--radius);
}
/* 자동으로 정해지는 값이라 고칠 수 없다 */
.mg-codes .mg-sex { background: var(--c-line); cursor: default; }

.mg-reset {
    border: 1px solid var(--c-line); border-radius: var(--radius); background: none;
    padding: 4px 7px; font-size: 13px; line-height: 1; cursor: pointer; color: var(--c-muted);
}
.mg-reset:hover { color: var(--c-accent); border-color: var(--c-accent); }

.mg-items { list-style: none; margin: 0; padding: 0; }
.mg-items li {
    display: flex; align-items: center; gap: 8px;
    padding: 4px 6px; font-size: 12px; border-radius: var(--radius);
}
.mg-items li:nth-child(odd) { background: rgba(0, 0, 0, 0.02); }
.mg-items em { margin-left: auto; color: var(--c-muted); font-style: normal; }
.mg-items .mg-empty { justify-content: center; color: var(--c-muted); padding: 12px; background: none; }

.mg-out {
    border: 0; background: none; color: var(--c-muted);
    font-size: 14px; line-height: 1; padding: 0 3px; cursor: pointer;
}
.mg-out:hover { color: var(--c-on-error); }

.mg-foot {
    display: flex; align-items: center; justify-content: space-between;
    margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--c-line);
    font-size: 12px; color: var(--c-muted);
}
/* 「선택 항목 넣기」와 「해제」 — 붙여 놓으면 한 단어처럼 읽힌다 */
.mg-acts { display: flex; align-items: center; gap: 12px; }
.mg-add {
    border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg);
    font-size: 12px; padding: 3px 8px; cursor: pointer;
}
.mg-add:hover { border-color: var(--c-accent); color: var(--c-accent); }

@media (max-width: 720px) {
    .join-cols { grid-template-columns: 1fr; }
    .mg-codes { flex-wrap: wrap; }

    /*
     * 좌우가 위아래로 쌓이므로 붙일 곳이 없다 — sticky 를 끈다. 대신 각 목록을
     * 더 낮춰 두 영역이 한 화면에 함께 보이게 한다. 여기서는 애초에 네이티브
     * 드래그가 안 되므로 「선택한 종목 합치기」가 유일한 길이다.
     */
    .join-cols > section:last-child { position: static; }
    .event-pool, .event-merged { max-height: 320px; }
}

/* 1팀뿐이라 고를 수 없는 종목 */
.event-pool > li.is-disabled { opacity: 0.55; cursor: not-allowed; }
.event-pool > li.is-disabled label { cursor: not-allowed; }
.event-pool em.warn { color: var(--c-on-error); font-style: normal; font-size: 12px; }

/* 대진 조건 — 종목별 예상 결과 */
.plan-list { list-style: none; margin: 0 0 16px; padding: 0; }
.plan-list li {
    display: flex; align-items: baseline; gap: 10px;
    padding: 5px 10px; font-size: 12px;
    border-left: 2px solid var(--c-accent); margin-bottom: 3px;
    background: rgba(37, 99, 235, 0.04);
}
.plan-list b { font-weight: 600; min-width: 12em; }
.plan-list span { color: var(--c-muted); }
.field-row label.wide { flex: 2; }

@media (max-width: 720px) {
    .plan-list li { flex-direction: column; gap: 2px; }
    .plan-list b { min-width: 0; }
}

/* 종목 목록 — 배정 상태 배지 */
.event-pool .badge {
    margin-left: 6px; padding: 1px 7px; border-radius: 10px;
    font-style: normal; font-size: 11px;
    background: var(--c-line); color: var(--c-muted);
}
/* 이 일자·장소에 이미 배정된 종목 */
.event-pool .badge.is-on { background: rgba(5, 150, 105, 0.12); color: var(--c-on-ok); }
.event-pool > li.is-assigned { border-color: var(--c-ok); }

/* 내려받기 버튼 줄 — 화면이 좁으면 접힌다 */
.dl-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }

/* ------------------------------------------------------------------ */
/* 대회 요강 — 탭 · 첨부 · 표 입력 · 삭제 모달                          */
/* ------------------------------------------------------------------ */

/* 탭 — 요강 / 게임. 두 탭이 한 폼이라 저장 버튼은 아래에 하나뿐이다. */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--c-line); margin-bottom: 18px; }
.tab {
    padding: 9px 20px; border: 0; background: none; cursor: pointer;
    color: var(--c-muted); font-size: 14px; font-weight: 600;
    border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tab:hover { color: var(--c-fg); }
.tab.is-on { color: var(--c-accent); border-bottom-color: var(--c-accent); }

.player-set + .player-set { margin-top: 4px; }

/*
 * .player-set 의 **직계 자식 label** — 라벨을 위에, 입력은 한 줄 통째로.
 *
 * .form-box label 과 .field-row > label 에는 같은 처리가 이미 있는데 여기만
 * 없었다. label 은 기본이 inline 이라 <span> 과 입력이 한 줄에 붙어, 공지
 * 제목 칸이 라벨 옆에 좁게 끼어 있었다.
 *
 * 직계(>)로 한정하는 이유: .radio-row / .radio-col 안의 라디오 라벨까지
 * 블록이 되면 동그라미와 글자가 줄바꿈된다.
 */
.player-set > label { display: block; margin-bottom: 12px; }
.player-set > label > span { display: block; margin-bottom: 4px; font-size: 13px; color: var(--c-muted); }
.player-set > label > input,
.player-set > label > select {
    width: 100%; padding: 9px 11px;
    border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg); font-size: 14px;
}
.player-set > label > input:focus,
.player-set > label > select:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }

/* 여러 줄 입력도 같은 모양으로 */
.player-set label:has(textarea) { display: block; margin-bottom: 12px; }
.player-set label > textarea {
    display: block; width: 100%; margin-top: 4px;
    padding: 9px 11px; border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg); font-size: 14px;
    font-family: inherit; line-height: 1.5; resize: vertical;
}
.player-set label > textarea:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }

.field-row > label.wide { flex: 2 1 320px; }
label.narrow { max-width: 200px; }

/* 라디오 — 가로 한 줄(안내 선택)과 세로 목록(순위 방식) 두 가지 */
.radio-row { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; margin-bottom: 12px; }
.radio-col { flex: 1 1 240px; margin-bottom: 12px; }
/*
 * 세로 목록의 라디오. 문구가 길어 줄바꿈되므로 **위쪽 정렬**이다.
 * center 로 두면 두 줄짜리 항목에서 동그라미가 가운데로 내려가 어느 줄에
 * 붙은 것인지 알기 어렵다.
 */
.radio-col .radio { display: flex; align-items: flex-start; gap: 6px; margin-bottom: 6px; line-height: 1.45; }
.radio-col .radio > input { margin-top: 3px; flex: 0 0 auto; }
/* 순위 방식 문구가 길다. 좁은 열에 3개를 욱여넣지 않는다. */
.radio-col { flex: 1 1 300px; }
.radio-label { font-size: 13px; color: var(--c-muted); }
.radio { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; }

/*
 * 한 줄을 통째로 쓰는 라디오 묶음.
 *
 * "다승 → 득실차 → 승자승 → 다득점" 같은 문장은 300px 열에서 서너 줄로
 * 접혀 어느 항목이 어디까지인지 읽히지 않는다. 셋을 가로로 늘어놓지 않고
 * 각자 한 줄을 준다 — old 도 그렇다.
 */
.radio-col.is-block { flex: 1 1 100%; margin-bottom: 16px; }
.radio-col.is-block .radio-label {
    display: block; margin-bottom: 6px; font-weight: 600; color: var(--c-fg);
}
.radio-col.is-block .radio { padding: 3px 0; margin-bottom: 2px; }
.radio-col.is-block .hint { display: block; margin-top: 4px; }

/* 켜고 끄는 하나짜리 설정. 문구가 길어 라디오와 같은 위쪽 정렬을 쓴다. */
label.checkbox {
    display: flex; align-items: flex-start; gap: 6px;
    font-size: 13px; line-height: 1.45; margin-bottom: 12px;
}
label.checkbox > input { margin-top: 3px; flex: 0 0 auto; }

/* 숫자 칸 뒤에 단위를 붙인다 — "[4] 팀 이하 50%" */
/*
 * 단위가 붙는 숫자 칸 — "[4] 팀 이하 50%"
 *
 * ⚠️ **여기 입력칸은 스스로 꾸며야 한다.** 폼 입력 스타일은 전부
 *    `.player-set > label > input` 처럼 **직계**로 한정돼 있는데(라디오 라벨까지
 *    말려드는 것을 막으려고 그렇게 두었다), 이 칸은 `label > span > input` 이라
 *    한 겹 더 들어가 아무것도 적용되지 않았다. 테두리도 여백도 없이 브라우저
 *    기본 모양으로 떠 있었다.
 */
.unit-field { display: block; margin-bottom: 12px; }
.unit-field > span { display: block; margin-bottom: 4px; font-size: 13px; color: var(--c-muted); }

.inline-unit { display: inline-flex; align-items: center; gap: 6px; }
.inline-unit > em { font-style: normal; font-size: 13px; color: var(--c-muted); }
.inline-unit input {
    width: 90px; padding: 9px 11px;
    border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg); font-size: 14px;
}
.inline-unit input:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }

/*
 * 첨부 — 자리를 미리 펼쳐 둔다.
 *
 * 몇 장까지 되는지, 지금 몇 장이 차 있는지가 화면에 보여야 한다. 입력 하나에
 * `multiple` 만 걸어 두면 둘 다 알 수 없다.
 */
.file-set { margin-bottom: 16px; }
.file-label { display: block; font-size: 13px; color: var(--c-muted); margin-bottom: 2px; }
.file-slots { list-style: none; margin: 6px 0; padding: 0; font-size: 13px; }
.file-slot {
    display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
    padding: 6px 8px; border: 1px solid var(--c-line); border-radius: var(--radius); margin-bottom: 4px;
}
.file-slot-no { flex: 0 0 100px; color: var(--c-muted); font-size: 12px; }
.file-slot input[type="file"] { flex: 1 1 220px; min-width: 0; }
.file-link { flex: 1 1 220px; min-width: 0; overflow-wrap: anywhere; }
.file-drop { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--c-on-error); }

/*
 * 표 형태 입력 — 기권 점수(단·복식 × 단계), 구간 점수, 급수별 점수.
 * 라벨을 칸마다 반복하지 않으려고 표로 만든다.
 */
.grid-input { width: auto; margin-bottom: 10px; }
.grid-input th { background: none; font-size: 12px; color: var(--c-muted); font-weight: 600; padding: 4px 8px; }
.grid-input td { padding: 3px 6px; border-bottom: 0; }
.grid-input input[type="number"] { width: 84px; }
.grid-input input[type="text"] { width: 110px; }
.grid-input input, .grid-input select {
    padding: 6px 8px; border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg); font-size: 13px;
}

.range-table, .level-table { margin-top: 10px; }

/*
 * 구간 한 줄을 **문장처럼** 읽히게 한다.
 *
 *   종목 팀수 [1] 팀 이상 [100] 팀 미만 → 승리당 [10] 점
 *
 * 표의 머리글로 "시작 / 끝 / 점수" 라고만 적었을 때는 무엇의 시작인지,
 * 끝이 포함인지 알 수 없었다. 단위를 칸 사이에 끼워 두면 읽으면 그대로 뜻이 된다.
 */
.range-row {
    border: 1px solid var(--c-line); border-radius: var(--radius);
    padding: 8px 10px; margin-bottom: 6px;
}
.range-row.is-bad { border-color: var(--c-danger); background: color-mix(in srgb, var(--c-danger) 6%, transparent); }
.range-line { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.range-line input[type="number"] { width: 78px; }
.range-line input {
    padding: 6px 8px; border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg); font-size: 13px;
}
.range-word { font-size: 13px; color: var(--c-muted); }
.range-arrow { font-size: 13px; color: var(--c-muted); padding: 0 2px; }
.range-drop { margin-left: auto; }
.range-sub {
    display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
    margin-top: 6px; padding-top: 6px; border-top: 1px dashed var(--c-line);
}

/* 표가 좁은 화면을 밀어내지 않게. 넘치면 표만 가로로 스크롤한다. */
.grid-input { display: block; max-width: 100%; overflow-x: auto; }

/* 목록의 공개/비공개 전환 — 버튼이지만 링크처럼 보인다 */
.btn-link-state {
    border: 0; background: none; cursor: pointer; font-size: 13px;
    color: var(--c-muted); padding: 0;
}
.btn-link-state.is-open { color: var(--c-on-ok); font-weight: 600; }

.btn-danger {
    padding: 9px 18px; border: 0; border-radius: var(--radius);
    background: var(--c-danger); color: #fff; font-size: 14px; font-weight: 600; cursor: pointer;
}
.btn-danger:disabled { background: var(--c-line); color: var(--c-muted); cursor: default; }

/* 삭제 확인 모달 — 문구를 정확히 쳐야 버튼이 열린다 */
.modal { position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center; }
.modal-back { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.45); }
.modal-box {
    position: relative; width: min(440px, calc(100vw - 32px));
    background: var(--c-bg); border-radius: var(--radius);
    padding: 22px 24px; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
}
.modal-box h2 { margin: 0 0 12px; font-size: 17px; }
.modal-target { font-weight: 600; margin: 0 0 8px; }
.modal-prompt { font-size: 13px; margin: 14px 0 6px; }
.modal-box input[type="text"] {
    width: 100%; padding: 9px 11px; border: 1px solid var(--c-line);
    border-radius: var(--radius); background: var(--c-bg); color: var(--c-fg); font-size: 14px;
}
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }

/* 순위 노출 기준 — 최소 팀수 표와 팀수별 미리보기 */
.least-table th { text-align: left; }
.least-table td.muted { font-size: 12px; }

/*
 * "1위 최소 1, 4위 최소 99" 만 보고는 실제로 무엇이 표시되는지 알 수 없다.
 * 팀 수 구간별 결과를 펼쳐 보여 준다 (old ranking_least_preview).
 */
.least-preview {
    max-width: 520px; margin-top: 8px; padding: 10px 12px;
    border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-surface); font-size: 13px;
}
.least-preview-head { font-weight: 600; margin-bottom: 6px; }
.least-row { padding: 1px 0; }
.least-row::before { content: '· '; color: var(--c-muted); }
.least-row.is-warn { color: var(--c-warn); font-weight: 600; }
.least-badge {
    display: inline-block; padding: 0 6px; border-radius: 10px;
    background: var(--c-tint-warn); color: var(--c-on-warn); font-size: 11px; font-weight: 600;
}
.least-note { margin-top: 6px; color: var(--c-muted); font-size: 12px; line-height: 1.5; }
.least-note.is-warn { color: var(--c-warn); }

/* ------------------------------------------------------------------ */
/* 참가 현황 요약 — 참가자 목록 위                                       */
/* ------------------------------------------------------------------ */

.stats-box {
    border: 1px solid var(--c-line); border-radius: var(--radius);
    padding: 12px 16px; margin-bottom: 20px;
}

/* 접수 · 선수 · 종목 · 소속 — 큰 숫자 넷 */
.stats-head { display: flex; flex-wrap: wrap; gap: 20px; margin-bottom: 10px; }
.stats-head span { color: var(--c-muted); font-size: 13px; }
.stats-head b { font-size: 19px; color: var(--c-fg); margin-right: 3px; font-variant-numeric: tabular-nums; }

/* 종별·급수·연령·소속 분포 — 라벨과 값을 두 열로 */
.stats-rows { display: grid; grid-template-columns: max-content 1fr; gap: 3px 14px; margin: 0; font-size: 13px; }
.stats-rows dt { color: var(--c-muted); }
.stats-rows dd { margin: 0; }

/* 3팀 미만이라 대진이 성립하지 않는 종목 */
.stats-warn { list-style: none; margin: 10px 0 0; padding: 8px 10px; font-size: 12px;
    border-left: 3px solid var(--c-warn); background: rgba(217, 119, 6, 0.07); color: var(--c-warn); }
.stats-warn li { margin: 1px 0; }

@media (max-width: 720px) {
    .stats-rows { grid-template-columns: 1fr; gap: 0 0; }
    .stats-rows dt { margin-top: 6px; }
}

/* ------------------------------------------------------------------ */
/* 대회 참가팀 — 필터 줄 · 편성 표시                     docs/10        */
/* ------------------------------------------------------------------ */

/*
 * .page-head 안의 버튼 둘 이상. head 자체가 flex 라 버튼을 그냥 넣으면
 * 세로로 쌓인다.
 */
.head-actions { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
/*
 * .btn-primary 의 기본 width: 100% (로그인 폼 전용)가 여기서도 그대로 적용돼
 * 좁은 팝업에서 버튼 하나가 줄 전체를 차지하고, 옆의 .btn-cancel 이 밀려나
 * 글자가 줄바꿈됐다(contest/winner/receipt.php). .form-actions .btn-primary
 * 와 같은 이유로 폭을 내용에 맞춘다.
 */
.head-actions .btn-primary { width: auto; padding: 10px 20px; }

/*
 * 필터 줄 — 종목 · 소속 · 이름 검색.
 *
 * 라벨을 입력 위에 두는 .field-row 와 달리 **한 줄에 늘어놓는다.** 목록
 * 위에 얹히는 도구 줄이라 세로 공간을 적게 써야 표가 바로 보인다.
 * align-items: flex-end 는 라벨 높이가 달라도 입력 밑선을 맞춘다.
 */
.filter-bar {
    display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
    padding: 12px 14px; margin-bottom: 14px;
    border: 1px solid var(--c-line); border-radius: var(--radius);
    /* 표와 구분되게 아주 옅게만 깔았다. 변수로 둘 만큼 여러 곳에 쓰지 않는다. */
    background: var(--c-surface);
}
.filter-bar label { display: flex; flex-direction: column; gap: 4px; margin: 0; }
.filter-bar label > span { font-size: 12px; color: var(--c-muted); }
.filter-bar select,
.filter-bar input[type="search"] {
    padding: 7px 10px; border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg); font-size: 13px; min-width: 140px;
}
.filter-bar button { width: auto; padding: 7px 14px; font-size: 13px; }
/* 해제 링크는 버튼 줄에 서지만 버튼처럼 보이면 안 된다 */
.filter-bar .btn-link { font-size: 13px; padding: 7px 2px; }

.list-count { margin: 0 0 8px; font-size: 13px; color: var(--c-muted); }

/*
 * 대진 편성 여부. .event-pool .badge.is-on 과 같은 초록을 쓴다 —
 * 이 화면에서도 "이미 자리를 잡았다" 는 뜻이라 의미가 겹친다.
 */
.tag {
    display: inline-block; padding: 2px 8px; border-radius: 999px;
    font-size: 12px; border: 1px solid var(--c-line); color: var(--c-muted);
}
.tag.is-on { background: rgba(5, 150, 105, 0.12); color: var(--c-on-ok); border-color: transparent; }

@media (max-width: 720px) {
    /* 좁으면 필터가 세로로 쌓이고 입력이 폭을 다 쓴다 */
    .filter-bar { flex-direction: column; align-items: stretch; }
    .filter-bar select,
    .filter-bar input[type="search"] { width: 100%; }
}

/* ------------------------------------------------------------------ */
/* 대회 경기 목록 · 경기 수정                            docs/10        */
/* ------------------------------------------------------------------ */

/*
 * 경기 표는 열이 열 개라 기본 셀 여백으로는 한 화면에 안 들어온다.
 * .table-scroll 이 가로 스크롤을 맡고 여기서는 밀도를 올린다.
 */
.match-table { font-size: 13px; }
.match-table td,
.match-table th { padding: 7px 9px; vertical-align: top; }
/* 경기번호·점수는 자릿수를 맞춰 세로로 읽히게 한다 */
.match-table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.match-table td .muted { font-size: 12px; }

/*
 * 수정 폼 위의 읽기 전용 값들 — 종목·대진·팀.
 * .stats-rows 와 같은 두 열 격자다. 뜻이 같아 모양도 같게 둔다.
 */
.read-rows {
    display: grid; grid-template-columns: max-content 1fr; gap: 4px 14px;
    margin: 0 0 14px; padding: 12px 14px; font-size: 13px;
    border: 1px solid var(--c-line); border-radius: var(--radius); background: var(--c-surface);
}
.read-rows dt { color: var(--c-muted); }
.read-rows dd { margin: 0; }

@media (max-width: 720px) {
    .read-rows { grid-template-columns: 1fr; gap: 0; }
    .read-rows dt { margin-top: 6px; }
}

/* 자리 맞바꾸기 체크박스 열 — 표에서 가장 좁은 칸 */
.pick-col { width: 32px; text-align: center; }
.pick-col input { margin: 0; }

/* 세트별 점수 입력 — 좁은 표 세 열 */
.set-table { width: auto; margin-bottom: 8px; }
.set-table th, .set-table td { padding: 5px 8px; }
.set-table input { width: 80px; padding: 7px 9px; border: 1px solid var(--c-line);
    border-radius: var(--radius); background: var(--c-bg); color: var(--c-fg);
    font-size: 14px; text-align: right; font-variant-numeric: tabular-nums; }
.set-table input:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }

/* 입상자 — 종목별 상자 */
.winner-box { border: 1px solid var(--c-line); border-radius: var(--radius);
    padding: 14px 16px; margin-bottom: 16px; }
.winner-box h2 { margin: 0 0 10px; font-size: 15px; display: flex; align-items: baseline;
    gap: 10px; flex-wrap: wrap; }
.winner-box table { margin-bottom: 0; }
.winner-actions { margin-top: 10px; }
.winner-actions button { width: auto; }

/* 종목 옆 "입상자 수/참가 팀 수" */
.event-count { font-size: 12px; font-weight: 400; color: var(--c-muted); }

/* 종목 헤더의 일괄 인쇄 버튼 — 제목 줄과 같은 높이라 폭을 스스로 정한다 */
.winner-box h2 .receipt-link { width: auto; margin-left: auto; font-size: 12px; padding: 4px 10px; }

/*
 * 수령 토글 — .tag 를 버튼으로 쓴다. 눌러서 뭔가 바뀌는 보조 동작이라 커서만 얹는다.
 * 미수령은 기본 .tag(회색 테두리)로는 눈에 안 띈다 — 수령(초록)과 대비되는 색을
 * 따로 준다. .tag 자체는 다른 화면(팀 등록 상태 등)에서도 쓰므로 건드리지 않는다.
 */
.goods-toggle { cursor: pointer; }
.goods-toggle:disabled { cursor: default; opacity: 0.6; }
.goods-toggle:not(.is-on) { background: rgba(220, 38, 38, 0.12); color: var(--c-on-error); border-color: transparent; }

/* 순위 변경 ▲▼ — 순위 칸 앞에 붙는 작은 버튼 */
.order-btn {
    width: 16px; height: 14px; padding: 0; margin-right: 2px;
    border: 1px solid var(--c-line); border-radius: 3px;
    background: var(--c-bg); color: var(--c-muted);
    font-size: 8px; line-height: 1; cursor: pointer; vertical-align: middle;
}
.order-btn:hover { border-color: var(--c-accent); color: var(--c-accent); }

/* 상품수령증 — 화면·인쇄 공용 카드 */
.receipt-sheet { display: flex; flex-direction: column; gap: 16px; }
.receipt-card { border: 2px solid var(--c-line); border-radius: var(--radius); padding: 20px; }
.rc-title { margin: 0 0 6px; text-align: center; font-size: 18px; letter-spacing: 4px; }
.rc-contest { margin: 0 0 14px; text-align: center; padding: 8px; background: var(--c-line); }
.rc-info { width: 100%; border-collapse: collapse; margin-bottom: 12px; }
.rc-info th, .rc-info td { border: 1px solid var(--c-line); padding: 8px; font-weight: 600; }
.rc-sign { width: 100%; border-collapse: collapse; }
.rc-sign th { border: 1px solid var(--c-line); padding: 8px; text-align: left; width: 30%; }
.rc-sign td { border: 1px solid var(--c-line); height: 40px; }

/*
 * 인쇄 — 지금까지 admin.css 에는 @media print 가 아예 없었다. 입상 선수 목록의
 * 인쇄 버튼(winner/player.php)도 실은 헤더·네비까지 같이 찍히고 있었다.
 * 여기서 한 번에 고친다.
 */
@media print {
    /*
     * ⚠️ **인쇄는 늘 밝게.**
     *
     * 시스템이 다크면 토큰이 어두운 값으로 뒤집혀 있다. 그대로 인쇄하면 흰
     * 종이에 **밝은 글씨**가 찍혀 사라진다(브라우저는 배경색을 기본적으로 안
     * 찍는다). 그래서 종이용으로 토큰을 되돌린다.
     */
    :root {
        --c-bg: #ffffff;
        --c-fg: #1c1e21;
        --c-muted: #4b5563;
        --c-line: #cbd5e1;
        --c-surface: #f1f3f5;
        --c-tint-ok: #ecfdf5;
        --c-tint-warn: #fff7ed;
        --c-tint-error: #fef2f2;
        --c-tint-info: #eff6ff;
        --c-on-ok: #047857;
        --c-on-error: #b91c1c;
        --c-on-warn: #9a3412;
        --c-on-info: #1d4ed8;
        --c-warn: #a86500;
        color-scheme: light;
    }
    body { background: #fff; color: #1c1e21; }

    .app-header, .app-footer, .app-nav, .contest-nav, .flash,
    .page-head .head-actions, .winner-box h2 .receipt-link { display: none; }
    .receipt-card { border: 0; padding: 0; page-break-after: always; }
    .receipt-card:last-child { page-break-after: auto; }
}

/* 단체순위 가산점 입력 — 표 안이라 좁게 */
.plus-input { width: 90px; padding: 6px 8px; border: 1px solid var(--c-line);
    border-radius: var(--radius); background: var(--c-bg); color: var(--c-fg);
    font-size: 13px; text-align: right; font-variant-numeric: tabular-nums; }
.plus-input:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }

/* 목록 위 줄 — 건수와 내려받기 링크를 양끝에 */
.count-row { display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; flex-wrap: wrap; margin: 0 0 8px; }
.count-row .list-count { margin: 0; }

/* ------------------------------------------------------------------ */
/* 코트 현황판                                            docs/10        */
/* ------------------------------------------------------------------ */

/*
 * 본부석 모니터에 띄워놓고 보는 화면이라 **코트(열) × 라인(행)** 격자다.
 * 코트 수가 많으면 화면 폭을 넘으므로 컨테이너가 가로 스크롤을 맡는다
 * (.table-scroll 과 같은 이유, 다만 표가 아니라 격자라 별도 클래스다).
 *
 * 열 개수는 뷰가 `style="--courts: N"` 으로 넘긴다. 코트 수가 대회마다
 * 다르므로 CSS 에 적어 둘 수 없다 — 타임테이블 화면도 같은 방식이다.
 */
/*
 * 종목 범례 — 누르면 그 종목 경기가 도드라진다.
 *
 * 색은 대진표 타임테이블의 범례(.tt-chip)와 같은 8색 순환이다. 두 화면을
 * 오가는 사람이 같은 종목을 같은 색으로 찾게 맞춘 것이다.
 */
.cb-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0 0 12px; }
.cb-legend-label { font-size: 12px; color: var(--c-muted); margin-right: 2px; }
.cb-chip {
    --hue: calc(var(--i) * 45);
    padding: 3px 10px;
    border: 1px solid var(--c-line);
    border-left: 3px solid hsl(var(--hue) 60% 55%);
    border-radius: var(--radius);
    background: hsl(var(--hue) 60% 55% / 0.09);
    color: inherit; font-size: 12px; font-family: inherit; cursor: pointer;
}
.cb-chip:hover { border-color: var(--c-accent); }
.cb-chip.is-on { border-color: var(--c-accent); background: var(--c-tint-info); font-weight: 700; }
.cb-chip-n { color: var(--c-muted); margin-left: 4px; font-weight: 400; }

.court-board {
    display: grid;
    grid-template-columns: 76px repeat(var(--courts, 1), minmax(190px, 1fr));
    gap: 6px; overflow: auto; padding-bottom: 8px; max-height: 78vh;
}

/*
 * ⚠️ 시간 열과 코트 머리는 **스크롤을 따라와야** 한다. 코트가 열댓 개인
 *    대회에서 오른쪽 끝까지 밀면 "몇 시 몇 번째 줄인지" 가 화면 밖으로
 *    나가 격자가 뜻을 잃는다. 겹치는 좌상단 모서리가 z-index 가 제일 높다.
 */
.cb-corner, .cb-head { position: sticky; top: 0; z-index: 2; background: var(--c-surface); }
.cb-corner { left: 0; z-index: 4; }
.cb-line   { position: sticky; left: 0; z-index: 3; background: var(--c-bg); }

.cb-head {
    display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
    padding: 8px 10px; border: 1px solid var(--c-line); border-radius: var(--radius);
    font-size: 14px; font-weight: 700;
}
.court-progress { font-size: 12px; color: var(--c-muted); font-weight: 400; }

/* 좌측 열 — 그 라인의 시각(크게)과 코트 내 순번(작게). 순번은 화면에서만 1부터다 */
.cb-line {
    display: flex; flex-direction: column; justify-content: center;
    padding: 8px 6px; text-align: right;
}
.cb-line b    { font-size: 15px; font-variant-numeric: tabular-nums; }
.cb-line span { font-size: 11px; color: var(--c-muted); }

/* 경기 없는 자리 — 빈 라인도 통째로 이렇게 남는다. 글자는 넣지 않는다 */
.cb-cell { min-height: 56px; }
.cb-cell.is-empty {
    border: 1px dashed var(--c-line); border-radius: var(--radius);
    background: var(--c-surface);
}

/* 경기 한 줄 — 눌러서 점수입력 팝업(선수 변경과 같은 data-popup 패턴)을 연다 */
.court-row {
    display: block; padding: 8px; border: 1px solid var(--c-line);
    border-radius: var(--radius); color: var(--c-fg); font-size: 13px;
    background: var(--c-bg); height: 100%;
}
.court-row + .court-row { margin-top: 6px; }   /* 한 칸에 겹친 경기 */
.court-row:hover { border-color: var(--c-accent); text-decoration: none; }

/*
 * 종목 강조 — 고른 종목만 남기고 나머지는 물러난다.
 *
 * 숨기지는 않는다. 코트가 비어 보이면 "경기 없는 자리" 와 구분되지 않기
 * 때문이다 — 이 화면이 끝난 경기도 지우지 않는 것과 같은 이유다.
 * 상태 색(is-state-*)은 배경이라 윤곽선으로 겹쳐 칠해도 서로 지우지 않는다.
 */
.court-board.is-lit-on .court-row { opacity: 0.28; }
.court-board.is-lit-on .court-row.is-lit {
    opacity: 1;
    outline: 2px solid var(--c-accent);
    outline-offset: -2px;
}

/*
 * 상태 색 — old dashboard_court 의 파랑=종료 / 빨강=진행중 / 노랑=대기를
 * 신규 팔레트로 옮긴 것이다. 끝난 경기를 숨기지 않으므로 색이 유일한
 * 구분이다. 대기(N)는 기본 배경 그대로 둔다 — 대부분이 대기라 칠하면
 * 화면 전체가 물든다.
 */
.court-row.is-state-E { background: var(--c-tint-info); color: var(--c-muted); }
.court-row.is-state-S { background: var(--c-tint-error); border-color: var(--c-danger); }

.court-row .cr-num { color: var(--c-muted); font-size: 12px; }
.court-row .cr-time {
    float: right; font-size: 12px; color: var(--c-on-warn);
    font-variant-numeric: tabular-nums;
}
.court-row .cr-event { display: block; margin: 2px 0; font-size: 12px; color: var(--c-muted); }
.court-row .cr-teams {
    display: flex; align-items: center; justify-content: space-between; gap: 6px;
}
.court-row .cr-teams .is-win { font-weight: 700; }
.court-row .cr-score { font-variant-numeric: tabular-nums; color: var(--c-muted); flex-shrink: 0; }

/*
 * ⚠️ `hidden` 은 이 한 줄이 없으면 **믿을 수 없다.**
 *
 * 브라우저 기본 스타일시트의 `[hidden] { display: none }` 은 우리가 쓴 규칙에
 * 언제나 진다. `class="field-row" hidden` 처럼 display 를 지정한 클래스가
 * 붙어 있으면 `hidden` 이 아무 일도 하지 않는다.
 *
 * 실제로 요강의 "급수별로 다른 점수 적용" 을 골라도 위쪽 1~4위 점수칸이
 * 그대로 보였다 — JS 는 `hidden` 을 제대로 켜고 있었고 CSS 가 무시했다.
 * 오류가 나지 않아 원인을 찾기 어려운 종류다.
 *
 * 이 규칙 전에는 걸릴 때마다 `.modal[hidden]` 처럼 하나씩 덧대고 있었다.
 * 한 번에 막는다.
 *
 * ⚠️ **파일 맨 끝에 둔다.** `!important` 만으로도 브라우저에서는 이기지만,
 *    소스 순서만 보는 도구(테스트용 DOM 구현 등)에서는 뒤에 오는 규칙이
 *    이긴다. 끝에 두면 두 방식 모두에서 이긴다. 새 규칙은 이 위에 쓸 것.
 */
[hidden] { display: none !important; }

/* ── 목록 페이지 이동 ── */
/*
 * popup.css 에도 같은 이름이 있다. 두 레이아웃이 서로 다른 CSS 를 읽으므로
 * 양쪽에 있어야 하고, 마크업은 `partials/pager.php` 한 벌이라 갈리지 않는다.
 */
.pager {
    display: flex; align-items: center; justify-content: center; gap: 14px;
    margin: 20px 0 4px;
}
.pager-summary { color: var(--c-muted); font-size: 13px; }
.pager-summary em { font-style: normal; margin-left: 6px; font-variant-numeric: tabular-nums; }
.pager-prev, .pager-next {
    padding: 6px 12px;
    border: 1px solid var(--c-line); border-radius: var(--radius);
    font-size: 13px; text-decoration: none; color: var(--c-fg);
}
.pager-prev:hover, .pager-next:hover { border-color: var(--c-accent); }

/* ── 바닥글의 약관·방침 ── */
.legal-links { display: flex; gap: 12px; }
.legal-links a { font-size: 12px; color: var(--c-muted); }
.app-footer { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; justify-content: space-between; }

/* ── 이메일 미인증 안내 띠 ── */
/*
 * 대리 로그인 띠(.impersonate-banner)와 같은 자리·같은 모양이지만 **이쪽은
 * admin.css 에 있다.** 저쪽은 관리자 화면 전용(admin-panel.css)이고, 이 띠는
 * 로그인한 사람이면 어느 화면에서나 보여야 하기 때문이다.
 *
 * 색은 경고색이 아니라 강조색이다 — 지금 뭔가 잘못됐다는 뜻이 아니라
 * "아직 안 끝난 일이 있다" 는 안내라서다.
 */
.verify-banner {
    display: flex; flex-wrap: wrap; gap: 10px; align-items: center; justify-content: center;
    padding: 8px 14px;
    background: var(--c-accent); color: #fff;
    font-size: 14px; font-weight: 600;
}
.verify-banner a { color: #fff; text-decoration: underline; }

/* ── 마이페이지 ── */
/*
 * 섹션마다 폼이 따로다(→ app/Views/my/index.php). 입력 칸 모양은 로그인·가입
 * 화면(.auth-box)과 같게 두되, 폭만 좁힌다 — 한 줄짜리 입력이 화면 끝까지
 * 늘어나면 어디를 채워야 할지 눈이 헤맨다.
 */
.my-form { max-width: 420px; }
.my-form label { display: block; margin-bottom: 14px; }
.my-form label > span { display: block; margin-bottom: 4px; font-size: 13px; color: var(--c-muted); }
.my-form input[type="text"],
.my-form input[type="email"],
.my-form input[type="tel"],
.my-form input[type="password"],
.my-form select {
    width: 100%;
    padding: 9px 11px;
    border: 1px solid var(--c-line); border-radius: var(--radius);
    background: var(--c-bg); color: var(--c-fg); font-size: 14px;
}
.my-form input:focus, .my-form select:focus { outline: 2px solid var(--c-accent); outline-offset: -1px; }

/* ⚠️ 체크박스는 위의 width:100% 를 물려받으면 한 줄을 통째로 차지한다 */
.my-form .agree-row input[type="checkbox"] { width: auto; }

.my-meta { margin: 0 0 12px; font-size: 12px; color: var(--c-muted); }

/*
 * 이메일 교체 대기 안내 — 확정 링크를 누르기 전까지 계속 보인다.
 * 사용자가 "바꿨는데 왜 그대로지" 로 헤매지 않게 하는 장치다.
 */
.my-pending {
    margin-top: 12px; padding: 12px 14px;
    border: 1px solid var(--c-accent); border-radius: var(--radius);
    font-size: 13px;
}
.my-pending p { margin: 0 0 8px; }

/*
 * 탈퇴 — 접어 둔다. 되돌릴 수 없는 일이라 실수로 누를 자리에 두지 않는다.
 */
.my-danger { margin: 28px 0 8px; border: 1px solid var(--c-line); border-radius: var(--radius); }
.my-danger > summary {
    padding: 12px 14px; cursor: pointer;
    font-size: 14px; font-weight: 600; color: var(--c-on-error);
}
.my-danger[open] > summary { border-bottom: 1px solid var(--c-line); }
.my-danger .my-form, .my-danger .my-danger-warn { margin: 14px; }
.my-danger-warn { font-size: 13px; line-height: 1.6; color: var(--c-muted); }
