/* ====================================================================
 * [preline-zone-modal] Современный дизайн модалок «Точка интереса»,
 * «Точка путеводителя» и «Прикрепить страницу live.daddy.by».
 *
 * Источник истины: эти правила перебивают устаревшие .app-modal-*
 * из /public/style.css (7499-7614) и .guide-modal-* / .btn-* из
 * /public/guides.html (96-100, 817-825), так как подключаются ПОСЛЕ
 * них. Заодно унифицируют «тяжёлые» izone-guide модалки и
 * «лёгкие» app-modal в одну дизайн-систему.
 *
 * Дизайн-токены повторяют preline-modal.css:
 *   --brand: #1274cf
 *   light:  bg #ffffff, text #0f172a, border #e5e7eb, surface #f8fafc
 *   dark:   bg #1f2937, text #f1f5f9, border #334155, surface #111827
 *
 * Палитра намеренно холоднее/чище, чем в preline-modal (там — форма
 * создания izone/guide с большим количеством полей). Здесь — лёгкие
 * action-модалки с 2–4 кнопками и опциональным селектом в стиле
 * us-button (см. user-select.js).
 * ==================================================================== */

/* ---------- Backdrop (overlay) ----------
   Современный glass-фон с blur и плавным появлением. z-index выше
   стандартного izone-modal-overlay (25000), чтобы не конфликтовать
   с другими оверлеями. */
.app-modal-overlay,
.izone-modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 25100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: saturate(140%) blur(6px);
    -webkit-backdrop-filter: saturate(140%) blur(6px);
    opacity: 0;
    animation: app-modal-fade-in 180ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

/* Тёмная тема — фон чуть темнее, чтобы модалка ярче выделялась
   на фоне тёмной страницы. */
.dark-theme .app-modal-overlay,
.dark-theme .izone-modal-overlay {
    background: rgba(2, 6, 23, 0.72);
}

@keyframes app-modal-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ---------- Скрытие через .hidden ----------
   Класс .hidden из style.css (display: none) имеет ту же
   специфичность (0,1,0), что и .app-modal-overlay (display: flex).
   Поскольку preline-zone-modal.css подключается после style.css,
   display: flex из .app-modal-overlay побеждает display: none из .hidden.
   Решение: правило с бо́льшей специфичностью (0,2,0) для комбинации
   .app-modal-overlay.hidden / .izone-modal-overlay.hidden. */
 .app-modal-overlay.hidden,
 .izone-modal-overlay.hidden {
     display: none !important;
     animation: none;
 }

/* Модалки с явным атрибутом hidden не должны участвовать в layout до открытия. */
.app-modal-overlay[hidden],
.izone-modal-overlay[hidden] {
    display: none !important;
}


@keyframes app-modal-pop-in {
    from { opacity: 0; transform: translateY(8px) scale(0.985); }
    to   { opacity: 1; transform: translateY(0)    scale(1); }
}

/* ---------- Корневой контейнер модалки ----------
   Современный «card» с rounded-2xl, мягкой тенью и тонкой границей.
   max-width расширен с 360px → 480px, чтобы вместить 5 кнопок в ряд
   на мобильных (иначе они переносятся и ломают визуальный ритм). */
