/* Компоненты группы «controls», которых дизайн-система IDS не даёт.
   Строго на токенах --ids__*, без своих цветовых литералов: тогда компоненты
   автоматически работают и в тёмной теме (IDS переключает семантические токены
   по классу .dark на <html>). Файл подключается в MainAsset после site.css. */

/* ==========================================================================
   Кнопки. Ровно один акцент на действие: заливку (--site__action) получает
   только primary, secondary и ghost — без заливки (bookov.app: акцентная
   кнопка на странице одна, поэтому главное действие всегда однозначно).

   .btn — общий класс и для <button>, и для <a>: на сайте кнопка внутри формы —
   всегда <button>, кнопка-переход — всегда <a>, а выглядеть они обязаны одинаково.
   ========================================================================== */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ids__gap-s);
    padding: 0.6em 1.2em;
    border: none;
    border-radius: var(--ids__radius-m);
    background-color: transparent;
    box-shadow: none;
    font: inherit;
    /* Кнопка — элемент интерфейса: гротеском и внутри текста антиквой («О работе»). */
    font-family: var(--site__font-sans);
    font-weight: 550;
    cursor: pointer;
    transition:
        background-color var(--ids__duration-fast) var(--ids__easing-base),
        box-shadow var(--ids__duration-fast) var(--ids__easing-base),
        transform var(--ids__duration-fast) var(--ids__easing-base);
}

/* .ids a / .ids a:hover (assets/ids/css/components/ids.css) красят и подчёркивают
   ЛЮБУЮ ссылку на сайте — их специфичность (класс + тег [+ псевдокласс]) выше, чем
   у голого .btn/.btn:hover, поэтому именно цвет и подчёркивание кнопки переопределяем
   отдельно, селектором той же специфичности: ничью решает порядок подключения
   (controls.css идёт после ids.css). Остальных свойств .ids a не касается вовсе —
   там эта оговорка не нужна. */
:is(a, button).btn,
:is(a, button).btn:hover,
:is(a, button).btn:active {
    color: var(--ids__text);
    text-decoration: none;
}

.btn svg {
    width: 1em;
    height: 1em;
    flex-shrink: 0;
}

.btn:active {
    transform: translateY(1px);
}

.btn:disabled,
.btn[aria-disabled="true"] {
    cursor: not-allowed;
    pointer-events: none;
    /* --muted-opacity — та же переменная, что и у приглушённых карточек-тизеров
       (assets/main/site.css): единый визуальный язык «неактивно», а не новое число. */
    opacity: var(--muted-opacity);
}

/* Primary — единственный вариант с заливкой. */
.btn--primary {
    background-color: var(--site__action);
}

:is(a, button).btn--primary,
:is(a, button).btn--primary:hover,
:is(a, button).btn--primary:active {
    color: var(--site__action-text);
}

.btn--primary:hover,
.btn--primary:active {
    background-color: var(--site__action-hover);
}

/* Positive — зелёная заливка для главного призыва написать (первый экран главной).
   Белый текст на #0b7a55 — 5.3:1 (WCAG AA), тот же цвет, что у зоны «Интерфейсы». */
.btn--positive {
    background-color: var(--site__positive);
}

:is(a, button).btn--positive,
:is(a, button).btn--positive:hover,
:is(a, button).btn--positive:active {
    color: var(--site__action-text);
}

.btn--positive:hover,
.btn--positive:active {
    background-color: var(--site__positive-hover);
}

/* Secondary — рамка вместо заливки. */
.btn--secondary {
    box-shadow: inset 0 0 0 var(--ids__border-width-s) var(--site__hairline-strong);
}

.btn--secondary:hover {
    box-shadow: inset 0 0 0 var(--ids__border-width-s) var(--ids__text);
}

/* Ghost — только текст, фон проступает лишь при наведении. */
.btn--ghost:hover {
    background-color: color-mix(in srgb, var(--ids__text) 8%, transparent);
}

/* Кнопка-ссылка — минимальная: визуально обычная ссылка (цвет и подчёркивание те же,
   что .ids a уже даёт бесплатно), но с семантикой действия — годится и для <button>. */
