/* Mini App shell and screens.
 *
 * EVERY value here is a token from tokens.css — the machine projection of the brand book, linked in
 * from the Api project so there is one file for every surface. A value that is not there is added to
 * the brand book first and never picked at the call site (CLAUDE.md).
 *
 * There is no dark/light switch: the app has ONE theme, dark, and Telegram's themeParams are
 * deliberately not read — someone else's palette over ours gives unpredictable contrast against a
 * mandatory 4.5:1 (brandbook ch. 12 §9.1).
 */

*,
*::before,
*::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--color-bg-primary);
    color: var(--color-text-primary);
    font-family: var(--font-sans);
    font-size: var(--font-body);
    line-height: var(--leading-body);
    -webkit-font-smoothing: antialiased;
}

/* ---------------------------------------------------------------- shell --- */

.app-shell {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
}

.app-content {
    flex: 1 1 auto;
    /* 16px screen margins, safe areas on top of that (ch. 12 §9.3). The bottom pad clears the tab
       bar: content that scrolls under it can never be read or tapped. */
    padding:
        calc(var(--space-16) + env(safe-area-inset-top))
        calc(var(--space-16) + env(safe-area-inset-right))
        calc(var(--space-96) + env(safe-area-inset-bottom))
        calc(var(--space-16) + env(safe-area-inset-left));
}

.tabbar {
    position: fixed;
    inset: auto 0 0 0;
    z-index: var(--layer-sticky);
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    background: var(--color-bg-elevated);
    border-top: 1px solid var(--color-border-subtle);
    padding-bottom: env(safe-area-inset-bottom);
}

.tabbar__item {
    /* 44px minimum touch target (ch. 12 §9.3) even though the label is shorter. */
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-12) var(--space-8);
    color: var(--color-text-secondary);
    font-size: var(--font-small);
    text-decoration: none;
    transition: color var(--motion-fast) var(--ease-standard);
}

.tabbar__item:hover {
    color: var(--color-text-primary);
}

.tabbar__item.active {
    color: var(--color-action-primary);
}

/* ------------------------------------------------------------ typography --- */

h1 {
    margin: 0 0 var(--space-16);
    font-size: var(--font-h2);
    line-height: var(--leading-heading);
    font-weight: 600;
}

h2 {
    margin: var(--space-32) 0 var(--space-12);
    font-size: var(--font-h4);
    line-height: var(--leading-subhead);
    font-weight: 600;
}

p {
    margin: 0 0 var(--space-12);
}

.muted {
    color: var(--color-text-secondary);
}

.caption {
    font-size: var(--font-caption);
    color: var(--color-text-muted);
}

/* ----------------------------------------------------------------- card --- */

.card {
    background: var(--color-surface-default);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-lg);
    padding: var(--space-16);
    margin-bottom: var(--space-12);
}

.card__title {
    margin: 0 0 var(--space-4);
    font-size: var(--font-h5);
    font-weight: 600;
}

.card__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-12);
    margin-bottom: var(--space-8);
}

/* --------------------------------------------------------------- badges --- */

.badge {
    display: inline-block;
    padding: var(--space-4) var(--space-12);
    border-radius: var(--radius-full);
    font-size: var(--font-caption);
    font-weight: 600;
}

.badge--success {
    background: var(--color-success-soft);
    color: var(--color-success);
}

.badge--warning {
    background: var(--color-warning-soft);
    color: var(--color-warning);
}

.badge--error {
    background: var(--color-error-soft);
    color: var(--color-error);
}

.badge--info {
    background: var(--color-info-soft);
    color: var(--color-info);
}

/* -------------------------------------------------------------- buttons --- */

.btn {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-8);
    padding: var(--space-12) var(--space-24);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-family: inherit;
    font-size: var(--font-body);
    font-weight: 600;
    cursor: pointer;
    transition:
        background-color var(--motion-fast) var(--ease-standard),
        color var(--motion-fast) var(--ease-standard);
}

.btn:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}

/* Width is fixed while loading so the button does not resize under the finger mid-tap
   (ch. 12 §6.2, step 1). */
.btn[disabled] {
    background: var(--color-action-disabled);
    color: var(--color-text-disabled);
    cursor: default;
}