.app-modal,
.guide-modal {
    position: relative;
    background: #ffffff;
    color: #0f172a;
    width: 100%;
    max-width: 480px;
    border: 1px solid #e5e7eb;
    border-radius: 16px;
    box-shadow:
        0 24px 48px -16px rgba(15, 23, 42, 0.22),
        0 0 0 1px rgba(15, 23, 42, 0.04);
    font-family: inherit;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    /* Ограничиваем высоту по вьюпорту с учётом safe-area, чтобы
       модалка всегда помещалась на мобильных. */
    max-height: calc(100dvh - 32px);
    max-height: calc(100dvh - 32px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
    opacity: 0;
    transform: translateY(8px) scale(0.985);
    animation: app-modal-pop-in 220ms cubic-bezier(0.22, 0.61, 0.36, 1) 40ms forwards;
}

/* ---------- Тёмная тема (единый источник: .dark-theme на <html>) ---------- */
.dark-theme .app-modal,
.dark-theme .guide-modal {
    background: #1f2937;
    color: #f1f5f9;
    border-color: #334155;
    box-shadow:
        0 24px 48px -16px rgba(0, 0, 0, 0.7),
        0 0 0 1px rgba(255, 255, 255, 0.05);
}

/* ---------- Шапка модалки ----------
   Структура: <.app-modal-header>
                  <.app-modal-header-icon><i/></.app-modal-header-icon>
                  <.app-modal-header-text>
                      <h3>...</h3>
                      <.app-modal-subtitle>...</.app-modal-subtitle>
                  </.app-modal-header-text>
                  <.app-modal-close>×</.app-modal-close>  (опц.)
              </.app-modal-header>
   Используется только в новых модалках, старые (confirm/prompt/
   statistics) остаются без header'а — там диалог компактнее. */
.app-modal-header {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 20px 14px;
    background: inherit;
    border-bottom: 1px solid #f1f5f9;
    flex: 0 0 auto;
}
.dark-theme .app-modal-header {
    border-bottom-color: #334155;
}

.app-modal-header-icon {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 11px;
    background: linear-gradient(135deg, #1274cf 0%, #1d8fee 100%);
    color: #ffffff;
    font-size: 16px;
    box-shadow: 0 6px 14px -6px rgba(18, 116, 207, 0.55);
}
.dark-theme .app-modal-header-icon {
    background: linear-gradient(135deg, #1d8fee 0%, #38bdf8 100%);
    box-shadow: 0 6px 14px -6px rgba(29, 143, 238, 0.65);
}

/* Вариант «опасная» модалка (delete confirm и т.п.) */
.app-modal-header-icon--danger {
    background: linear-gradient(135deg, #dc2626 0%, #ef4444 100%);
    box-shadow: 0 6px 14px -6px rgba(220, 38, 38, 0.55);
}
.dark-theme .app-modal-header-icon--danger {
    background: linear-gradient(135deg, #ef4444 0%, #f87171 100%);
    box-shadow: 0 6px 14px -6px rgba(239, 68, 68, 0.65);
}

/* Вариант «нейтральная» — для информационных модалок */
.app-modal-header-icon--neutral {
    background: linear-gradient(135deg, #475569 0%, #64748b 100%);
    box-shadow: 0 6px 14px -6px rgba(71, 85, 105, 0.45);
}

.app-modal-header-text {
    flex: 1 1 auto;
    min-width: 0;
}

.app-modal-header-text h3 {
    margin: 0;
    padding: 0;
    font-size: 17px;
    line-height: 1.25;
    font-weight: 600;
    color: inherit;
    letter-spacing: -0.01em;
    /* Старая структура (один h3 без обёртки) должна выглядеть так же */
    font-family: inherit;
}

.app-modal-header-text h3 i {
    margin-right: 6px;
    opacity: 0.85;
}

.app-modal-subtitle {
    margin: 2px 0 0 0;
    font-size: 12.5px;
    color: #64748b;
    line-height: 1.35;
}
.dark-theme .app-modal-subtitle {
    color: #94a3b8;
}

/* Кнопка-крестик в шапке (если нужна). */
.app-modal-close,
.guide-modal-close {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    min-width: 32px;
    min-height: 32px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 9px;
    background: transparent;
    color: #64748b;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    transition: background-color 160ms ease, color 160ms ease;
}
.app-modal-close:hover,
.app-modal-close:focus-visible,
.guide-modal-close:hover,
.guide-modal-close:focus-visible {
    background: #f1f5f9;
    color: #0f172a;
    outline: none;
}
.app-modal-close:focus-visible,
.guide-modal-close:focus-visible {
    box-shadow: 0 0 0 3px rgba(18, 116, 207, 0.25);
}
.dark-theme .app-modal-close,
.dark-theme .guide-modal-close {
    color: #94a3b8;
}
.dark-theme .app-modal-close:hover,
.dark-theme .app-modal-close:focus-visible,
.dark-theme .guide-modal-close:hover,
.dark-theme .guide-modal-close:focus-visible {
    background: rgba(255, 255, 255, 0.08);
    color: #f1f5f9;
}
.dark-theme .app-modal-close:focus-visible,
.dark-theme .guide-modal-close:focus-visible {
    box-shadow: 0 0 0 3px rgba(56, 189, 248, 0.3);
}

/* ---------- Тело модалки ----------
   Для старых модалок без явного .app-modal-body — растягиваем
   контентную часть. Для новых — фиксированный padding 20px. */
.app-modal-body,
.guide-modal-body {
    padding: 18px 20px;
    overflow-y: auto;
    /* Скроллбар — нативный, чтобы не было визуального шума */
    scrollbar-width: thin;
    scrollbar-color: rgba(15, 23, 42, 0.18) transparent;
    flex: 1 1 auto;
    min-height: 0;
}
.app-modal-body::-webkit-scrollbar,
.guide-modal-body::-webkit-scrollbar {
    width: 8px;
}
.app-modal-body::-webkit-scrollbar-thumb,
.guide-modal-body::-webkit-scrollbar-thumb {
    background: rgba(15, 23, 42, 0.18);
    border-radius: 4px;
}
.dark-theme .app-modal-body::-webkit-scrollbar-thumb,
.dark-theme .guide-modal-body::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.22);
}

/* ---------- Подсказка / описание ----------
   Сохраняем семантический класс .app-modal-hint и .guide-modal-hint
   (он используется в JS), но делаем компактнее и в две строки
   (multiline) для длинных описаний. */
.app-modal-hint,
.guide-modal-hint {
    margin: 0 0 14px;
    font-size: 13px;
    line-height: 1.5;
    color: #64748b;
}
.app-modal-hint:last-child,
.guide-modal-hint:last-child {
    margin-bottom: 0;
}
.dark-theme .app-modal-hint,
.dark-theme .guide-modal-hint {
    color: #94a3b8;
}

/* Модификатор: опасная подсказка (для delete-флоу). */
.app-modal-hint--danger {
    color: #b91c1c;
    background: rgba(220, 38, 38, 0.06);
    border: 1px solid rgba(220, 38, 38, 0.18);
    border-radius: 10px;
    padding: 10px 12px;
}
.dark-theme .app-modal-hint--danger {
    color: #fca5a5;
    background: rgba(239, 68, 68, 0.08);
    border-color: rgba(239, 68, 68, 0.22);
}

/* Inline-ссылка внутри подсказки: «+ создать новую страницу»
   в модалке прикрепления live.daddy.by страницы. Без подчёркивания
   по умолчанию, чтобы не «кричала», но при этом явно кликабельна
   на hover/focus. inline-block + margin-top даёт визуальный
   зазор, если <br> по какой-то причине не отработал. */
.app-modal-hint-link {
    display: inline-block;
    margin-top: 6px;
    color: #1274cf;
    text-decoration: none;
    font-weight: 500;
    border-radius: 4px;
    transition: color 140ms ease, background 140ms ease;
}
.app-modal-hint-link:hover,
.app-modal-hint-link:focus-visible {
    color: #0f5da3;
    text-decoration: underline;
    outline: none;
}
.app-modal-hint-link:focus-visible {
    box-shadow: 0 0 0 3px rgba(18, 116, 207, 0.25);
}
.dark-theme .app-modal-hint-link {
    color: #38bdf8;
}
.dark-theme .app-modal-hint-link:hover,
.dark-theme .app-modal-hint-link:focus-visible {
    color: #7dd3fc;
}

/* ---------- Список действий (кнопки) ----------
   В новых модалках кнопки лежат в .app-modal-footer (sticky внутри
   flex-модалки), но для обратной совместимости .app-modal-actions
   тоже работает как footer-секция. */
.app-modal-actions,
.guide-modal-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: flex-end;
    padding: 14px 20px 18px;
    background: inherit;
    border-top: 1px solid #f1f5f9;
    flex: 0 0 auto;
}
.dark-theme .app-modal-actions,
.dark-theme .guide-modal-actions {
    border-top-color: #334155;
}

/* Если .app-modal-actions идёт без header'а (старые confirm'ы),
   убираем верхнюю границу — она там визуально лишняя. */
.app-modal:not(.app-modal--has-header) > .app-modal-actions {
    border-top: 0;
    padding-top: 4px;
}

/* ---------- Кнопки ----------
   Семантика остаётся обратно-совместимой: .app-modal-btn +
   .app-modal-btn-ok / -cancel / -danger. Внешний вид переработан
   в стиле preline: filled-primary / soft-secondary / filled-danger.
   Текст — 14px, иконка + label, минимум 40px высоты для touch.

   Лейаут: иконка (если есть) — слева, текст — по центру всей кнопки.
   Реализовано через `position: relative` + абсолютно
   спозиционированную .app-modal-btn-icon-wrap и text-align: center
   для текстового узла. Кнопка без иконки получает обычный
   padding (класс .app-modal-btn--has-icon выставляет JS). */
.app-modal-btn,
.guide-modal-actions .btn {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin: 0;                 /* сброс глобального `input, select, button { margin: 10px 0 }` */
    padding: 9px 16px;         /* по умолчанию — для кнопок БЕЗ иконки */
    min-height: 40px;
    border: 1px solid transparent;
    border-radius: 10px;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.2;
    letter-spacing: -0.005em;
    text-align: center;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition:
        background-color 160ms ease,
        color 160ms ease,
        border-color 160ms ease,
        box-shadow 160ms ease,
        transform 80ms ease;
}
/* Если у кнопки есть иконка — резервируем 38px слева под неё
   (22px кружок + 16px отступ от левого края кнопки) и переносим
   иконку в абсолют. Текстовый узел центрируется через
   text-align: center и justify-content: center, иконка не
   участвует в flex-потоке и прижата к левому краю. */
.app-modal-btn--has-icon {
    padding-left: 38px;
    text-align: center;
}
.app-modal-btn--has-icon .app-modal-btn-icon-wrap {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    margin: 0;
}
/* Фолбэк для старых WebView без поддержки :has() — если кнопка
   содержит .app-modal-btn-icon-wrap напрямую, ведём себя так же.
   Класс .app-modal-btn--has-icon приоритетнее, но если JS его
   забыл поставить, :has() спасёт layout. */
@supports selector(:has(*)) {
    .app-modal-btn:not(.app-modal-btn--has-icon):has(.app-modal-btn-icon-wrap) {
        padding-left: 38px;
    }
    .app-modal-btn:not(.app-modal-btn--has-icon):has(.app-modal-btn-icon-wrap)
        .app-modal-btn-icon-wrap {
        position: absolute;
        left: 10px;
        top: 50%;
        transform: translateY(-50%);
        margin: 0;
    }
}
.app-modal-btn:active,
.guide-modal-actions .btn:active {
    transform: scale(0.98);
}
.app-modal-btn:focus-visible,
.guide-modal-actions .btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px rgba(18, 116, 207, 0.28);
}
.app-modal-btn i,
.app-modal-btn svg,
.guide-modal-actions .btn i,
.guide-modal-actions .btn svg {
    flex: 0 0 auto;
    font-size: 14px;
    line-height: 1;
}
.app-modal-btn[disabled],
.guide-modal-actions .btn[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* Primary (filled, accent) */
.app-modal-btn-ok,
.app-modal-btn--primary {
    background: linear-gradient(180deg, #1d8fee 0%, #1274cf 100%);
    color: #ffffff;
    border-color: #1274cf;
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.08),
        0 6px 14px -8px rgba(18, 116, 207, 0.55);
}
.app-modal-btn-ok:hover,
.app-modal-btn--primary:hover {
    background: linear-gradient(180deg, #2c9bf3 0%, #1380d6 100%);
    border-color: #1380d6;
}
.app-modal-btn-ok:focus-visible,
.app-modal-btn--primary:focus-visible {
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.08),
        0 0 0 3px rgba(18, 116, 207, 0.28);
}

/* Secondary (soft) */
.app-modal-btn-cancel,
.app-modal-btn--secondary {
    background: #f1f5f9;
    color: #0f172a;
    border-color: #e2e8f0;
}
.app-modal-btn-cancel:hover,
.app-modal-btn--secondary:hover {
    background: #e2e8f0;
    color: #0f172a;
    border-color: #cbd5e1;
}

/* Danger (filled, red) */
.app-modal-btn-danger,
.app-modal-btn--danger {
    background: linear-gradient(180deg, #ef4444 0%, #dc2626 100%);
    color: #ffffff;
    border-color: #dc2626;
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.08),
        0 6px 14px -8px rgba(220, 38, 38, 0.55);
}
.app-modal-btn-danger:hover,
.app-modal-btn--danger:hover {
    background: linear-gradient(180deg, #f87171 0%, #e03030 100%);
    border-color: #e03030;
}

/* Soft-danger — для подтверждения удаления в одну кнопку */
.app-modal-btn--soft-danger {
    background: rgba(220, 38, 38, 0.08);
    color: #b91c1c;
    border-color: rgba(220, 38, 38, 0.22);
}
.app-modal-btn--soft-danger:hover {
    background: rgba(220, 38, 38, 0.14);
    color: #991b1b;
    border-color: rgba(220, 38, 38, 0.34);
}

/* Тёмная тема для кнопок */
.dark-theme .app-modal-btn-cancel,
.dark-theme .app-modal-btn--secondary {
    background: rgba(255, 255, 255, 0.05);
    color: #e2e8f0;
    border-color: #334155;
}
.dark-theme .app-modal-btn-cancel:hover,
.dark-theme .app-modal-btn--secondary:hover {
    background: rgba(255, 255, 255, 0.1);
    color: #f8fafc;
    border-color: #475569;
}
.dark-theme .app-modal-btn-ok,
.dark-theme .app-modal-btn--primary {
    background: linear-gradient(180deg, #28a3f3 0%, #1274cf 100%);
    border-color: #1274cf;
}
.dark-theme .app-modal-btn-ok:hover,
.dark-theme .app-modal-btn--primary:hover {
    background: linear-gradient(180deg, #3daef5 0%, #1481d6 100%);
}
.dark-theme .app-modal-btn-danger,
.dark-theme .app-modal-btn--danger {
    background: linear-gradient(180deg, #ef4444 0%, #dc2626 100%);
    border-color: #dc2626;
}
.dark-theme .app-modal-btn--soft-danger {
    background: rgba(239, 68, 68, 0.1);
    color: #fca5a5;
    border-color: rgba(239, 68, 68, 0.28);
}
.dark-theme .app-modal-btn--soft-danger:hover {
    background: rgba(239, 68, 68, 0.18);
    color: #fecaca;
    border-color: rgba(239, 68, 68, 0.42);
}
.dark-theme .app-modal-btn:focus-visible,
.dark-theme .guide-modal-actions .btn:focus-visible {
    box-shadow: 0 0 0 3px rgba(56, 189, 248, 0.3);
}

/* Кнопка-«полная ширина» (для одиночных CTA в футере). */
.app-modal-btn--block {
    width: 100%;
}

/* Иконка слева от текста внутри кнопки — в брендовом кружочке
   (как в .izone-preline-modal-header-icon, но меньше).
   Позиционируется абсолютно в .app-modal-btn--has-icon (см. выше)
   и прижата к левому краю кнопки. Текст при этом центрирован
   в оставшемся пространстве через text-align: center. */
.app-modal-btn-icon-wrap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.15);
    color: inherit;
    font-size: 12px;
    flex: 0 0 auto;
    line-height: 1;
}
.app-modal-btn-icon-wrap > i,
.app-modal-btn-icon-wrap > svg {
    font-size: 12px;
    line-height: 1;
}
.app-modal-btn-cancel .app-modal-btn-icon-wrap,
.app-modal-btn--secondary .app-modal-btn-icon-wrap {
    background: rgba(15, 23, 42, 0.06);
    color: inherit;
}
.dark-theme .app-modal-btn-cancel .app-modal-btn-icon-wrap,
.dark-theme .app-modal-btn--secondary .app-modal-btn-icon-wrap {
    background: rgba(255, 255, 255, 0.08);
}

/* ---------- Селект в стиле us-button ----------
   Кастомный dropdown для выбора live.daddy.by страницы.
   Стилистически повторяет .us-button из user-select.js, но с
   вариантом "disabled placeholder" и опциональной иконкой слева.
   Триггер открывает .app-modal-select-list (popover). */
.app-modal-select-label {
    display: block;
    font-size: 12.5px;
    font-weight: 600;
    color: #475569;
    margin: 0 0 6px 0;
    letter-spacing: 0.01em;
}
.dark-theme .app-modal-select-label {
    color: #cbd5e1;
}

.app-modal-select {
    width: 100%;
    margin: 0;
    /* Контейнер для popover-списка (.app-modal-select-list
       использует position: fixed + JS-координаты, но мы держим
       position: relative на случай фоллбэка и для
       правильной работы CSS-контекста). */
    position: relative;
}

.app-modal-select-trigger {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    background: #ffffff;
    border: 1px solid #cbd5e1;
    border-radius: 12px;
    cursor: pointer;
    text-align: left;
    font: inherit;
    font-size: 15px;
    font-weight: 500;
    color: #0f172a;
    min-height: 48px;
    transition:
        border-color 160ms ease,
        box-shadow 200ms ease,
        background 160ms ease;
    -webkit-appearance: none;
    appearance: none;
}
.app-modal-select-trigger:hover {
    border-color: #94a3b8;
}
.app-modal-select-trigger:focus-visible,
.app-modal-select-trigger.app-modal-select-trigger--open {
    outline: none;
    border-color: #1274cf;
    box-shadow: 0 0 0 4px rgba(18, 116, 207, 0.18);
}

.app-modal-select-trigger-inner {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 12px;
    overflow: hidden;
}

.app-modal-select-trigger-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    overflow: hidden;
}

.app-modal-select-trigger-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Вторая строка в trigger — slug страницы, когда у неё задан
   settings.password_seo_title. Делаем её мелкой и приглушённой,
   чтобы название страницы оставалось главным. */
.app-modal-select-trigger-sub {
    flex: 0 0 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12px;
    font-weight: 400;
    color: #64748b;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco,
        Consolas, "Liberation Mono", "Courier New", monospace;
}
.app-modal-select-trigger--placeholder .app-modal-select-trigger-sub {
    display: none;
}

.app-modal-select-trigger--placeholder {
    color: #94a3b8;
    font-weight: 400;
}

.app-modal-select-caret {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    color: #64748b;
    transition: transform 220ms ease, background 160ms ease, color 160ms ease;
}
.app-modal-select-trigger:hover .app-modal-select-caret,
.app-modal-select-trigger--open .app-modal-select-caret {
    color: #1274cf;
    background: rgba(18, 116, 207, 0.08);
}
.app-modal-select-trigger--open .app-modal-select-caret {
    transform: rotate(180deg);
}

/* Popover-список.
   Делаем floating popover через position: fixed + JS-координаты,
   чтобы список перекрывал кнопки модалки и не обрезался её
   overflow:hidden / flex-контейнером. Без этого модалка при
   открытии выглядит «съеденной» — пункты уходят за нижние
   блоки и видны только пока пользователь не доскроллит. */
.app-modal-select-list {
    box-sizing: border-box;
    margin: 0;
    list-style: none;
    background: #ffffff;
    border: 1px solid #e2e8f0;
    border-radius: 12px;
    box-shadow:
        0 1px 2px rgba(15, 23, 42, 0.06),
        0 12px 32px -12px rgba(15, 23, 42, 0.2);
    /* Сжимаем по высоте в зависимости от доступного места
       снизу или сверху от триггера. JS выставляет
       top/left/width/max-height через inline-стили. */
    max-height: 260px;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
    padding: 4px;
    scrollbar-width: thin;
    scrollbar-color: rgba(15, 23, 42, 0.2) transparent;
    z-index: 10;
}
.app-modal-select-list[data-popover="1"] {
    /* Когда JS переключил список в floating-режим, он временно
       переносится в body. Уровень должен быть выше overlay (25100). */
    position: fixed;
    z-index: 25200;
    /* На случай, если JS ещё не успел посчитать координаты,
       скрываем визуально, но оставляем элемент в DOM. */
    visibility: hidden;
    left: 0;
    top: 0;
}
.app-modal-select-list[data-popover="1"][data-ready="1"] {
    visibility: visible;
}
.app-modal-select-list::-webkit-scrollbar { width: 8px; }
.app-modal-select-list::-webkit-scrollbar-thumb {
    background: rgba(15, 23, 42, 0.2);
    border-radius: 4px;
}

/* Сброс глобального правила `input, select, button { margin: 10px 0 }`
   из style.css: иначе триггер и пункты селекта получают лишние
   отступы 10px сверху/снизу (видно в DevTools и в UI). */
.app-modal-select-trigger,
.app-modal-select-item {
    margin: 0;
}

.app-modal-select-item {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 10px 12px;
    border: 0;
    background: transparent;
    color: #0f172a;
    font: inherit;
    font-size: 14.5px;
    text-align: left;
    border-radius: 9px;
    cursor: pointer;
    transition: background 140ms ease, color 140ms ease;
}
.app-modal-select-item:hover,
.app-modal-select-item:focus-visible {
    background: #f1f5f9;
    outline: none;
}
.app-modal-select-item--active {
    background: rgba(18, 116, 207, 0.1);
    color: #1274cf;
    font-weight: 500;
}
.app-modal-select-item-icon {
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    background: rgba(18, 116, 207, 0.1);
    color: #1274cf;
    font-size: 12px;
}
.app-modal-select-item-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    overflow: hidden;
}
.app-modal-select-item-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Вторая строка под названием — slug страницы (только когда у
   страницы задан settings.password_seo_title). Мелкий моноширинный
   шрифт и приглушённый цвет, чтобы название оставалось главным. */
.app-modal-select-item-sub {
    flex: 0 0 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11.5px;
    font-weight: 400;
    color: #64748b;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco,
        Consolas, "Liberation Mono", "Courier New", monospace;
}

/* Тёмная тема для селекта. */
.dark-theme .app-modal-select-trigger {
    background: #0f172a;
    border-color: #334155;
    color: #f1f5f9;
}
.dark-theme .app-modal-select-trigger:hover {
    border-color: #475569;
}
.dark-theme .app-modal-select-trigger:focus-visible,
.dark-theme .app-modal-select-trigger.app-modal-select-trigger--open {
    border-color: #38bdf8;
    box-shadow: 0 0 0 4px rgba(56, 189, 248, 0.22);
}
.dark-theme .app-modal-select-trigger--placeholder {
    color: #64748b;
}
.dark-theme .app-modal-select-caret {
    color: #94a3b8;
}
.dark-theme .app-modal-select-trigger:hover .app-modal-select-caret,
.dark-theme .app-modal-select-trigger--open .app-modal-select-caret {
    color: #38bdf8;
    background: rgba(56, 189, 248, 0.14);
}

.dark-theme .app-modal-select-list {
    background: #111827;
    border-color: #334155;
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.4),
        0 12px 32px -12px rgba(0, 0, 0, 0.6);
}
.dark-theme .app-modal-select-item {
    color: #e2e8f0;
}
.dark-theme .app-modal-select-item:hover,
.dark-theme .app-modal-select-item:focus-visible {
    background: rgba(255, 255, 255, 0.06);
}
.dark-theme .app-modal-select-item--active {
    background: rgba(56, 189, 248, 0.16);
    color: #38bdf8;
}
.dark-theme .app-modal-select-item-icon {
    background: rgba(56, 189, 248, 0.16);
    color: #38bdf8;
}
.dark-theme .app-modal-select-item-sub,
.dark-theme .app-modal-select-trigger-sub {
    color: #94a3b8;
}

/* ---------- Адаптив ----------
   На очень узких экранах (<420px) переводим кнопки в столбец и
   делаем их во всю ширину — так удобнее нажимать пальцем. */
@media (max-width: 420px) {
    .app-modal,
    .guide-modal {
        max-width: 100%;
        border-radius: 14px;
    }
    .app-modal-actions,
    .guide-modal-actions {
        flex-direction: column-reverse;
        align-items: stretch;
    }
    .app-modal-btn,
    .guide-modal-actions .btn {
        width: 100%;
        justify-content: center;
    }
}

/* Старые динамические confirm/prompt-окна используют .app-modal без
   `.app-modal--has-header`. Для них применяем тот же sticky-контракт. */
.app-modal:not(.app-modal--has-header) {
    display: block;
    padding: 0;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
}
.app-modal:not(.app-modal--has-header) > h3 {
    position: sticky;
    top: 0;
    z-index: 3;
    display: flex;
    align-items: center;
    min-height: 64px;
    box-sizing: border-box;
    margin: 0;
    padding: 16px 20px;
    background: #ffffff;
    border-bottom: 1px solid #f1f5f9;
}
.app-modal:not(.app-modal--has-header) > .app-modal-hint,
.app-modal:not(.app-modal--has-header) > .app-modal-input {
    margin-left: 20px;
    margin-right: 20px;
}
.app-modal:not(.app-modal--has-header) > .app-modal-actions {
    position: sticky;
    bottom: 0;
    z-index: 3;
    margin-top: 0;
    background: #ffffff;
    box-shadow: 0 -8px 18px -16px rgba(15, 23, 42, 0.35);
}
.dark-theme .app-modal:not(.app-modal--has-header) > h3,
.dark-theme .app-modal:not(.app-modal--has-header) > .app-modal-actions {
    background: #1f2937;
    border-color: #334155;
}

/* ====================================================================
 * Совместимость со старыми .modal-модалками miniapp.
 *
 * В miniapp исторически осталось много окон со структурой
 * `.modal-content > .modal-close + h3 + content + .modal-actions`.
 * Переписывать их разметку по одному опасно: JS открывает их по ID и
 * обновляет содержимое напрямую. Поэтому здесь тот же визуальный
 * контракт достигается без изменения DOM:
 *   - карточка ограничена viewport и не выходит за safe-area;
 *   - h3 и кнопка закрытия работают как закреплённая шапка;
 *   - .modal-actions закреплён внизу как footer;
 *   - промежуточное содержимое прокручивается внутри карточки.
 * Новые `.app-modal` и тяжёлые map/fullscreen-компоненты не затрагиваются.
 * ==================================================================== */
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content):not(.modal-content-exploration-map):not(.modal-content-map-fullscreen):not(.modal-content-heatmap-fullscreen):not(.modal-content-fullscreen-map) {
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    padding: 0;
    max-height: calc(100dvh - 32px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
    /* Скролл НЕ переносим на саму карточку, чтобы длинное тело
       не «уезжало» под sticky-шапку/подвал: прокрутка делается
       внутренним контейнером .modal-body (или виртуальной обёрткой
       см. ниже). Поэтому карточка сохраняет overflow: hidden, но
       при отсутствии .modal-body scroll открывается через правило
       ниже — для случая «плоской» разметки со множеством детей. */
    overflow-x: hidden;
    overflow-y: hidden;
}

/* Контейнер для всего тела модалки между шапкой и подвалом.
   Все «средние» элементы карточки получают flex: 1 1 auto +
   min-height: 0 + overflow-y: auto, чтобы корректно занимать
   свободное место между фиксированной шапкой (h3) и фиксированным
   подвалом (.modal-actions) внутри flex-column карточки. Это
   покрывает и .modal-body, и любые одиночные контейнеры вроде
   .timeline-detail-modal-body, .modal-filter, .modal-time и т.п. */
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content):not(.modal-content-exploration-map):not(.modal-content-map-fullscreen):not(.modal-content-heatmap-fullscreen):not(.modal-content-fullscreen-map) > .modal-body,
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content):not(.modal-content-exploration-map):not(.modal-content-map-fullscreen):not(.modal-content-heatmap-fullscreen):not(.modal-content-fullscreen-map) > .timeline-detail-modal-body,
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content):not(.modal-content-exploration-map):not(.modal-content-map-fullscreen):not(.modal-content-heatmap-fullscreen):not(.modal-content-fullscreen-map) > [class*="-modal-body"],
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content):not(.modal-content-exploration-map):not(.modal-content-map-fullscreen):not(.modal-content-heatmap-fullscreen):not(.modal-content-fullscreen-map) > [id$="List"]:not(.exploration-map-inner) {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: rgba(15, 23, 42, 0.2) transparent;
    padding: 18px 20px;
    box-sizing: border-box;
}


