/*
 * components.css — набор «Полночного архива». Собран ТОЛЬКО на токенах.
 * Подключать после tokens.css, до common.css и CSS страницы. Бриф — /DESIGN.md.
 *
 * Смысл файла: экран собирается из этих кусков, а не рисуется заново. Если
 * кажется, что нужен свой класс кнопки или своя карточка — значит либо здесь
 * не хватает куска (добавь ЗДЕСЬ), либо экран делает то, чего не должен.
 *
 * Правила, которые нельзя нарушить и которые проверяет tests/test_design_tokens.py:
 *   · box-shadow не бывает — ни одной, включая «еле заметную»;
 *   · рамка строго 1 px и только --hair или --border, цветных рамок нет;
 *   · золото — одна залитая кнопка на экран и метка «бесплатно», больше нигде;
 *   · заголовки весом 400, капса нет;
 *   · при наведении и нажатии меняется цвет, ничего не двигается и не растёт.
 */

/* ── Колонка контента ── */
.container {
    width: 100%;
    max-width: var(--container);
}

/* ═══ ТЕКСТ ═══════════════════════════════════════════════════════════ */

/* Заголовок экрана. Фирменный ход — ДВЕ гарнитуры в одном заголовке: первое слово
   рукописным светом, остальное узким тяжёлым капсом. Разметку собирает
   assets/js/screen-head.js, второго места у этого правила нет:
   <h1 class="title"><i>Карта</i><b>дня</b></h1>
   Капс здесь — часть гарнитуры, а не «способ сделать дорого»: разрядки нет. */
.title {
    font-family: var(--font-display); font-weight: 800;
    font-size: var(--fs-h1); line-height: .88;
    color: var(--ink); text-align: center; text-wrap: balance;
    text-transform: uppercase; margin: 0;
}
/* Первое слово: рукописный светом. Свечение — роль света (tokens.css §2). */
.title i {
    display: block; font-family: var(--font-script); font-style: normal;
    font-weight: 400; font-size: .82em; line-height: .92; text-transform: none;
    color: var(--light); text-shadow: 0 0 20px rgba(var(--light-rgb), .45);
}
.title b { display: block; font-weight: inherit; margin-top: -.18em; }
.title--section { font-size: var(--fs-h2); }

/* Одна строка под заголовком. Больше одной не бывает. */
.subtitle {
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    line-height: var(--lh-normal);
    color: var(--body);
    text-align: center;
    margin: var(--space-2) 0 0;
}

/* Голос Ясны. Она говорит курсивом, интерфейс — прямым. */
.voice {
    font-family: var(--font-voice);
    font-style: italic;
    font-weight: 400;
    font-size: var(--fs-base);
    line-height: var(--lh-body);
    color: var(--ink);
}

/* Обычный читаемый текст: описания, пояснения. */
.note {
    font-family: var(--font-body);
    font-size: var(--fs-base);
    line-height: var(--lh-body);
    color: var(--body);
}

/* Тот же текст, но про сбой: та же краска, что у опасного действия. Второго
   акцента нет — ошибка отличается краской, а не размером и не заливкой. */
.note--error { color: rgba(var(--danger-rgb), .95); }

/* ═══ ПОВЕРХНОСТИ ═════════════════════════════════════════════════════ */

/* Витрина — поверхность с экспонатом (карта, результат, крупный блок).
   Границу здесь показывает сам экспонат, поэтому рамка волосяная. */
.case {
    background: var(--case);
    border: 1px solid var(--hair);
    border-radius: var(--radius-case);
    padding: var(--space-5);
}
/* Витрина-строка: экспонат слева, этикетка справа (карта дня на главной). */
.case--row { display: flex; gap: var(--space-5); align-items: stretch; }
.case--row > img,
.case--row > .deck-back { width: 74px; flex: 0 0 auto; border-radius: var(--radius-sm); display: block; }
/* Экспонат витрины-строки — карта колоды. Границу показывает сам арт, поэтому
   рамка волосяная (как у карты на экране результата). */
.deck-card { align-self: flex-start; border: 1px solid var(--hair); height: auto; }

/* Рубашка карты в витрине-строке. Рисунок даёт assets/js/card-back.js — рубашка
   в проекте одна, и картинкой она быть перестала: /static/images/card-back.svg
   на бою отдаёт 404 (#1023), и витрина стояла с дырой вместо экспоната. */
.deck-back {
    border: 1px solid var(--border);
    overflow: hidden;
    align-self: flex-start;
}
.deck-back svg { display: block; width: 100%; height: auto; }
.case--row > .case__side { flex: 1; display: flex; flex-direction: column; min-width: 0; }

/* .card — старое имя витрины, живёт в 19 местах разметки. Новый код берёт .case. */
.card {
    background: var(--case);
    border: 1px solid var(--hair);
    border-radius: var(--radius-case);
}

/* Плитка-экспонат: услуга в каталоге, две колонки. */
.tile {
    background: var(--case);
    border: 1px solid var(--hair);
    border-radius: var(--radius-tile);
    padding: var(--space-4) var(--space-5);
    display: block;
    text-decoration: none;
    transition: var(--transition);
}
.tile > img { display: block; width: 100%; border-radius: var(--radius-sm); margin-bottom: var(--space-3); }

/* Ряд плиток — две колонки всегда: на узком экране ужимаются, но не схлопываются
   в одну. Жил в landing.css, пока плитка была только на главной; с 02.08.2026
   ею же собран каталог таро, и раскладка переехала к самому компоненту. */