.btn--primary {
    background: var(--color-action-primary);
    color: var(--color-text-inverse);
}

.btn--primary:hover:not([disabled]) {
    background: var(--color-action-hover);
}

.btn--primary:active:not([disabled]) {
    background: var(--color-action-pressed);
}

.btn--secondary {
    background: var(--color-surface-default);
    border-color: var(--color-border-control);
    color: var(--color-text-primary);
}

.btn--secondary:hover:not([disabled]) {
    background: var(--color-surface-hover);
}

.btn--block {
    width: 100%;
}

.btn-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-8);
}

/* ---------------------------------------------------------- state panel --- */

.state-panel {
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-lg);
    padding: var(--space-16);
    margin-bottom: var(--space-16);
    background: var(--color-surface-default);
}

.state-panel--error,
.state-panel--offline {
    border-color: var(--color-error);
    background: var(--color-error-soft);
}

.state-panel--sessionended {
    border-color: var(--color-warning);
    background: var(--color-warning-soft);
}

.state-panel__text {
    margin: 0 0 var(--space-12);
}

.state-panel__text:last-child {
    margin-bottom: 0;
}

/* ------------------------------------------------------------- skeleton --- */

/* A skeleton in the geometry of the content to come, never a full-screen spinner
   (ch. 12 §4.2). */
.skeleton {
    background: var(--color-surface-hover);
    border-radius: var(--radius-sm);
    height: 1rem;
    margin-bottom: var(--space-8);
    animation: skeleton-pulse var(--motion-screen) var(--ease-standard) infinite alternate;
}

.skeleton--title {
    height: 1.5rem;
    width: 60%;
}

.skeleton--line {
    width: 100%;
}

.skeleton--short {
    width: 40%;
}

@keyframes skeleton-pulse {
    from { opacity: 1; }
    to { opacity: 0.55; }
}

@media (prefers-reduced-motion: reduce) {
    .skeleton {
        animation: none;
    }

    * {
        transition-duration: var(--motion-instant) !important;
    }
}

/* ------------------------------------------------------------- key card --- */

.key-card__link {
    font-family: var(--font-mono);
    font-size: var(--font-small);
    color: var(--color-text-secondary);
    word-break: break-all;
    margin-bottom: var(--space-12);
}

.key-card__qr {
    display: block;
    width: 220px;
    max-width: 100%;
    height: auto;
    margin: var(--space-12) auto 0;
    /* The QR is rendered on a white field because scanners need the quiet zone light — this is the
       one surface in the product that is not on the dark ground, and it is functional. */
    background: #FFFFFF;
    border-radius: var(--radius-sm);
    padding: var(--space-8);
}

/* ---------------------------------------------------------------- forms --- */

.field {
    margin-bottom: var(--space-16);
}

.field__label {
    display: block;
    margin-bottom: var(--space-8);
    font-size: var(--font-small);
    color: var(--color-text-secondary);
}

.field input {
    width: 100%;
    min-height: 44px;
    padding: var(--space-12);
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border-control);
    border-radius: var(--radius-md);
    color: var(--color-text-primary);
    font-family: inherit;
    font-size: var(--font-body);
}

.field input:focus-visible {
    outline: none;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-focus);
}

/* ---------------------------------------------------------------- toast --- */

/* The ONE place a toast is right: copying leaves no state behind (ch. 12 §5.1). */
.toast {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(var(--space-96) + env(safe-area-inset-bottom));
    z-index: var(--layer-toast);
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-full);
    padding: var(--space-8) var(--space-24);
    box-shadow: var(--shadow-popover);
    font-size: var(--font-small);
}

/* ------------------------------------------------------------- заголовок --- */

/* Тот же вид, что у голого h1: класс существует, чтобы экран мог называть свой заголовок явно, а
   не полагаться на то, что он единственный h1 на странице. Значения не дублируются -- правило
   наследует их у h1 выше и добавляет только принадлежность экрану. */
.screen-title {
    margin: 0 0 var(--space-16);
}

/* Пояснение под содержимым: тише основного текста, но не настолько, чтобы его перестали читать --
   .caption для подписей к элементам, .hint для целой мысли под блоком. */