.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > h3 {
    flex: 0 0 auto;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    min-height: 64px;
    margin: 0;
    padding: 16px 58px 16px 20px;
    background: #ffffff;
    border-bottom: 1px solid #f1f5f9;
}

/* Виртуальный скролл-контейнер для модалок без .modal-body:
   берём ВСЕХ прямых детей карточки кроме шапки, крестика и
   footer, оборачиваем через CSS контейнером, который занимает
   всё свободное место и скроллится. */
@supports selector(:has(*)) {
    .modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content):not(.modal-content-exploration-map):not(.modal-content-map-fullscreen):not(.modal-content-heatmap-fullscreen):not(.modal-content-fullscreen-map):not(:has(> .modal-body)) {
        /* Контейнер-обёртка создаётся через JS-фоллбэк; здесь стили
           применяются только если :has показывает, что .modal-body
           отсутствует. Основная логика ниже — перебиваем то же
           правило с padding 20px для прямых детей шапки */
    }
}

/* Если .modal-body отсутствует — каждый «средний» ребёнок
   получает горизонтальные отступы, и обёртка-скролл создаётся
   через display: contents не получится; вместо этого используем
   псевдо-обёртку: добавляем прямому набору детей стили, а сам
   scroll идёт по самой карточке. */
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content):not(.modal-content-exploration-map):not(.modal-content-map-fullscreen):not(.modal-content-heatmap-fullscreen):not(.modal-content-fullscreen-map) {
    /* Включаем скролл самой карточки ТОЛЬКО при отсутствии modal-body
       и не слишком коротком содержимом: max-height ограничен
       вьюпортом, поэтому при длинном контенте появится scroll.
       Однако шапка и footer должны быть sticky. Реализуем sticky
       через отдельные position:sticky элементы, поскольку сама
       карточка — scroll-контейнер. */
}