.btn--link {
    display: inline;
    padding: 0;
    background: none;
}

:is(a, button).btn--link,
:is(a, button).btn--link:hover,
:is(a, button).btn--link:active {
    color: var(--ids__link);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

:is(a, button).btn--link:hover,
:is(a, button).btn--link:active {
    color: var(--ids__hover);
}

/* Пилюля — для главного призыва, обычно вместе с primary. */
.btn--pill {
    border-radius: var(--ids__radius-pill);
}

/* Стеклянная — поверх фотографии/тёмного фона, а не проверка текущей темы сайта:
   цвет берём через color-mix от токена --site__on-media (белый в любой теме), это не
   литерал, а ссылка на токен — кнопка рассчитана на тёмную подложку. */
.btn--glass {
    background-color: color-mix(in srgb, var(--site__on-media) 18%, transparent);
    box-shadow: inset 0 0 0 var(--ids__border-width-s) color-mix(in srgb, var(--site__on-media) 35%, transparent);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}

:is(a, button).btn--glass,
:is(a, button).btn--glass:hover,
:is(a, button).btn--glass:active {
    color: var(--site__on-media);
}

.btn--glass:hover,
.btn--glass:active {
    background-color: color-mix(in srgb, var(--site__on-media) 28%, transparent);
}

/* Мелкий размер. */
.btn--sm {
    padding: 0.35em 0.8em;
    font-size: 0.85em;
}

/* На всю ширину контейнера. */
.btn--block {
    display: flex;
    width: 100%;
}

/* ==========================================================================
   Формы. IDS не даёт ни одного поля — всё ниже наше.
   ========================================================================== */

/* Обёртка одного поля: подпись + контрол + подсказка/ошибка. Держит себя и сама по
   себе (свой отступ снизу), и внутри .kit__demo.stack — там просто добавится к gap
   контейнера. */
.field {
    display: flex;
    flex-direction: column;
    gap: 0.35em;
    max-width: 32em;
    margin-bottom: var(--ids__gap-m);
}

.field label {
    font-size: 0.9em;
    font-weight: 550;
}

/* Звёздочка у обязательного поля — только визуальное усиление; само слово
   «обязательное» произносится текстом в подсказке, а не одним лишь значком. */
.field__required {
    color: var(--ids__error);
}

/* Текст, email, пароль, поиск, многострочное и выпадающий список — один класс на
   все контролы. Рамка — box-shadow inset, а не border: при фокусе/ошибке толщина
   меняется без сдвига раскладки (border при box-sizing: border-box отъедал бы себе
   место в блочной модели, box-shadow — никогда; приём с bookov.app). */
.field__control {
    display: block;
    width: 100%;
    padding: 0.55em 0.75em;
    background-color: var(--ids__background);
    color: var(--ids__text);
    border: none;
    border-radius: var(--ids__radius-s);
    box-shadow: inset 0 0 0 var(--ids__border-width-s) var(--site__hairline-strong);
    font: inherit;
    transition: box-shadow var(--ids__duration-fast) var(--ids__easing-base);
}

.field__control::placeholder {
    color: var(--ids__text-caption);
}

.field__control:focus {
    box-shadow: inset 0 0 0 var(--ids__border-width-m) var(--ids__link);
}

/* Ошибка — через aria-invalid, а не отдельный CSS-класс: визуальное состояние поля
   и то, что о нём знает скринридер, тогда не могут разойтись. */
.field__control[aria-invalid="true"] {
    box-shadow: inset 0 0 0 var(--ids__border-width-m) var(--ids__error);
}

.field__control:disabled {
    cursor: not-allowed;
    opacity: var(--muted-opacity);
}

.field__control:read-only {
    background-color: var(--ids__surface);
}

textarea.field__control {
    resize: vertical;
    min-height: 6em;
}

.field__hint {
    margin: 0;
    color: var(--ids__text-caption);
    font-size: 0.85em;
}

.field__error {
    margin: 0;
    color: var(--ids__error);
    font-size: 0.85em;
}

/* Чекбокс и радио — своя строка: контрол и подпись рядом, а не подпись над полем. */
.field__check {
    display: flex;
    align-items: center;
    gap: var(--ids__gap-s);
    margin-bottom: 0.5em;
}

.field__check label {
    font-size: 0.95em;
    font-weight: normal;
}

.field__check input[type="checkbox"],
.field__check input[type="radio"] {
    width: 1.1em;
    height: 1.1em;
    accent-color: var(--site__action);
}

/* Файл — своя, более лёгкая обёртка вместо .field__control: нативный виджет уже
   состоит из кнопки и подписи, дублировать это в разметке — переусложнение ради
   поля, которого на сайте почти не будет. Кнопку выбора файла оформляем через
   ::file-selector-button, остальное остаётся как в браузере. */
.field__control--file {
    color: var(--ids__text-caption);
    font: inherit;
}

.field__control--file::file-selector-button {
    margin-right: var(--ids__gap-s);
    padding: 0.4em 0.9em;
    border: none;
    border-radius: var(--ids__radius-s);
    box-shadow: inset 0 0 0 var(--ids__border-width-s) var(--site__hairline-strong);
    background-color: var(--ids__surface);
    color: var(--ids__text);
    font: inherit;
    cursor: pointer;
}

.field__control--file:hover::file-selector-button {
    box-shadow: inset 0 0 0 var(--ids__border-width-s) var(--ids__text);
}

/* Группа полей — fieldset/legend. Браузерный border у fieldset выключаем явно и
   рисуем рамку тем же приёмом (box-shadow), что и у полей. */
.field-group {
    margin: 0 0 var(--ids__gap-m);
    padding: var(--ids__spacer-m);
    border: none;
    border-radius: var(--ids__radius-m);
    box-shadow: inset 0 0 0 var(--ids__border-width-s) var(--site__hairline);
}

.field-group legend {
    padding: 0 0.4em;
    font-weight: 600;
}

/* ==========================================================================
   Сообщения и статусы. IDS даёт только цвета --ids__success/--ids__error — самих
   компонентов (алерт, бейдж, тег, счётчик, пустое состояние) нет вообще.
   ========================================================================== */

.alert {
    display: flex;
    align-items: flex-start;
    gap: var(--ids__gap-s);
    padding: var(--ids__spacer-s) var(--ids__spacer-m);
    border-radius: var(--ids__radius-m);
    background-color: var(--ids__surface);
    box-shadow: inset 0 0 0 var(--ids__border-width-s) var(--site__hairline);
}

.alert p {
    margin: 0;
}

.alert__title {
    font-weight: 600;
}

/* Успех и ошибка — цветом токенов IDS. Предупреждение и нейтральный сознательно
   цвета не получают (условие задачи): различаются весом рамки, а называется вид
   сообщения — словом в тексте, а не оттенком. */
.alert--success {
    box-shadow: inset 0 0 0 var(--ids__border-width-m) var(--ids__success);
}

.alert--error {
    box-shadow: inset 0 0 0 var(--ids__border-width-m) var(--ids__error);
}

.alert--warning {
    box-shadow: inset 0 0 0 var(--ids__border-width-m) var(--site__hairline-strong);
}

/* Бейдж статуса. Статус называется словом («Опубликовано» и т.п.) — цвет здесь
   только усиление, а не единственный носитель смысла (bookov.app: «Released» /
   «TBA» подписью, а не одним цветом). */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.2em 0.7em;
    border-radius: var(--ids__radius-pill);
    background-color: var(--ids__surface);
    box-shadow: inset 0 0 0 var(--ids__border-width-s) var(--site__hairline-strong);
    color: var(--ids__text);
    font-size: 0.8em;
    font-weight: 600;
}

