/* ============================================
   КСЛТ — СУДЕЙСКИЙ ЭКРАН (префикс um-)
   Пульт, а не страница: одна задача, две мишени, ноль чтения.
   ============================================ */

/* ПАЛИТРА — ПСЕВДОНИМЫ ТОКЕНОВ, А НЕ ВТОРАЯ ПАЛИТРА.
   До 24.09 здесь стояли свои краски числом, и три из них были чуть-чуть не
   те: #EF5350 против --danger #FF4757, #66BB6A против --success #2ED573,
   #0a0a0a против --bg-base. В продукте выходило два красных и два зелёных.
   Имена --um-* оставлены — по ним зовут краску правила ниже, — но каждое
   теперь ведёт к одному определению в токенах. */
:root {
    --um-bg:     var(--bg-base);
    --um-card:   var(--bg-elevated);
    --um-accent: var(--accent);
    --um-text:   var(--text-primary);
    --um-dim:    var(--text-muted);

    /* ДВЕ КРАСКИ ИГРОКОВ — единственное своё, и это осознанно.
       Судья на корте должен различать две кнопки боковым зрением, не читая.
       Статусных красок тут нет: экран закрытый, служебный, и ни красный, ни
       зелёный на нём ничего не значат. Синий и оранжевый взяты потому, что
       различимы при самой частой слепоте — красно-зелёной. */
    --um-p1: var(--player-1);
    --um-p2: var(--player-2);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
    background: var(--um-bg);
    color: var(--um-text);
    font-family: var(--font-sans);
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    -webkit-user-select: none;
    user-select: none;
    overscroll-behavior: none;
}

/* МИШЕНЬ — ДОЛЯ ЭКРАНА, А НЕ ЧИСЛО. Померено 25.09: кнопка очка гуляла
   471 / 80 / 651 / 395 / 527 по пяти видам и 471 / 444 / 406 внутри одного
   вида — это был остаток flex: 1, а не решение. Мышечная память судьи
   опирается на неё сильнее всего. Остаток высоты уходит воздуху НАД
   мишенью: мишень и нижний ряд едут вниз одной группой, чтобы до них
   доставал большой палец. */
#um-app {
    --um-target: 38dvh;
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: var(--space-3);
    max-width: 500px;
    margin: 0 auto;
    width: 100%;
    gap: var(--space-3);
}

/* ЗАГОЛОВОК МАТЧА. Судья не видел, какой матч ведёт: ни турнира, ни
   соперников — только счёт. Если у него два матча подряд, перепутать легко. */
.um-match-head { text-align: center; padding: 0 var(--space-2); }
.um-match-players { font-size: var(--fs-base); font-weight: 700; line-height: 1.3; }
.um-match-meta { font-size: var(--fs-xs); color: var(--um-dim); margin-top: var(--space-1); }

/* Полоса состояния */
.um-status {
    text-align: center;
    font-size: var(--fs-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    padding: var(--space-2);
    border-radius: var(--radius-sm);
}
.um-status-warmup { background: var(--surface-glass-hover); color: var(--um-dim); }
.um-status-live { background: var(--danger-subtle); color: var(--danger); animation: um-pulse 1.5s infinite; }
.um-status-paused { background: var(--warning-subtle); color: var(--warning); }
.um-status-break { background: var(--warning-subtle); color: var(--warning); }
.um-status-completed { background: var(--accent-subtle); color: var(--um-accent); }

@keyframes um-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
}

/* Победитель */
.um-winner {
    text-align: center;
    font-size: var(--fs-md);
    font-weight: 700;
    color: var(--um-accent);
    padding: var(--space-3);
    background: var(--accent-subtle);
    border-radius: var(--radius-md);
    border: var(--bw-hair) solid var(--um-accent);
}

/* Табло */
.um-scoreboard {
    background: var(--um-card);
    border-radius: var(--radius-lg);
    padding: var(--space-2);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.um-player-row {
    display: grid;
    grid-template-columns: 24px 1fr 44px 44px;
    align-items: center;
    padding: var(--space-3) var(--space-2);
    border-radius: var(--radius-md);
    gap: var(--space-2);
    transition: background 0.2s;
}
.um-player-row.um-serving { background: var(--surface-glass); }
.um-player-row.um-winner-row { background: var(--accent-subtle); }

/* ЗНАЧОК ПОДАЧИ — свой, а не эмодзи 🎾. Эмодзи рисует операционная система:
   на одном телефоне он жёлтый, на другом зелёный, на третьем плоский, и
   размер его нам не подчиняется. */
.um-serve-dot { display: flex; align-items: center; justify-content: center; }
.um-serve-dot::before {
    content: '';
    width: 12px;
    height: 12px;
    border-radius: var(--radius-full);
    background: var(--um-accent);
}
.um-serve-dot:empty::before { display: none; }

/* ИМЯ НЕ ОБРЕЗАЕТСЯ. Было nowrap + ellipsis, и на 390 «Иван Корабельников»
   показывался как «Иван Корабельн…» — 203 пикселя текста в 178 коробки.
   Судья обязан видеть, кто есть кто: перепутать игроков дороже, чем
   потратить вторую строку. */
.um-player-name {
    font-size: var(--fs-md);
    font-weight: 600;
    line-height: 1.1;
    overflow-wrap: anywhere;
}

.um-games, .um-points {
    text-align: center;
    font-size: var(--fs-xl);
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}
.um-games { color: var(--um-text); }
.um-points { color: var(--um-accent); }

/* История сетов */
.um-sets { display: flex; gap: var(--space-2); justify-content: center; flex-wrap: wrap; }
.um-set-score {
    background: var(--um-card);
    border-radius: var(--radius-md);
    padding: var(--space-2) var(--space-3);
    display: flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--fs-base);
    font-weight: 600;
}
.um-set-label {
    font-size: var(--fs-2xs);
    color: var(--um-dim);
    margin-right: var(--space-1);
    text-transform: uppercase;
}
.um-set-val { font-variant-numeric: tabular-nums; }
.um-set-sep { color: var(--um-dim); }
.um-set-tb { color: var(--um-dim); font-size: var(--fs-xs); }