.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > .modal-close {
    position: absolute;
    top: 14px;
    right: 14px;
    z-index: 5;
    margin: 0;
}

.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > .modal-actions {
    flex: 0 0 auto;
    box-sizing: border-box;
    margin: 0;
    padding: 14px 20px 18px;
    background: #ffffff;
    border-top: 1px solid #f1f5f9;
    box-shadow: 0 -8px 18px -16px rgba(15, 23, 42, 0.35);
}

/* Обёртка-средняя часть (для модалок, в которых JS вставил
   дочерние элементы без явного .modal-body). Чтобы контент
   скроллился, ограничиваем его максимальную высоту по
   формуле: max-height карточки минус шапка минус footer.
   Считаем шапку 64px и footer-запас 88px, остаток — тело. */


/* Окна без явного h3 всё равно получают ту же карточку и footer. */
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > .modal-text,
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > p:not(.modal-actions),
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > .modal-form-row,
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > .modal-filter,
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > .modal-time,
.modal > .modal-content:not(:has(> .modal-content-fullscreen-map)):not(.custom-select-modal-content) > input[type]:not([class*="native-select-hidden"]),
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > select:not([class*="native-select-hidden"]),
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > [id$="List"]:not(.exploration-map-inner),
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > [class*="-modal-body"],
.modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > [class*="-modal-meta"] {
    margin-left: 20px;
    margin-right: 20px;
    box-sizing: border-box;
}