.badge--published {
    box-shadow: inset 0 0 0 var(--ids__border-width-s) var(--ids__success);
    color: var(--ids__success);
}

.badge--in-progress {
    color: var(--ids__text-caption);
}

/* Тег — нейтральная метка темы/категории, в отличие от бейджа не несёт статуса. */
.tag {
    display: inline-flex;
    padding: 0.2em 0.6em;
    border-radius: var(--ids__radius-s);
    background-color: var(--site__surface-paper);
    color: var(--ids__text-caption);
    font-size: 0.8em;
}

/* Тег в своём цвете (App\Shared\Tag\TagPalette): цвета приходят переменными --tag-* в style. */
.tag-chip {
    display: inline-flex;
    padding: 0.2em 0.6em;
    border-radius: var(--ids__radius-s);
    background-color: var(--tag-bg);
    color: var(--tag-title);
    font-weight: 600;
}

/* Выбор цвета тега — образцами в строку; выбранный обведён. */
.tag-palette {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ids__gap-s);
    margin: 0 0 var(--ids__spacer-m);
    padding: 0;
    border: 0;
}

.tag-palette legend {
    margin-bottom: var(--ids__gap-s);
    font-weight: 600;
}

.tag-palette__option {
    display: inline-flex;
    align-items: center;
    gap: 0.3em;
    cursor: pointer;
}

