/* =====================================================================
   ПЕРЕИСПОЛЬЗУЕМЫЕ КОМПОНЕНТЫ РЕДИЗАЙНА
   =====================================================================
   Новые общие CSS-компоненты: Icon, Button, Modal, Badge, FormField,
   EmptyState/SkeletonLoader. Используются на экранах, уже переверстанных
   в рамках редизайна (см. дерево экранов в плане).

   Сознательно НЕ переиспользуют старые имена классов (.btn, .help-area,
   .input-row__field и т.п.) — те классы используются в десятках мест на
   ещё не переверстанных экранах, и их массовое переопределение сейчас
   сломало бы то, что уже работает и не проверено визуально в этой среде.
   Экраны переводятся на новые классы по одному, по мере редизайна
   (см. план: "модальные окна — визуально сразу, механизм — по ходу").
   ===================================================================== */

/* ================= ICON ================= */
.icon {
    width: var(--icon-md);
    height: var(--icon-md);
    display: inline-block;
    vertical-align: middle;
    flex-shrink: 0;
    fill: none;
}

.icon-sm {
    width: var(--icon-sm);
    height: var(--icon-sm);
}

/* Видимо только для скринридеров — стандартная техника sr-only */
.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;
}

.icon-lg {
    width: var(--icon-lg);
    height: var(--icon-lg);
}

/* Единый вид фокуса с клавиатуры для новых интерактивных компонентов (a11y) */
.action-btn:focus-visible,
.form-field__input:focus-visible,
.modal-v2__close:focus-visible,
.checklist-item:focus-visible {
    outline: 3px solid var(--color-primary-700);
    outline-offset: 2px;
}

/* ================= BUTTON (primary / secondary / destructive / disabled) ================= */
.action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-1);
    min-height: var(--tap-min);
    padding: 0 var(--sp-3);
    border-radius: var(--radius-md);
    border: 2px solid transparent;
    font-family: inherit;
    font-size: var(--font-size-base);
    font-weight: 700;
    cursor: pointer;
    transition: filter var(--motion-fast), opacity var(--motion-fast);
    text-decoration: none;
    box-sizing: border-box;
}

.action-btn .icon {
    flex-shrink: 0;
}

.action-btn--primary {
    /* Было var(--color-primary-700) — самый тёмный оттенок палитры вместо
       базового брендового зелёного (208B3A = --color-primary-500), которым
       он и должен быть, раз это ГЛАВНАЯ кнопка (OK/подтверждение/сабмит) и
       встречается практически на каждом окне сайта — из-за этого почти
       весь сайт визуально казался куда темнее задуманного (п.2 багов после
       редизайна). -700 остаётся для рамок/текста на белом, как и было
       задумано, просто не для больших заливок самой частой кнопки. */
    background: var(--color-primary-500);
    color: var(--color-btn-primary-text);
}

.action-btn--primary:hover {
    filter: brightness(1.1);
}

.action-btn--secondary {
    background: var(--color-surface);
    color: var(--color-primary-700);
    border-color: var(--color-primary-700);
}

.action-btn--secondary:hover {
    background: var(--color-surface-alt);
}

.action-btn--destructive {
    background: var(--color-btn-destructive-bg);
    color: var(--color-btn-primary-text);
}

.action-btn--destructive:hover {
    background: var(--color-btn-destructive-bg-hover);
}

.action-btn:disabled,
.action-btn--disabled,
.action-btn[aria-disabled="true"],
/* #user-race-on-map (окно "время по КП", см. CLAUDE.md) переключает именно
   .prohibited, а не .action-btn--disabled — общесайтовый класс "недоступно"
   (см. .menu-item.prohibited и т.д.), а не свой собственный. */
.action-btn.prohibited {
    background: var(--color-surface-disabled);
    color: var(--color-text-muted);
    border-color: transparent;
    cursor: not-allowed;
    filter: none;
    /* Эти кнопки — div'ы, не <button disabled>, клик у них по умолчанию
       никак не блокируется самим DOM. pointer-events:none не даёт клику
       даже долетать до делегированного обработчика (closest('[data-action]')),
       а не просто красит кнопку серым, пока она всё ещё реально нажимается. */
    pointer-events: none;
}

/* Кнопка на всю ширину — типично для мобильных форм в одно касание */
.action-btn--block {
    width: 100%;
}