.dark-theme .modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > h3,
.dark-theme .modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > .modal-actions {
    background: #1f2937;
    border-color: #334155;
}

@media (max-width: 420px) {
    .modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) {
        max-width: 100%;
        border-radius: 14px;
    }
    .modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > .modal-actions {
        flex-direction: column-reverse;
        align-items: stretch;
    }
    .modal > .modal-content:not(.izone-preline-modal):not(.custom-select-modal-content) > .modal-actions .modal-btn {
        width: 100%;
    }
}

/* ============================================================
   Geoguide QR Code modal (public/geoguide.html#geoguideQrModal).
   Использует ту же дизайн-систему app-modal--has-header, что и
   share/delete модалки, но с центрированным QR-блоком и
   специальной типографикой (моноширинная ссылка под QR).
   ============================================================ */
.geoguide-qr-modal {
    max-width: 380px;
    text-align: center;
}

.geoguide-qr-modal-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: 18px 20px 6px;
}

.geoguide-qr-loading {
    margin: 28px 0 12px;
    font-size: 13px;
    line-height: 1.4;
    color: var(--text-muted, #64748b);
    opacity: 0.85;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

/* [bugfix] Атрибут `hidden` устанавливает display:none через
   user-agent stylesheet, но наше правило выше с display:inline-flex
   его перебивает по специфичности. Это даёт баг — спиннер
   «Генерируем QR-код…» остаётся видимым, когда QR уже готов.
   Явно скрываем элемент через атрибутный селектор. */
.geoguide-qr-loading[hidden],
.geoguide-qr-error[hidden],
.geoguide-qr-canvas-wrap[hidden] {
    display: none !important;
}

.geoguide-qr-loading::before {
    content: '';
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid rgba(100, 116, 139, 0.25);
    border-top-color: #1274cf;
    animation: geoguide-qr-spin 0.8s linear infinite;
}

@keyframes geoguide-qr-spin {
    to { transform: rotate(360deg); }
}

.geoguide-qr-error {
    margin: 24px 0 8px;
    padding: 10px 12px;
    font-size: 13px;
    line-height: 1.4;
    border-radius: 8px;
    background: rgba(220, 38, 38, 0.08);
    color: inherit;
    border: 1px solid rgba(220, 38, 38, 0.18);
}

.geoguide-qr-canvas-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    width: 100%;
}

.geoguide-qr-telegram-pill {
    /* [fix/geoguide-qr-open-in-telegram] Информационная пилюля
       "Камера телефона откроет именно в Telegram" — нужна, чтобы
       пользователь явно видел, что QR ведёт не на обычную web-страницу,
       а транзитом через /public/geoguide-open.html в Telegram-клиент. */
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 8px 12px;
    margin: 0 0 4px;
    width: 100%;
    box-sizing: border-box;
    border-radius: 10px;
    background: rgba(34, 158, 217, 0.10);
    border: 1px solid rgba(34, 158, 217, 0.22);
    color: inherit;
    font-size: 12px;
    line-height: 1.45;
    text-align: left;
}
.geoguide-qr-telegram-pill i {
    color: #229ed9;
    font-size: 14px;
    line-height: 1.3;
    margin-top: 1px;
    flex-shrink: 0;
}
.geoguide-qr-telegram-pill span {
    flex: 1;
    min-width: 0;
}

.dark-theme .geoguide-qr-telegram-pill {
    background: rgba(34, 158, 217, 0.16);
    border-color: rgba(34, 158, 217, 0.30);
}
.dark-theme .geoguide-qr-telegram-pill i {
    color: #2aabee;
}

.geoguide-qr-canvas {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 12px;
    border-radius: 14px;
    background: #ffffff;
    box-shadow:
        0 0 0 1px rgba(15, 23, 42, 0.06),
        0 8px 24px -10px rgba(15, 23, 42, 0.18);
    /* qrcodejs рисует <canvas>/<img> внутрь — наследуем max-width. */
    max-width: 100%;
}

.geoguide-qr-canvas canvas,
.geoguide-qr-canvas img,
.geoguide-qr-fallback-img {
    display: block;
    width: 240px;
    height: 240px;
    max-width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
}

.geoguide-qr-scan-hint {
    margin: 4px 0 0;
    font-size: 12px;
    line-height: 1.45;
    color: var(--text-muted, #64748b);
    opacity: 0.92;
    max-width: 320px;
}

.dark-theme .geoguide-qr-loading {
    color: #94a3b8;
}

.dark-theme .geoguide-qr-error {
    background: rgba(239, 68, 68, 0.12);
    border-color: rgba(239, 68, 68, 0.28);
}

.dark-theme .geoguide-qr-canvas {
    background: #ffffff;
    /* QR остаётся белым для контраста в тёмной теме — это стандарт
       для сканеров камер телефона. */
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.08),
        0 8px 24px -10px rgba(0, 0, 0, 0.5);
}

.dark-theme .geoguide-qr-scan-hint {
    color: #94a3b8;
}

/* На узких экранах — кнопки в actions выстраиваются вертикально,
   чтобы не было горизонтальной прокрутки. */
@media (max-width: 420px) {
    .geoguide-qr-modal .app-modal-actions {
        flex-direction: column-reverse;
        align-items: stretch;
    }
    .geoguide-qr-modal .app-modal-actions .app-modal-btn {
        width: 100%;
    }
    .geoguide-qr-canvas canvas,
    .geoguide-qr-canvas img,
    .geoguide-qr-fallback-img {
        width: 200px;
        height: 200px;
    }
}

/* ============================================================
   [feature/geoguide-qr-styles-random] Индикатор текущего стиля
   QR-кода (маленькая пилюля под scan-hint, отображает текущий
   стиль: «Классический» / «Стиль N»). Иконка слева меняет
   цвет в тон выбранному стилю. ============================================================ */
.geoguide-qr-style-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 2px 0 0;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(37, 98, 232, 0.08);
    border: 1px solid rgba(37, 98, 232, 0.18);
    font-size: 11px;
    line-height: 1.2;
    color: var(--text-muted, #64748b);
    max-width: 100%;
    box-sizing: border-box;
}

.geoguide-qr-style-pill i {
    font-size: 10px;
    line-height: 1;
    color: #2562e8;
    transition: color 220ms ease;
}

.geoguide-qr-style-pill .geoguide-qr-style-pill-swatch {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    border: 1px solid rgba(15, 23, 42, 0.18);
    background: #ffffff;
    transition: background 220ms ease, border-color 220ms ease;
}

.geoguide-qr-style-pill span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dark-theme .geoguide-qr-style-pill {
    background: rgba(96, 165, 250, 0.10);
    border-color: rgba(96, 165, 250, 0.22);
    color: #94a3b8;
}

.dark-theme .geoguide-qr-style-pill i {
    color: #60a5fa;
}

/* При переключении стиля — короткая анимация swap-импульса
   на canvas-wrapper, чтобы было визуальное подтверждение. */
.geoguide-qr-canvas-wrap.is-restyle canvas,
.geoguide-qr-canvas-wrap.is-restyle img {
    animation: geoguide-qr-restyle 260ms ease;
}

@keyframes geoguide-qr-restyle {
    0%   { opacity: 0.35; transform: scale(0.94); }
    60%  { opacity: 1.0;  transform: scale(1.02); }
    100% { opacity: 1.0;  transform: scale(1.00); }
}

/* ============================================================
   [feature/qr-share-other-sections] QR Code modal — префиксы
   guide-qr-* / geokvest-qr-* / geotask-qr-*. Полностью паритетны
   геогидной модалке, но с независимыми CSS-классами, чтобы
   анимации / keyframes / dark-theme-overrides не пересекались
   между разделами. Все правила идентичны геогидным — для
   будущего сопровождения см. комментарий «Geoguide QR Code
   modal» выше.
   ============================================================ */
.guide-qr-modal,
.geokvest-qr-modal,
.geotask-qr-modal {
    max-width: 380px;
    text-align: center;
}

.guide-qr-modal-body,
.geokvest-qr-modal-body,
.geotask-qr-modal-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: 18px 20px 6px;
}