.tag-palette__option input:checked + .tag-chip {
    outline: 2px solid var(--ids__text);
    outline-offset: 2px;
}

/* Слот блока «Проекты на главной» в админке (src/Web/Admin/HomeProjects). */
.home-projects-slot {
    margin: 0 0 var(--ids__spacer-m);
    padding: var(--ids__spacer-s) var(--ids__spacer-m);
    border: 1px solid var(--site__hairline);
    border-radius: var(--ids__radius-m);
}

.home-projects-slot legend {
    padding: 0 0.3em;
    font-weight: 700;
}

.home-projects-slot__options {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ids__gap-s) var(--ids__gap-l);
}

/* Счётчик — например, число работ у пункта навигации. */
.counter {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.6em;
    padding: 0.1em 0.4em;
    border-radius: var(--ids__radius-pill);
    background-color: var(--ids__surface);
    color: var(--ids__text-caption);
    font-size: 0.8em;
    font-variant-numeric: tabular-nums;
}

/* Пустое состояние — раздел опубликован, но пуст (App\Shared\EmptySectionQuotes).
   Пунктирная рамка сигналит «здесь пока ничего нет», а не «что-то сломано». */
.empty-state {
    padding: var(--ids__spacer-l) var(--ids__spacer-m);
    border: var(--ids__border-width-s) dashed var(--site__hairline-strong);
    border-radius: var(--ids__radius-m);
    color: var(--ids__text-caption);
    text-align: center;
}

.empty-state__title {
    margin-bottom: var(--ids__gap-s);
    color: var(--ids__text);
    font-weight: 600;
}

/* ==========================================================================
   Хлебные крошки (App\Web\Shared\Widget\BreadcrumbsWidget) — docs/PLAN.md §4.7
   называет их среди того, чего IDS не даёт вообще.
   ========================================================================== */

/* <ol> — семантически верно (путь пронумерован по порядку), но самой нумерации
   быть не должно: IDS даёт её любому <ol> внутри <body class="ids">
   (`.ids ol li { list-style: decimal inside none; }`, assets/ids/css/components/ids.css).
   Специфичность переопределения та же (класс + тег + тег) — ничью решает порядок
   подключения файлов (controls.css после ids.css), тот же приём, что и у
   .taxonomy-nav в site.css и у a.card--link в blocks.css. */
.breadcrumbs ol {
    display: flex;
    flex-wrap: wrap;
    margin: 0;
    padding: 0;
}

.breadcrumbs ol li {
    display: flex;
    align-items: center;
    list-style: none;
    margin-bottom: 0;
}

/* Разделитель — псевдоэлемент у всех пунктов, кроме первого, а не отдельный узел
   в разметке виджета: добавить/убрать пункт не требует менять код разделителей. */
.breadcrumbs li + li::before {
    content: "/";
    margin: 0 0.5em;
    color: var(--ids__text-caption);
}

/* Текущая страница — без ссылки на саму себя, приглушённым текстом (тот же
   язык «вторичности», что у --ids__text-caption в .tag/.counter/.taxonomy-nav
   small). */
.breadcrumbs [aria-current="page"] {
    color: var(--ids__text-caption);
}