/* Тайбрейк */
.um-tiebreak-label {
    text-align: center;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--warning);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

/* ЭЙС И ДВОЙНАЯ — ЭТО ОЧКО, А НЕ ПОМЕТКА. Решение Кости 25.09.
   Эйс: очко подающему. Двойная: очко принимающему. Одно касание вместо двух.
   Кто получает очко — сказано именем и полосой его краски: смысл кнопки
   меняется вместе с подачей и обязан это показывать, а ПОЛОЖЕНИЕ её меняться
   не имеет права — судья жмёт не глядя.
   Кнопки стоят постоянно, а не выскакивают после очка: окно на три секунды
   проигрывало гонку с сетью и не открывалось НИ РАЗУ (найдено 25.09). */
.um-marks { display: flex; gap: var(--space-3); }
.um-btn-mark {
    flex: 1;
    min-height: var(--btn-h-lg);
    font-size: var(--fs-base);
    background: var(--um-card);
    color: var(--um-text);
    border: var(--bw-hair) solid var(--border-subtle);
    position: relative;
    padding-left: var(--space-4);
    text-align: left;
    line-height: 1.1;
}
.um-btn-mark b { display: block; font-weight: 700; }
.um-btn-mark span {
    display: block;
    font-size: var(--fs-2xs);
    font-weight: 400;
    color: var(--um-dim);
}
.um-btn-mark::before {
    content: '';
    position: absolute;
    left: 0;
    top: var(--space-2);
    bottom: var(--space-2);
    width: 4px;
    border-radius: var(--radius-full);
    background: var(--um-p1);
}
.um-btn-mark.um-to-p2::before { background: var(--um-p2); }