.guide-qr-loading,
.geokvest-qr-loading,
.geotask-qr-loading {
    margin: 28px 0 12px;
    font-size: 13px;
    line-height: 1.4;
    color: var(--text-muted, #64748b);
    opacity: 0.85;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.guide-qr-loading[hidden],
.guide-qr-error[hidden],
.guide-qr-canvas-wrap[hidden],
.geokvest-qr-loading[hidden],
.geokvest-qr-error[hidden],
.geokvest-qr-canvas-wrap[hidden],
.geotask-qr-loading[hidden],
.geotask-qr-error[hidden],
.geotask-qr-canvas-wrap[hidden] {
    display: none !important;
}

.guide-qr-loading::before,
.geokvest-qr-loading::before,
.geotask-qr-loading::before {
    content: '';
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid rgba(100, 116, 139, 0.25);
    border-top-color: #1274cf;
    animation: qr-share-spin 0.8s linear infinite;
}

@keyframes qr-share-spin {
    to { transform: rotate(360deg); }
}

.guide-qr-error,
.geokvest-qr-error,
.geotask-qr-error {
    margin: 24px 0 8px;
    padding: 10px 12px;
    font-size: 13px;
    line-height: 1.4;
    border-radius: 8px;
    background: rgba(220, 38, 38, 0.08);
    color: inherit;
    border: 1px solid rgba(220, 38, 38, 0.18);
}

.guide-qr-canvas-wrap,
.geokvest-qr-canvas-wrap,
.geotask-qr-canvas-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    width: 100%;
}

.guide-qr-canvas,
.geokvest-qr-canvas,
.geotask-qr-canvas {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 12px;
    border-radius: 14px;
    background: #ffffff;
    box-shadow:
        0 0 0 1px rgba(15, 23, 42, 0.06),
        0 8px 24px -10px rgba(15, 23, 42, 0.18);
    max-width: 100%;
}

.guide-qr-canvas canvas,
.guide-qr-canvas img,
.guide-qr-fallback-img,
.geokvest-qr-canvas canvas,
.geokvest-qr-canvas img,
.geokvest-qr-fallback-img,
.geotask-qr-canvas canvas,
.geotask-qr-canvas img,
.geotask-qr-fallback-img {
    display: block;
    width: 240px;
    height: 240px;
    max-width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
}

.guide-qr-scan-hint,
.geokvest-qr-scan-hint,
.geotask-qr-scan-hint {
    margin: 4px 0 0;
    font-size: 12px;
    line-height: 1.45;
    color: var(--text-muted, #64748b);
    opacity: 0.92;
    max-width: 320px;
}

.dark-theme .guide-qr-loading,
.dark-theme .geokvest-qr-loading,
.dark-theme .geotask-qr-loading {
    color: #94a3b8;
}

.dark-theme .guide-qr-error,
.dark-theme .geokvest-qr-error,
.dark-theme .geotask-qr-error {
    background: rgba(239, 68, 68, 0.12);
    border-color: rgba(239, 68, 68, 0.28);
}

.dark-theme .guide-qr-canvas,
.dark-theme .geokvest-qr-canvas,
.dark-theme .geotask-qr-canvas {
    background: #ffffff;
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.08),
        0 8px 24px -10px rgba(0, 0, 0, 0.5);
}

.dark-theme .guide-qr-scan-hint,
.dark-theme .geokvest-qr-scan-hint,
.dark-theme .geotask-qr-scan-hint {
    color: #94a3b8;
}

@media (max-width: 420px) {
    .guide-qr-modal .app-modal-actions,
    .geokvest-qr-modal .app-modal-actions,
    .geotask-qr-modal .app-modal-actions {
        flex-direction: column-reverse;
        align-items: stretch;
    }
    .guide-qr-modal .app-modal-actions .app-modal-btn,
    .geokvest-qr-modal .app-modal-actions .app-modal-btn,
    .geotask-qr-modal .app-modal-actions .app-modal-btn {
        width: 100%;
    }
    .guide-qr-canvas canvas,
    .guide-qr-canvas img,
    .guide-qr-fallback-img,
    .geokvest-qr-canvas canvas,
    .geokvest-qr-canvas img,
    .geokvest-qr-fallback-img,
    .geotask-qr-canvas canvas,
    .geotask-qr-canvas img,
    .geotask-qr-fallback-img {
        width: 200px;
        height: 200px;
    }
}

/* Индикатор текущего стиля QR (пилюля «Классический / Стилизованный»). */
.guide-qr-style-pill,
.geokvest-qr-style-pill,
.geotask-qr-style-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 2px 0 0;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(37, 98, 232, 0.08);
    border: 1px solid rgba(37, 98, 232, 0.18);
    font-size: 11px;
    line-height: 1.2;
    color: var(--text-muted, #64748b);
    max-width: 100%;
    box-sizing: border-box;
}

.guide-qr-style-pill i,
.geokvest-qr-style-pill i,
.geotask-qr-style-pill i {
    font-size: 10px;
    line-height: 1;
    color: #2562e8;
    transition: color 220ms ease;
}

.guide-qr-style-pill .guide-qr-style-pill-swatch,
.geokvest-qr-style-pill .geokvest-qr-style-pill-swatch,
.geotask-qr-style-pill .geotask-qr-style-pill-swatch {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    border: 1px solid rgba(15, 23, 42, 0.18);
    background: #ffffff;
    transition: background 220ms ease, border-color 220ms ease;
}

.guide-qr-style-pill span,
.geokvest-qr-style-pill span,
.geotask-qr-style-pill span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dark-theme .guide-qr-style-pill,
.dark-theme .geokvest-qr-style-pill,
.dark-theme .geotask-qr-style-pill {
    background: rgba(96, 165, 250, 0.10);
    border-color: rgba(96, 165, 250, 0.22);
    color: #94a3b8;
}

.dark-theme .guide-qr-style-pill i,
.dark-theme .geokvest-qr-style-pill i,
.dark-theme .geotask-qr-style-pill i {
    color: #60a5fa;
}

/* Swap-импульс при смене стиля. */
.guide-qr-canvas-wrap.is-restyle canvas,
.guide-qr-canvas-wrap.is-restyle img,
.geokvest-qr-canvas-wrap.is-restyle canvas,
.geokvest-qr-canvas-wrap.is-restyle img,
.geotask-qr-canvas-wrap.is-restyle canvas,
.geotask-qr-canvas-wrap.is-restyle img {
    animation: qr-share-restyle 260ms ease;
}

@keyframes qr-share-restyle {
    0%   { opacity: 0.35; transform: scale(0.94); }
    60%  { opacity: 1.0;  transform: scale(1.02); }
    100% { opacity: 1.0;  transform: scale(1.00); }
}