/* ================= MODAL (единая оболочка) ================= */
.modal-v2 {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal-overlay);
    display: none;
    align-items: center;
    justify-content: center;
    padding: var(--sp-2);
    background: var(--color-overlay);
    animation: modal-v2-fade var(--motion-base);
}

.modal-v2--no-backdrop {
    background: transparent;
    pointer-events: none;
}

.modal-v2.is-open {
    display: flex;
}

.modal-v2__panel {
    position: relative;
    z-index: var(--z-modal-panel);
    width: 100%;
    max-width: 480px;
    max-height: 90dvh;
    overflow-y: auto;
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: var(--sp-3);
    pointer-events: auto;
    animation: modal-v2-pop var(--motion-base);
}

.modal-v2__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    margin-bottom: var(--sp-2);
}

.modal-v2__title {
    font-size: var(--font-size-md);
    font-weight: 900;
    color: var(--color-primary-700);
}

.modal-v2__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--tap-min);
    height: var(--tap-min);
    margin: calc(var(--sp-1) * -1);
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    border-radius: var(--radius-pill);
    flex-shrink: 0;
}

.modal-v2__close:hover {
    background: var(--color-surface-muted);
    color: var(--color-text);
}

.modal-v2__body {
    font-size: var(--font-size-sm);
    line-height: 1.5;
}

.modal-v2__actions {
    display: flex;
    gap: var(--sp-1);
    margin-top: var(--sp-2);
}

/* 3 кнопки ("Себе" в рассылке) должны помещаться в ОДНУ строку даже на
   узком экране модалки (явное требование — не переносить). Вместо min-width
   и flex-wrap (чинили так раньше, но перенос не нужен) — ужимаем паддинг,
   шрифт и иконку именно здесь, не трогая .action-btn по умолчанию. */
.modal-v2__actions .action-btn {
    flex: 1 1 0;
    min-width: 0;
    padding: 0 var(--sp-1);
    font-size: var(--font-size-sm);
}

.modal-v2__actions .action-btn .icon {
    width: var(--icon-sm);
    height: var(--icon-sm);
}

@keyframes modal-v2-fade {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

@keyframes modal-v2-pop {
    from {
        opacity: 0;
        transform: scale(0.95) translateY(8px);
    }

    to {
        opacity: 1;
        transform: scale(1) translateY(0);
    }
}

/* ================= GALLERY LIGHTBOX (п.14) =================
   Полностью самостоятельный компонент на .modal-v2 — не завязан на старый
   #photo-vombat-area (у него своя глобальная логика "клик где угодно
   закрывает", которая рискованно конфликтует с добавлением кнопок
   навигации внутрь). Открывается/закрывается только через свои
   data-action="gallery-*", см. main.js. */
.modal-v2--gallery .modal-v2__panel {
    max-width: min(92vw, 900px);
    padding: 0;
    background: var(--color-text);
    overflow: hidden;
}

.gallery-lightbox__photo {
    display: block;
    width: 100%;
    max-height: 80dvh;
    object-fit: contain;
    background: var(--color-text);
    margin: 0;
    border-radius: 0;
    box-shadow: none;
    cursor: default;
}

.gallery-lightbox__close {
    position: absolute;
    top: var(--sp-3);
    right: var(--sp-3);
    background: rgba(0, 0, 0, 0.55);
    color: var(--color-text-on-dark);
    z-index: 1;
}

.gallery-lightbox__close:hover {
    background: rgba(0, 0, 0, 0.75);
    color: var(--color-text-on-dark);
}

.gallery-lightbox__nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    padding: var(--sp-2);
    background: rgba(0, 0, 0, 0.55);
}

.gallery-lightbox__nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--tap-min);
    height: var(--tap-min);
    border: none;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.15);
    color: var(--color-text-on-dark);
    cursor: pointer;
}

.gallery-lightbox__nav-btn:hover {
    background: rgba(255, 255, 255, 0.3);
}