.hint {
    margin: var(--space-12) 0 0;
    font-size: var(--font-small);
    color: var(--color-text-secondary);
}

/* ------------------------------------------------------------------ поле --- */

/* Отдельно от `.field input`: тот селектор работает только внутри обёртки .field, а поле кода
   стоит в своей раскладке. Значения те же -- расхождение вида одного и того же элемента между
   экранами читается как небрежность, а не как замысел. */
.input {
    min-height: 44px;
    padding: var(--space-12);
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border-control);
    border-radius: var(--radius-md);
    color: var(--color-text-primary);
    font-family: inherit;
    font-size: var(--font-body);
    transition: border-color var(--motion-fast) var(--ease-standard);
}

.input:focus-visible {
    outline: none;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-focus);
}

.input[disabled] {
    color: var(--color-text-disabled);
    cursor: not-allowed;
}

/* --------------------------------------------------- разрушающее действие --- */

/* Отзыв пропуска -- единственное место, где кнопка красная. Отдельный вид нужен потому, что
   действие необратимо: вторичная кнопка рядом с ним выглядит равнозначной, а они не равнозначны. */
.btn--danger {
    background: var(--color-error);
    border-color: var(--color-error);
    color: var(--color-text-inverse);
}

.btn--danger:hover:not([disabled]) {
    background: var(--color-error-hover);
    border-color: var(--color-error-hover);
}

.btn--danger:active:not([disabled]) {
    background: var(--color-error-pressed);
    border-color: var(--color-error-pressed);
}

.btn--danger[disabled] {
    background: var(--color-action-disabled);
    border-color: var(--color-action-disabled);
    color: var(--color-text-disabled);
    cursor: not-allowed;
}

/* ---------------------------------------------------------- код привязки --- */

/* ПЕРВЫЙ экран, который человек видит вне Telegram, поэтому он не может выглядеть как черновик.
   Раскладка в одну колонку: поле и кнопка стоят друг под другом, а не в строку, — на узком экране
   строка ужимает поле до нечитаемой ширины ровно там, где надо разобрать шесть цифр. */
.device-code {
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
    padding: var(--space-16);
    background: var(--color-surface-default);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
}

.device-code__prompt {
    margin: 0;
    color: var(--color-text-primary);
}

.device-code__label {
    font-size: var(--font-small);
    color: var(--color-text-secondary);
}

/* Моноширинный и разреженный: шесть цифр переписывают с другого экрана, и слитный ряд в
   пропорциональной гарнитуре теряется на третьей цифре. Крупнее основного текста по той же
   причине. */
.device-code__input {
    width: 100%;
    font-family: var(--font-mono);
    font-size: var(--font-h4);
    letter-spacing: 0.2em;
    text-align: center;
}

.device-code__hint {
    margin: 0;
    font-size: var(--font-small);
    color: var(--color-text-muted);
}

/* -------------------------------------------------------------- устройства --- */

.device-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
}

.device-list__item {
    padding: var(--space-16);
    background: var(--color-surface-default);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
}

/* Отозванное устройство ОСТАЁТСЯ в списке и остаётся читаемым: строка нужна как след — «этот
   пропуск отозван тогда-то». Приглушение делается цветом текста, а не opacity: opacity гасит и
   границу, и человек читает это как «элемент выключен», а не «доступ отозван». */
.device-list__item--revoked .device-list__name {
    color: var(--color-text-secondary);
}

.device-list__name {
    font-weight: 600;
    color: var(--color-text-primary);
}

.device-list__meta {
    margin-top: var(--space-4);
    font-size: var(--font-small);
    color: var(--color-text-secondary);
}

/* Предупреждение перед отзывом: цена действия называется ДО нажатия, поэтому оно и выделено. */
.device-list__warning {
    margin: var(--space-12) 0;
    padding: var(--space-12);
    background: var(--color-error-soft);
    border-radius: var(--radius-md);
    font-size: var(--font-small);
    color: var(--color-text-primary);
}

/* ----------------------------------------------------------- нижняя панель --- */

/* Подпись вкладки: сама вкладка (.tabbar__item) держит зону нажатия и цвет, подпись отвечает
   только за перенос — длинное слово в узкой колонке иначе вылезает за её границу. */
.tabbar__label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