.tiles {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
    margin-top: var(--space-3);
}
.tile__name {
    display: block;
    font-family: var(--font-display); font-weight: 400;
    font-size: var(--fs-ui); line-height: var(--lh-normal);
    color: var(--ink);
}
.tile__price {
    display: block; margin-top: 2px;
    font-family: var(--font-body); font-size: var(--fs-xs);
    color: var(--body); font-variant-numeric: tabular-nums;
    min-height: 1em;                 /* место под цену держим заранее: она приезжает из API */
}
/* Каталог: плитка с экспонатом. Рамка волосяная — границу объекта показывает
   сама карта, как в витрине результата. */
.tiles--catalog .tile { border-color: var(--hair); }
.tile:hover { border-color: var(--border); }

/* Нажимаемая плитка БЕЗ экспоната внутри. Тоном её границу показать физически
   нельзя (витрина к холсту = 1.19), поэтому рамка видимая: 2.8 — порог, который
   Катя увидела глазами 02.08.2026. Вниз не двигать. */
.tile--pressable { border-color: var(--border); }

/* Зал — самый глубокий слой. ТОЛЬКО экран гадания и шапка результата. */
.hall { background: var(--hall); }

/* ═══ ЭТИКЕТКА ════════════════════════════════════════════════════════ */

/* Строка «название — метка» в витрине. */
.plate { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3); }
.plate__name {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: var(--fs-lg);
    color: var(--ink);
}

/* Музейная экспликация вместо подписи «5 карт · 73 ₽»: пары ключ → значение.
   Разметка: <dl class="label"><dt>состав</dt><dd>5 карт</dd>…</dl> */
.label {
    border-top: 1px solid var(--hair);
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-1) var(--space-5);
    font-family: var(--font-body);
    font-size: var(--fs-xs);
    line-height: var(--lh-normal);
    color: var(--body);
}
.label dt { color: var(--mark); }
.label dd { margin: 0; }

/* Метка «бесплатно» — второе и последнее место, где живёт золото. */
.tag {
    display: inline-block;
    background: var(--gold);
    color: var(--on-gold);
    border-radius: var(--radius-pill);
    padding: 3px 9px;
    font-family: var(--font-body);
    font-size: var(--fs-xs);
    font-weight: 500;
    white-space: nowrap;
}

/* ═══ ДЕЙСТВИЕ ════════════════════════════════════════════════════════ */

/* Единственная залитая кнопка на экране. Двух таких на экране не бывает. */
.btn {
    display: block;
    width: 100%;
    box-sizing: border-box;
    background: var(--gold);
    color: var(--on-gold);
    border: 1px solid var(--gold);
    border-radius: var(--radius-pill);
    padding: var(--space-5);
    font-family: var(--font-body);
    font-size: var(--fs-ui);
    font-weight: 500;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: var(--transition);
}
.btn:hover { opacity: .88; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .4; cursor: not-allowed; }

/* Кнопка в строку с полем ввода («Оплатить» рядом с суммой): ширина по тексту,
   всё остальное — та же кнопка. Заводить ради этого свой класс не нужно. */
.btn--inline { display: inline-block; width: auto; white-space: nowrap; padding: var(--space-4) var(--space-6); }

/* Кнопка со значком внутри («Поделиться ссылкой»): значок и подпись в строку,
   по центру. Единственное, чего не умеет .btn — из-за этого рядом жил целый
   свой класс .btn-share с повтором всей заливки. Снято 02.08.2026. */
.btn--icon { display: flex; align-items: center; justify-content: center; gap: var(--space-2); }

/* Вторичное действие — контурная пилюля. Не более одной на экран. */
.btn--ghost {
    background: transparent;
    color: var(--ink);
    border-color: var(--hair);
}
.btn--ghost:hover { border-color: var(--border); opacity: 1; }

/* Опасное действие (удаление данных) — единственный хроматический цвет кроме золота. */
.btn--danger {
    background: transparent;
    color: rgba(var(--danger-rgb), .85);
    border-color: rgba(var(--danger-border-rgb), .35);
}
.btn--danger:hover { color: rgb(var(--danger-rgb)); border-color: rgba(var(--danger-border-rgb), .6); }

/* Модификаторов .btn--solid и .btn--outline здесь нет намеренно: первый — это
   и есть .btn, второй — .btn--ghost. Разметку перевели 02.08.2026, дубли сняты. */

/* ═══ СООБЩЕНИЯ ═══════════════════════════════════════════════════════ */

/* Аварийная плашка («не удалось загрузить»). Раньше её рисовали инлайн-стилем
   прямо в JS: золотая заливка, золотая рамка и золотой текст — то есть роль
   действия, размазанная по блоку с сообщением. Плашка ничего не делает, поэтому
   она обычная витрина с текстом тела. */
.notice {
    background: var(--case);
    border: 1px solid var(--hair);
    border-radius: var(--radius-tile);
    padding: var(--space-5);
    margin: var(--space-5) var(--gutter);
    text-align: center;
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    line-height: var(--lh-normal);
    color: var(--body);
}
.notice__title { display: block; font-family: var(--font-display); font-size: var(--fs-lg); color: var(--ink); margin-bottom: var(--space-2); }
/* Действие внутри плашки центрируется само: .notice выровнена по центру. */
.notice__cta { margin-top: var(--space-5); }

/* Всплывающее сообщение. Тени нет (в направлении их нет ни одной), второго
   акцента нет: обычное сообщение отделяется от холста тоном витрины и рамкой,
   ошибка — той же краской, что и опасное действие. */
.toast {
    position: fixed; left: 50%; bottom: 32px; transform: translateX(-50%);
    max-width: 90%; z-index: 9999;
    background: var(--case);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    padding: var(--space-4) var(--space-6);
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    color: var(--ink);
    text-align: center;
    opacity: 0;
    transition: opacity .25s ease;
}
.toast--shown { opacity: 1; }
.toast--error { color: rgba(var(--danger-rgb), .95); border-color: rgba(var(--danger-border-rgb), .5); }