/* Выбор подающего (разминка) */
.um-serve-choice { text-align: center; }
.um-serve-choice-title {
    font-size: var(--fs-md);
    font-weight: 700;
    color: var(--um-dim);
    margin-bottom: var(--space-3);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.um-serve-choice-btns { display: flex; flex-direction: column; gap: var(--space-3); }
.um-btn-serve {
    min-height: var(--btn-h-lg);
    padding: var(--space-3) var(--space-4);
    font-size: var(--fs-base);
    background: var(--um-card);
    color: var(--um-text);
    border: var(--bw-hair) solid var(--border-light);
    transition: border-color var(--transition-fast), background var(--transition-fast);
}
.um-btn-serve-active {
    border-color: var(--um-accent);
    background: var(--accent-subtle);
    color: var(--um-accent);
}

/* Перерыв: смена сторон и перерыв между сетами */
.um-changeover {
    text-align: center;
    background: var(--warning-subtle);
    border: var(--bw-hair) solid var(--warning);
    border-radius: var(--radius-lg);
    padding: var(--space-3);
}
.um-changeover-label {
    font-size: var(--fs-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--warning);
    margin-bottom: var(--space-2);
}
.um-changeover-time {
    font-size: var(--fs-3xl);
    font-weight: 800;
    color: var(--warning);
    font-variant-numeric: tabular-nums;
    line-height: 1;
    margin-bottom: var(--space-3);
}
.um-changeover-bar {
    height: 4px;
    background: var(--surface-glass-hover);
    border-radius: var(--radius-full);
    overflow: hidden;
    margin-bottom: var(--space-3);
}
.um-changeover-fill {
    height: 100%;
    background: var(--warning);
    border-radius: var(--radius-full);
    transition: width 1s linear;
}
.um-btn-continue {
    width: 100%;
    min-height: var(--btn-h-lg);
    font-size: var(--fs-base);
    background: transparent;
    color: var(--warning);
    border: var(--bw-hair) solid var(--warning);
}

/* Мишень */
.um-actions {
    flex: 0 0 var(--um-target);
    display: flex;
    gap: var(--space-3);
    margin-top: auto;
}

.um-btn {
    border: none;
    border-radius: var(--radius-lg);
    font-weight: 700;
    cursor: pointer;
    transition: transform 0.1s, opacity 0.1s;
    -webkit-tap-highlight-color: transparent;
    /* ЗУМ ВЕРНУЛИ СТРАНИЦЕ, А ДВОЙНОЙ ТАП ЗАБРАЛИ У КНОПОК.
       user-scalable=no стоял ровно на одной странице из девяноста и валил
       WCAG 1.4.4. Здесь то же самое, но точечно: страницу можно увеличить,
       а кнопка не ждёт второго касания. */
    touch-action: manipulation;
}
.um-btn:active { transform: scale(0.96); opacity: 0.85; }

/* КНОПКА ОЧКА. Заливка — краска игрока, текст ПОЧТИ-ЧЁРНЫЙ, а не белый:
   белый на светлой заливке порог контраста не проходит. То же правило, что
   у Badge 27:53 в стиле Solid — заливка обязана доминировать, а читается
   она за счёт тёмного текста. */
.um-btn-p1, .um-btn-p2 {
    flex: 1;
    font-size: var(--fs-lg);
    line-height: 1.3;
    color: var(--accent-on);
}
.um-btn-p1 { background: var(--um-p1); }
.um-btn-p2 { background: var(--um-p2); }

.um-btn-start {
    flex: 1;
    font-size: var(--fs-xl);
    color: var(--accent-on);
    background: var(--um-accent);
}

/* Нижний ряд */
.um-bottom-actions { display: flex; gap: var(--space-3); }
.um-btn-undo, .um-btn-pause {
    flex: 1;
    min-height: var(--btn-h-lg);
    font-size: var(--fs-base);
    background: var(--um-card);
    color: var(--um-text);
    border: var(--bw-hair) solid var(--border-subtle);
}

/* ПРИЧИНА ПЕРЕРЫВА. Кнопка «Перерыв» спрашивает, почему остановили:
   медицинский, туалет, погода, другое. Пятой причины («технический» —
   сетка, мяч, свет) нет намеренно: каждая лишняя кнопка — лишнее решение в
   момент, когда судье надо действовать, а «Другое» её закрывает. */
.um-why {
    position: fixed;
    inset: 0;
    background: var(--overlay-modal);
    display: flex;
    align-items: flex-end;
    padding: var(--space-3);
    z-index: 5;
}
.um-why-card {
    width: 100%;
    max-width: 500px;
    margin: 0 auto;
    background: var(--um-card);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.um-why-title {
    font-size: var(--fs-md);
    font-weight: 700;
    text-align: center;
    color: var(--um-dim);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.um-btn-why {
    min-height: var(--btn-h-lg);
    font-size: var(--fs-base);
    background: var(--um-bg);
    color: var(--um-text);
    border: var(--bw-hair) solid var(--border-light);
}
.um-btn-why-cancel { background: transparent; border-color: transparent; color: var(--um-dim); }

/* Ошибка */
.um-error {
    text-align: center;
    color: var(--danger);
    font-size: var(--fs-md);
    padding: var(--space-16) var(--space-6);
}

/* ТЕЛЕФОН БОКОМ — ОДНА РАСКЛАДКА. Решение Кости 25.09: вторая раскладка
   стоит второго набора правил, второго прогона теста и второго источника
   кривизны, а судья держит телефон вертикально одной рукой — боком он
   оказывается случайно, от автоповорота. Замерено 25.09: боком с длинными
   именами документ был 422 при высоте 390, кнопки очка уезжали за край. */
.um-turn { display: none; }

/* ПЛАНШЕТ. Колонка растёт, мишень становится ниже: высоты там много, а
   тянуться через весь экран незачем. Планшет боком не отделяется — там
   высота 768 и портретная колонка помещается целиком. */
@media (min-width: 641px) {
    #um-app {
        --um-target: 34dvh;
        max-width: 720px;
        padding: var(--space-4);
        gap: var(--space-4);
    }
    .um-player-row { grid-template-columns: 28px 1fr 52px 52px; }
    .um-serve-choice-btns { flex-direction: row; }
    .um-btn-serve { flex: 1; }
}

@media (orientation: landscape) and (max-height: 500px) {
    #um-app { display: none; }
    .um-turn {
        display: flex;
        flex: 1;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: var(--space-4);
        padding: var(--space-6);
        text-align: center;
    }
    .um-turn svg { width: 56px; height: 56px; color: var(--um-accent); }
    .um-turn p { font-size: var(--fs-lg); font-weight: 700; }
    .um-turn small { font-size: var(--fs-sm); color: var(--um-dim); }
}

/* КОЛЬЦО ФОКУСА. Не было ни у одной кнопки: судья, идущий клавишами или
   внешней клавиатурой, не видел, где он. WCAG 2.4.7. */
.um-btn:focus-visible {
    outline: var(--bw-heavy) solid var(--um-accent);
    outline-offset: 3px;
}