.gallery-lightbox__counter {
    color: var(--color-text-on-dark);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* ================= MAP LIGHTBOX (полноэкранный зум/пан карты, п.8) =================
   Тот же независимый .modal-v2 паттерн, что и у .modal-v2--gallery выше —
   своё состояние и свои data-action в main.js (mapLightbox*), ничего не
   переиспользует из карусели КП/галереи. */
.modal-v2--map .modal-v2__panel {
    width: 100%;
    max-width: none;
    height: 100%;
    max-height: none;
    padding: 0;
    background: var(--color-text);
    overflow: hidden;
    border-radius: 0;
}

.map-lightbox__viewport {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    /* touch-action:none отдаёт ВСЕ жесты (пинч/пан) нашему JS — иначе
       браузер сам попытается прокрутить/зумить страницу пальцем поверх
       нашей собственной обработки жестов, конфликтуя с ней. */
    touch-action: none;
    cursor: grab;
    background: var(--color-text);
}

.map-lightbox__viewport.is-dragging {
    cursor: grabbing;
}

.map-lightbox__img {
    position: absolute;
    top: 0;
    left: 0;
    /* Позиция/масштаб полностью считает main.js (translate/scale через
       transform) — переход transform здесь только для случая programmatic
       сброса (двойной тап/клик), не для каждого кадра жеста (см.
       .map-lightbox__viewport.is-interacting ниже, которая на время
       самого жеста его выключает, чтобы не "тормозить" за пальцем). */
    transform-origin: 0 0;
    transition: transform 0.25s ease;
    max-width: none;
    margin: 0;
    border-radius: 0;
    box-shadow: none;
    cursor: inherit;
    user-select: none;
    -webkit-user-drag: none;
}

.map-lightbox__viewport.is-interacting .map-lightbox__img {
    transition: none;
}

.map-lightbox__close {
    position: absolute;
    top: var(--sp-3);
    right: var(--sp-3);
    background: rgba(0, 0, 0, 0.55);
    color: var(--color-text-on-dark);
    z-index: 2;
}

.map-lightbox__close:hover {
    background: rgba(0, 0, 0, 0.75);
    color: var(--color-text-on-dark);
}

/* ================= BADGE (статусы участника) ================= */
.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-half);
    padding: 3px var(--sp-1);
    border-radius: var(--radius-pill);
    font-size: var(--font-size-xs);
    font-weight: 700;
    white-space: nowrap;
    line-height: 1.4;
}

.badge .icon {
    width: 14px;
    height: 14px;
}

.badge--fin {
    background: var(--color-status-fin-bg);
    color: var(--color-status-fin);
}

.badge--race {
    background: var(--color-status-race-bg);
    color: var(--color-status-race);
}

.badge--dns {
    background: var(--color-status-dns-bg);
    color: var(--color-status-dns);
}

.badge--dnf {
    background: var(--color-status-dnf-bg);
    color: var(--color-status-dnf);
}

.badge--dq {
    background: var(--color-status-dq-bg);
    color: var(--color-status-dq);
}

.badge--nm {
    background: var(--color-status-nm-bg);
    color: var(--color-status-nm);
}

.badge-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

.badge-legend__item {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-half);
}

/* ================= FORM FIELD (лейбл + инпут + подсказка + инлайн-ошибка) ================= */
.form-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: var(--sp-2);
}

.form-field__label {
    font-size: var(--font-size-sm);
    font-weight: 700;
    color: var(--color-text);
}

.form-field__label .form-field__required {
    color: var(--color-danger);
    margin-inline-start: 2px;
}

.form-field__input {
    /* Раньше ширина не задавалась вовсе — <input> без width берёт свою
       "внутреннюю" ширину (браузерный default по атрибуту size, ~280px),
       а не ширину родителя. Для одиночных полей это просто выглядело чуть
       уже ожидаемого, незаметно — но для #auth-window-password, обёрнутого
       в .auth-window__password-row (которая сама честно растягивается на
       всю ширину .form-field), инпут оказывался ШИРЕ этой обёртки и вылезал
       за её правый край. Глазик (.auth-window__eye) позиционируется
       абсолютно от .auth-window__password-row, а не от инпута — из-за
       переполнения он визуально попадал в середину поля, а не к его
       настоящему правому краю (жалоба на "глазик не по центру" повторялась
       уже несколько раз, реальная причина была в этом, а не в самом
       центрировании). */
    width: 100%;
    min-height: var(--tap-min);
    padding: 0 var(--sp-2);
    border: 2px solid var(--color-border-neutral);
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--font-size-base);
    background: var(--color-surface);
    color: var(--color-text);
    box-sizing: border-box;
}

.form-field__input:focus {
    outline: none;
    border-color: var(--color-primary-700);
    box-shadow: 0 0 0 3px rgba(14, 78, 30, 0.15);
}

.form-field__hint {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

.form-field__error {
    display: none;
    align-items: center;
    gap: 4px;
    font-size: var(--font-size-xs);
    font-weight: 700;
    color: var(--color-danger);
}

.form-field--invalid .form-field__input {
    border-color: var(--color-danger);
}

.form-field--invalid .form-field__error {
    display: flex;
}

/* ================= EMPTY STATE / SKELETON LOADER ================= */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--sp-1);
    padding: var(--sp-4) var(--sp-2);
    color: var(--color-text-muted);
}

.empty-state .icon {
    width: 40px;
    height: 40px;
    opacity: 0.5;
}

.empty-state__title {
    font-size: var(--font-size-base);
    font-weight: 700;
    color: var(--color-text);
}

.empty-state__hint {
    font-size: var(--font-size-sm);
}

.skeleton {
    background: linear-gradient(90deg,
            var(--color-surface-muted) 25%,
            var(--color-surface-muted-alt) 37%,
            var(--color-surface-muted) 63%);
    background-size: 400% 100%;
    animation: skeleton-loading 1.4s ease infinite;
    border-radius: var(--radius-sm);
}

.skeleton-text {
    height: 1em;
    margin-bottom: var(--sp-1);
}

.skeleton-circle {
    border-radius: 50%;
}

@keyframes skeleton-loading {
    0% {
        background-position: 100% 50%;
    }

    100% {
        background-position: 0 50%;
    }
}

/* ================= READINESS CHECKLIST (онбординг перед стартом, п.11) ================= */
.readiness-checklist {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding: var(--sp-3);
    margin-bottom: var(--sp-3);
    border: 2px solid var(--color-primary-300);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
}

/* .absent (styles.css, display:none) и .readiness-checklist (components.css,
   display:flex) — оба однокласовых селектора одинаковой специфичности;
   components.css грузится ПОСЛЕ styles.css (см. CLAUDE.md про порядок
   каскада), поэтому при обоих классах на элементе побеждал display:flex
   и виджет оставался виден неавторизованным пользователям, хотя JS
   (renderReadinessChecklist) верно проставлял .absent. Составной селектор
   ниже специфичнее любого из них по отдельности — побеждает независимо
   от порядка подключения файлов. */
.readiness-checklist.absent {
    display: none;
}

.readiness-checklist__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
}

.readiness-checklist__title {
    font-weight: 900;
    font-size: var(--font-size-base);
    color: var(--color-primary-700);
}

.readiness-checklist__count {
    font-weight: 700;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.readiness-checklist__progress {
    height: 8px;
    border-radius: var(--radius-pill);
    background: var(--color-surface-muted);
    overflow: hidden;
}

.readiness-checklist__progress-bar {
    height: 100%;
    width: 0%;
    background: var(--color-primary-500);
    border-radius: var(--radius-pill);
    transition: width var(--motion-slow);
}

.checklist-item {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    min-height: var(--tap-min);
    padding: var(--sp-1) var(--sp-2);
    border: 2px solid var(--color-border-neutral-light);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background var(--motion-fast), border-color var(--motion-fast);
}

.checklist-item:hover {
    background: var(--color-surface-faint);
}

.checklist-item__icon {
    position: relative;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    color: var(--color-text-muted);
}

.checklist-item__icon .icon {
    position: absolute;
    inset: 0;
    width: 28px;
    height: 28px;
}

.checklist-item__icon .icon-check {
    display: none;
}

.checklist-item.is-done {
    border-color: var(--color-status-fin);
    background: var(--color-status-fin-bg);
}

.checklist-item.is-done .checklist-item__icon {
    color: var(--color-status-fin);
}

.checklist-item.is-done .icon-circle {
    display: none;
}

.checklist-item.is-done .icon-check {
    display: block;
}

.checklist-item__text {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.checklist-item__label {
    font-weight: 700;
    font-size: var(--font-size-sm);
    color: var(--color-text);
}

.checklist-item__hint {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

@media (prefers-reduced-motion: reduce) {

    .modal-v2,
    .modal-v2__panel,
    .skeleton,
    .action-btn {
        animation: none !important;
        transition: none !important;
    }
}
