/*
   app-styles.css (29.07.26) — вынесен из <style> внутри
   resources/views/layouts/app.blade.php по прямому запросу автора: "почему
   мы не можем создать один общий внешний файл стилей?". Причина, по которой
   стиль раньше жил inline в layout, была чисто исторической (так изначально
   сложилось в проекте), не архитектурным решением — выносить можно было
   всегда.

   Обычный статический CSS-файл, не через Vite/Tailwind-пайплайн (тот
   отдельный бандл, resources/css/app.css, используется только для
   vendor/laravel/framework .../pagination::tailwind — см. комментарий в
   layouts/app.blade.php и INTEGRATION_NOTES.md). Подключается напрямую
   через <link>, с версионированием ?v={filemtime} в самом layout — при
   правке этого файла кэш браузера у пользователей инвалидируется
   автоматически, без ручной правки версии здесь или в шаблоне.

   Все построчные комментарии-обоснования по конкретным правилам ниже
   перенесены из layout без изменений содержания — сам layout больше не
   хранит историю решений по CSS, теперь она здесь.
*/
@font-face {
    font-family: "Literata";
    src: url("../fonts/Literata-Variable.ttf") format("truetype-variations");
    font-style: normal;
    font-weight: 200 900;
    font-display: swap;
}

@font-face {
    font-family: "Literata";
    src: url("../fonts/Literata-Variable-Italic.ttf") format("truetype-variations");
    font-style: italic;
    font-weight: 200 900;
    font-display: swap;
}

@font-face {
    font-family: "Manrope";
    src: url("../fonts/Manrope-Variable.ttf") format("truetype-variations");
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
}

:root {
    color-scheme: dark;

    /* Design system v1.4.0 (docs/PROJECT_CONTEXT.md) — «Тёмная спортивная
       редакция», sportinluxembourg.com. Заменяет унаследованную от
       mozgovyi.com/books-engine светлую «Современную литературную
       редакцию» (значения ниже были: --color-canvas #f8f3ec и т.д.) —
       прямой запрос автора "придумай стиль для сайта и релизуй" после
       темного Hero (v1.3.0, .home-hero--gym, тот же --gym-accent #e2265a,
       теперь основной --color-primary сайта). Собственная палитра, НЕ
       --dj-* набор ниже (тот — чужой бренд mozgovyi.com/DJ RoMan, см.
       AI_RULES.md §1). Семантические имена — источник истины; короткие
       алиасы (--bg/--text/--accent и т.д.) ниже подхватывают эту тему
       автоматически во всех компонентах, которые их используют (222
       использования по файлу на момент правки) — переписывать компоненты
       по отдельности не требуется. */
    --color-canvas: #0e1013;
    --color-surface: #16191d;
    --color-surface-muted: #1e2227;
    --color-ink: #f2f1ef;
    --color-ink-muted: #a6abb1;
    --color-primary: #e2265a;
    --color-primary-rgb: 226, 38, 90;
    --color-primary-hover: #c81e4d;
    --color-primary-soft: #331621;
    --color-gold: #d9a441;
    --color-gold-ink: #e8c27a;
    --color-warning-soft: #332a16;
    --color-warning-ink: var(--color-gold-ink);
    --color-line: rgba(255, 255, 255, 0.12);
    --color-success-soft: #142e22;
    --color-success-ink: #6fcf9e;
    --color-danger-soft: #331419;
    --color-danger-ink: #f0879a;
    --color-danger-hover: #f4a3b2;

    --font-literary: "Manrope", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --font-ui: "Manrope", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    --space-12: 3rem;
    --space-16: 4rem;
    --space-24: 6rem;

    --radius-sm: 0.5rem;
    --radius-control: 0.875rem;
    --radius-card: 1.25rem;
    --radius-feature: 1.75rem;
    --radius-pill: 999px;

    --shadow-raised: 0 16px 45px rgba(58, 35, 40, 0.10);
    --shadow-interactive: 0 20px 55px rgba(58, 35, 40, 0.15);
    --focus-ring: 0 0 0 3px rgba(var(--color-primary-rgb), 0.24);

    --duration-fast: 160ms;
    --duration-base: 240ms;
    --duration-slow: 420ms;
    --ease-standard: cubic-bezier(0.2, 0.7, 0.2, 1);

    --container-max: 80rem;
    --container-reading: 47.5rem;
    --section-space: clamp(4rem, 9vw, 7.5rem);

    /* Обратная совместимость существующих компонентов. */
    --bg: var(--color-canvas);
    --surface: var(--color-surface);
    --border: var(--color-line);
    --text: var(--color-ink);
    --muted: var(--color-ink-muted);
    --accent: var(--color-primary);
    --accent-rgb: var(--color-primary-rgb);
    --accent-dark: var(--color-primary-hover);
    --success-bg: var(--color-success-soft);
    --success-text: var(--color-success-ink);
    --danger-bg: var(--color-danger-soft);
    --danger-text: var(--color-danger-ink);

    /* --dj-* — design tokens редизайна Home/шапки/футера (22.08.26,
       docs/HOME_DESIGN_SPEC_v2.md §5). Префикс отдельный от системы
       --color-* / --accent ("Современная литературная редакция" выше) по
       прямой причине из самого спека: снижает риск случайной регрессии
       остального сайта — тело всех страниц, кроме Home и шапки/футера,
       продолжает использовать --color-canvas/--color-primary как раньше
       (см. открытый вопрос §6 PROJECT_CONTEXT.md — редизайн решено делать
       по частям: шапка/футер + Home сейчас, остальные страницы отдельным
       решением позже, не одним PR). */
    --dj-bg: #050607;
    --dj-bg-soft: #0a0c0e;
    --dj-surface: #0d0f11;
    --dj-surface-hover: #121518;
    --dj-border: rgba(255, 255, 255, .10);

    --dj-text: #f5f5f3;
    --dj-muted: #9b9b9b;
    --dj-accent: #d71920;
    --dj-accent-hover: #ef2028;

    --dj-container: 1440px;
    --dj-pad: clamp(20px, 4vw, 72px);
    --dj-section-y: clamp(72px, 8vw, 128px);

    --dj-radius-sm: 6px;
    --dj-radius-md: 10px;
    --dj-transition: 180ms ease;
}
* { box-sizing: border-box; }
html {
    scroll-behavior: smooth;
    /* Локальные Manrope/Literata подключаются с font-display: swap. На
       короткой странице смена fallback-шрифта может на мгновение изменить
       высоту текста у границы viewport и включить/убрать вертикальную
       прокрутку. Стабильный gutter сохраняет ширину макета в обоих
       состояниях и устраняет горизонтальный рывок страницы. Явный `scroll`
       оставляет совместимый резерв и в Chromium-оболочках, которые вычисляют
       `stable`, но не создают gutter для `overflow-y: auto`. */
    overflow-y: scroll;
    scrollbar-gutter: stable;
    text-size-adjust: 100%;
}
body {
    margin: 0;
    min-width: 20rem;
    font-family: var(--font-ui);
    color: var(--text);
    background: var(--bg);
    font-size: 1rem;
    line-height: 1.65;
    font-synthesis: none;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    /* Sticky footer (24.08.26, баг автора — "в некоторых категориях которые
       не сильно заполнены <html> равен height 425.203px из-за этого футер
       посредине монитора"). Раньше у html/body не было ни одного height/flex
       правила — на страницах с малым количеством контента <body> сжимался
       по высоте контента (например, 425px), футер (@yield('footer'),
       layouts/app.blade.php) шёл сразу за ним в потоке, а не у нижнего края
       экрана: видимый эффект — футер "висит" посреди пустого пространства
       монитора, а не прижат к низу.

       Стандартный flex-column приём: body растягивается минимум на всю
       высоту viewport (min-height: 100vh), становится flex-контейнером по
       колонке. .topbar/.page-header/.container (или full-bleed 'content',
       layouts/app.blade.php) — обычные flex-элементы, растут по контенту.
       .site-footer получает margin-top: auto (public.blade.php, рядом с
       остальными правилами .site-footer) — на длинных страницах ведёт себя
       как раньше (просто margin-top: 2rem, auto не активируется, места нет),
       на коротких — заполняет пустое пространство и прижимает футер к низу
       экрана. Затрагивает только верхнеуровневых прямых потомков body —
       ни сайдбар-грид (.public-layout), ни full-bleed Home (§22 в докблоке
       app.blade.php) не меняют внутреннюю структуру, их содержимое просто
       растёт внутри отведённого flex-элемента как раньше. */
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}
::selection {
    color: var(--color-ink);
    background: var(--color-primary-soft);
}
img,
svg {
    max-width: 100%;
}
a {
    color: var(--accent);
    text-decoration: none;
    text-decoration-thickness: 0.08em;
    text-underline-offset: 0.18em;
}
a:hover { text-decoration: underline; }
a:active { color: var(--accent-dark); }
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
    outline: 3px solid rgba(var(--accent-rgb), 0.72);
    outline-offset: 3px;
}
.topbar {
    position: sticky;
    z-index: 100;
    top: 0;
    min-height: 4.5rem;
    background: rgba(255, 253, 249, 0.94);
    border-bottom: 1px solid var(--border);
    padding: 0.75rem 1.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    box-shadow: 0 1px 0 rgba(58, 35, 40, 0.03);
    backdrop-filter: blur(18px);
}
/* Раньше .brand была текстовой ссылкой ("Books") — правила веса/
   размера шрифта ниже здесь больше не нужны сами по себе (внутри
   теперь <img>, см. разметку .topbar), но оставлены на случай, если
   когда-нибудь рядом с картинкой снова появится текст. display: flex
   — просто хорошая практика для ссылки-контейнера картинки, не даёт
   img съехать по вертикали относительно остального .topbar. */
.topbar .brand {
    display: flex;
    align-items: center;
    font-weight: 700;
    color: var(--text);
    font-size: 1.1rem;
}
.topbar .brand img {
    display: block;
}

/* .brand__logo-frame (v1.4.0 -- пересчитано под РЕАЛЬНЫЙ файл
   sportinluxembourg.com). Комментарий здесь раньше (унаследован при
   переносе скелета из mozgovyi.com, docs/AI_RULES.md §3) описывал
   ДРУГОЙ логотип -- "DJ ROMAN" 2172x724 с ~27%/24% пустых прозрачных
   полей сверху/снизу -- и константы (153x28 рамка, height:58px,
   margin:-16px/-12px) были рассчитаны под те пропорции. Реальный
   public/images/template/logo.png этого проекта -- "SPORT | LUXEMBOURG",
   150x39px, контент занимает почти весь холст (проверено программно:
   alpha-bbox 149x38 из 150x39, пустых полей практически нет) -- старые
   константы ему не подходили (растягивали/обрезали не туда). Упрощено:
   рамка без обрезки/сдвигов, просто высота + пропорциональная ширина.

   Дополнительно (v1.4.0, тёмная тема на весь сайт): исходный PNG --
   чёрный рисунок на прозрачном фоне, на тёмном .topbar (после смены
   палитры :root в этом же файле) стал нечитаем. filter: invert(1)
   переворачивает чёрный в белый, прозрачность не затрагивает -- рабочее
   решение для монохромного лого без альфа-полутонов (пересмотреть, если
   автор заменит файл на цветной -- тогда invert() будет неверно менять
   оттенки, а не только чёрный/белый). */
.brand__logo-frame {
    display: block;
    height: 28px;
    filter: invert(1);
}

.brand__logo-frame img {
    display: block;
    width: auto;
    height: 100%;
}
/* nav сам по себе не был flex — дочерние элементы (ссылки, форма
   logout, .user-menu с его padding-bottom для ховера) выравнивались
   по умолчанию (baseline), из-за чего .user-menu визуально уезжал
   вниз относительно простых ссылок. flex + align-items: center
   выравнивает все прямые дочерние элементы nav по вертикальному
   центру независимо от их внутренних отступов. */
.topbar nav {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}
.topbar nav a {
    margin-left: 0;
    padding: 0.5rem 0.7rem;
    color: var(--muted);
    font-weight: 500;
    line-height: 1.3;
    transition: color var(--duration-fast) var(--ease-standard);
}
.topbar nav a:hover {
    color: var(--accent);
    text-decoration: none;
}
.topbar nav a:focus-visible {
    color: var(--accent);
    text-decoration: none;
}
.topbar nav a.is-active,
.topbar nav a[aria-current="page"] {
    color: var(--accent);
}
.topbar nav form { display: inline; margin-left: 0; }
/* Кнопка мобильного меню (☰) — в разметке идёт сразу после .brand,
   ДО nav (layouts/app.blade.php), скрыта здесь по умолчанию: на
   широких экранах nav показывается как обычно, инлайн. Видна только
   ниже брейкпоинта в медиа-запросе внизу файла (30.07.26, адаптация
   под разные устройства) — тот же принцип минимализма, что и toggle
   HTML-исходника в Quill (content-edit.blade.php, INTEGRATION_NOTES.md
   §124): простой vanilla JS, переключающий один класс, без стороннего
   меню-фреймворка. */
.nav-toggle {
    display: none;
    background: none;
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    padding: 0.55rem;
    line-height: 1;
    color: var(--text);
    cursor: pointer;
}
.nav-toggle svg {
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
}
.nav-toggle:hover {
    border-color: var(--accent);
    color: var(--accent);
}
/* Переключатель языка — настоящий <select> (не выпадающая панель по
   наведению, как .user-menu ниже — автор явно уточнил разницу между
   "выпадающий список" и "выпадающее окно"). Первый <select> в
   проекте, стиль — по образцу input[type="text"] выше, компактнее
   под топбар.

   18.08.26 (фича "языки сайта", возврат в шапку после ADD 'uk') — автор
   отметил, что селект выглядит крупнее и заметнее соседних пунктов меню,
   стоит особняком справа. Причина — нативный <select> в браузере добавляет
   собственные внутренние отступы/рамку/стрелку поверх заданного здесь CSS,
   поэтому визуальный размер оказывается больше, чем у текстовых <a>
   рядом, даже при сопоставимых padding/font-size. Исправлено: паддинги и
   font-size уменьшены до почти минимального читаемого размера, лишний
   margin-left убран (отрывал селект от остального меню отдельным блоком,
   .topbar nav уже даёт gap: var(--space-1) между всеми соседними пунктами
   flex-контейнера, отдельный margin не нужен), border облегчён (тоньше и
   светлее, transparent-фон вместо заливки var(--surface) — меньше
   визуального веса, ближе к обычной ссылке). */
.locale-select {
    /* width: auto/margin-bottom: 0 — переопределяют общее правило
       `input..., select { width: 100%; margin-bottom: 0.5rem; }` (строка
       ~1760): та же ситуация, что уже описана в комментарии .sort-select-row
       ниже — общее правило рассчитано на select ВНУТРИ формы на всю
       ширину, .locale-select сидит в строке топбара среди текстовых ссылок
       и не должен растягиваться на весь доступный flex-контейнер (это и
       была причина визуально "огромного" селекта, 18.08.26 — не паддинги/
       рамка, а именно унаследованный width: 100%). */
    width: auto;
    margin-bottom: 0;
    /* appearance: none + фоновая SVG-стрелка (вместо нативной) — нативная
       стрелка браузера сама по себе резервирует широкий отступ справа
       (~1-1.5rem), который не убрать одним только padding, поэтому select
       физически не мог стать компактным, пока управлял её отрисовкой сам
       браузер. Своя стрелка занимает ровно столько места, сколько задано
       здесь. font-size не переопределяется (было отдельное значение мельче
       остального меню) — наследует размер текста топбара, тот же размер,
       что у соседних <a>, автор явно попросил "как все в меню". */
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a7a72' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.35rem center;
    padding: 0.3rem 1.3rem 0.3rem 0.4rem;
    border: 1px solid transparent;
    border-radius: 6px;
    font-weight: 600;
    font-family: inherit;
    line-height: 1.3;
    color: var(--muted);
    background-color: transparent;
    cursor: pointer;
}
.locale-select:hover {
    color: var(--accent);
    border-color: var(--accent);
}
.locale-select:focus-visible {
    color: var(--accent);
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}
/* Вкладки языка контента (18.08.26, фича "языки сайта", многоязычный блог/
   блоки/настройки) — общий компонент (см. public/js/lang-tabs.js),
   подключаемый одинаково в admin/posts, admin/blocks, admin/settings.
   Заменяет прежнюю двухколоночную раскладку .settings-columns (годилась
   для двух языков рядом, для трёх стала бы тесной) — прямой запрос автора:
   "вкладки сверху с названием языка". */
.lang-tabs-nav {
    display: flex;
    gap: 0.35rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--border);
}
.lang-tab-button {
    padding: 0.5rem 1rem;
    border: none;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    background: transparent;
    color: var(--muted);
    font-weight: 600;
    font-size: 0.85rem;
    cursor: pointer;
    margin-bottom: -1px;
}
.lang-tab-button:hover {
    color: var(--accent);
}
.lang-tab-button.is-active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
/* Сортировка каталога /books (02.08.26) — .sort-select-row переопределяет
   width:100%/margin-bottom из общего правила select выше (строка ~329,
   рассчитано на select на всю ширину формы), здесь select должен сидеть
   рядом с текстовой подписью в одну строку, как .locale-select в топбаре
   (тот же образец: компактный select, не форма). */
.sort-select-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
}
.sort-select-row select {
    width: auto;
    margin-bottom: 0;
    padding: 0.3rem 0.5rem;
    font-size: 0.9rem;
}
.topbar nav form button {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-weight: 500;
    color: var(--muted);
    cursor: pointer;
}
.topbar nav form button:hover { color: var(--accent); }

/* Значки "Избранное"/"Библиотека" в топбаре (02.08.26, готовые символы ♥/🕮,
   не SVG) — margin-left уже даёт общее правило .topbar nav a (тот же
   отступ, что у "Все книги" и т.д.), здесь только цвет/размер/ховер.
   font-size крупнее текста ссылок рядом — иначе символы визуально мельче
   соседних слов. */
/* SVG вместо текстовых символов (02.08.26, вторая правка — см. комментарий
   в layouts/app.blade.php): иконки красятся через stroke/fill родителя
   (currentColor), а не font-size/color, как раньше для текстовых ♥/🕮. */
.topbar-icon-link {
    display: inline-flex;
    align-items: center;
    color: var(--muted);
}
.topbar-icon-link:hover {
    color: var(--accent);
}
.topbar-icon-link .heart-icon {
    stroke: currentColor;
}
.topbar-icon-link .book-icon {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linejoin: round;
    stroke-linecap: round;
}
/* 21.08.26, прямая жалоба автора: эмодзи 🐇 в шапке "смотрит спиной" на
   баланс справа от него — зеркалим по горизонтали, юникод не даёт готового
   зеркального варианта символа. */
.rabbit-emoji {
    display: inline-block;
    transform: scaleX(-1);
}
.user-menu {
    display: inline-block;
    position: relative;
    margin-left: 0;
}
/* Заполняет зазор до выпадашки, чтобы наведение не срывалось между
   триггером и .user-menu-dropdown — раньше это делал padding-bottom
   прямо на .user-menu, но это добавляло блоку лишнюю высоту и
   сбивало вертикальное центрирование по .topbar nav (align-items:
   center считал центром центр раздутого блока, а не текста триггера).
   ::after — невидимая полоса, позиционированная absolute (не влияет
   на высоту .user-menu в потоке), но остаётся внутри .user-menu,
   поэтому наведение на неё не сбрасывает :hover. */
.user-menu::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    height: 0.75rem;
}
.user-menu .user-menu-trigger {
    /* Перебивает .topbar nav a { margin-left: 1.25rem } — иначе
       отступ дублируется (он уже задан самим .user-menu). */
    margin-left: 0;
    color: var(--muted);
    font-weight: 500;
}
.user-menu:hover .user-menu-trigger,
.user-menu .user-menu-trigger:hover {
    color: var(--accent);
    text-decoration: none;
}
.user-menu-dropdown {
    display: none;
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 0;
    min-width: 180px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
    padding: 0.5rem 0;
    z-index: 20;
}
.user-menu:hover .user-menu-dropdown {
    display: block;
}
.user-menu:focus-within .user-menu-dropdown {
    display: block;
}
.user-menu-dropdown .user-menu-name {
    display: block;
    padding: 0.4rem 0.9rem;
    margin: 0;
    font-weight: 600;
    color: var(--text);
}
/* .user-menu .user-menu-dropdown ... (два класса) — специфичнее
   .topbar nav a/.topbar nav form выше, иначе те правила (margin-left,
   display: inline) перебивают вёрстку пунктов меню. */
.user-menu .user-menu-dropdown a,
.user-menu .user-menu-dropdown form button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.4rem 0.9rem;
    margin: 0;
    color: var(--muted);
    font-weight: 500;
    background: none;
    border: none;
    font: inherit;
    cursor: pointer;
}
.user-menu .user-menu-dropdown a:hover,
.user-menu .user-menu-dropdown form button:hover {
    color: var(--accent);
    text-decoration: none;
    background: var(--bg, #f5f5f7);
}
.user-menu .user-menu-dropdown form {
    display: block;
    margin: 0;
}
.container {
    width: min(calc(100% - 2rem), var(--container-max));
    max-width: none;
    margin: 0 auto;
    padding: var(--space-6) 0;
}
/* Заголовок сайта + подзаголовок на главной (books/index.blade.php,
   секция page_header) — 26.07.26, прямой запрос автора: вывести из
   .container. Рендерится ДО .container (см. разметку ниже), обёрнут
   в этот класс той же ширины/центрирования блока (max-width: 1200px,
   margin: 0 auto), что и остальной контент, но отдельным блоком, не
   внутри .public-layout/.public-main. text-align: center — сам текст
   заголовка/подзаголовка тоже по центру (тот же приём, что у
   .breadcrumbs/.reader-book-title), правка по итогам проверки (первая
   версия без обёртки-div, класс не был ни на чём навешан, поэтому
   центрирование не сработало). Обёртка выводится условно, только
   когда секция реально определена и не пуста — см. проверку прямо в
   разметке layouts/app.blade.php, подробное обоснование см.
   INTEGRATION_NOTES.md §94 (не повторяется здесь словами, чтобы снова
   случайно не задеть синтаксис шаблонизатора — см. предысторию там
   же). На страницах, не определяющих секцию, блок не рендерится
   вообще, не пустой div с лишним padding. */
.page-header {
    width: min(calc(100% - 2rem), var(--container-max));
    max-width: none;
    margin: 0 auto;
    padding: var(--space-8) 0 0;
    text-align: center;
}
/* Системные сообщения — отдельный компонент, не pill-статус сущности.
   Смысл различим по тексту, символу и цвету одновременно. */
.notice,
.status,
.status-error,
.alert {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    width: 100%;
    margin: 0 0 var(--space-4);
    padding: 0.85rem 1rem;
    border: 1px solid transparent;
    border-radius: var(--radius-control);
    font-weight: 600;
    line-height: 1.5;
    box-shadow: 0 8px 24px rgba(58, 35, 40, 0.05);
}

.notice::before,
.status::before,
.status-error::before,
.alert::before {
    flex: 0 0 auto;
    font-weight: 800;
}

.notice-info {
    color: var(--accent-dark);
    background: var(--color-primary-soft);
    border-color: rgba(var(--accent-rgb), 0.2);
}
.notice-info::before { content: "i"; }

.notice-success,
.status {
    color: var(--success-text);
    background: var(--success-bg);
    border-color: rgba(47, 107, 80, 0.22);
}
.notice-success::before,
.status::before { content: "\2713"; }

.notice-warning {
    color: var(--color-warning-ink);
    background: var(--color-warning-soft);
    border-color: rgba(169, 120, 50, 0.24);
}
.notice-warning::before { content: "!"; }

.notice-danger,
.status-error,
.alert-danger {
    color: var(--danger-text);
    background: var(--danger-bg);
    border-color: rgba(155, 38, 59, 0.22);
}
.notice-danger::before,
.status-error::before,
.alert-danger::before { content: "!"; }

/* Пустое и загрузочное состояния готовы для всех разделов и не требуют
   собственной палитры в каждом шаблоне. */
.empty-state {
    display: grid;
    place-items: center;
    min-height: 9rem;
    margin: var(--space-4) 0;
    padding: var(--space-8);
    color: var(--muted);
    background: rgba(241, 232, 223, 0.58);
    border: 1px dashed var(--border);
    border-radius: var(--radius-card);
    text-align: center;
}

.empty-state--compact {
    min-height: 0;
    padding: var(--space-4);
    border-radius: var(--radius-control);
}

.loading-state {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    color: var(--muted);
}

.loading-state::before {
    content: "";
    width: 1rem;
    height: 1rem;
    border: 2px solid rgba(var(--accent-rgb), 0.18);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: button-loading-spin 700ms linear infinite;
}

.skeleton {
    position: relative;
    overflow: hidden;
    color: transparent;
    background: var(--color-surface-muted);
    border-radius: var(--radius-sm);
}

.skeleton::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, transparent 20%, rgba(255, 253, 249, 0.72) 48%, transparent 76%);
    transform: translateX(-100%);
    animation: skeleton-shimmer 1.4s var(--ease-standard) infinite;
}

.skeleton-text { min-height: 1em; }
.skeleton-media { aspect-ratio: 2 / 3; }

@keyframes skeleton-shimmer {
    to { transform: translateX(100%); }
}
.card {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    padding: clamp(1.125rem, 2vw, 1.5rem);
    margin-bottom: var(--space-6);
    box-shadow: 0 1px 0 rgba(58, 35, 40, 0.04);
    /* Админ-таблицы (.admin-table, всегда напрямую внутри .card — см.
       admin/users|books|comments|posts|pages|blocks/index.blade.php)
       ничем не ограничены по ширине столбцов — на узком экране это
       раньше давало горизонтальную прокрутку всей страницы, не только
       карточки. overflow-x: auto здесь ничего не меняет визуально,
       пока контент карточки помещается (подавляющее большинство
       .card — формы/текст, не таблицы); включается только когда
       реально не помещается, и тогда прокручивается сама карточка,
       а не вся страница (30.07.26, адаптация под разные устройства). */
    overflow-x: auto;
}

/*
    21.08.26, прямая жалоба автора на /authors/{id}/edit: несколько .card
    подряд (фото / псевдоним+биография / отображаемое имя) выглядели как
    отдельные независимые блоки, хотя физически это один <form> с одной
    кнопкой "Сохранить" — рядом на странице ещё одна карточка (Email) с
    СВОЕЙ отдельной формой и своей кнопкой, тоже подписанной "Сохранить",
    и визуально не было понятно, какая кнопка что сохраняет.
    .card-group — общая рамка вокруг нескольких .card-group-item (те же
    внутренние отступы, что у обычной .card, но без собственной границы/
    тени/нижнего отступа — граница и тень теперь только у внешней группы),
    с разделительной линией между item'ами и общей кнопкой "Сохранить"
    внизу группы, вне последнего item'а. Первое применение — второй
    сценарий (email-карточка) осознанно НЕ подведён под этот же класс,
    остаётся обычной .card, так как она правда самостоятельна (свой
    <form>, своё действие) — переиспользовать здесь было бы неверно.
*/
.card-group {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    margin-bottom: var(--space-6);
    box-shadow: 0 1px 0 rgba(58, 35, 40, 0.04);
    overflow: hidden;
}

.card-group-item {
    padding: clamp(1.125rem, 2vw, 1.5rem);
    border-bottom: 1px solid var(--border);
}

.card-group-item:last-child {
    border-bottom: none;
}

.card-group-actions {
    padding: clamp(1.125rem, 2vw, 1.5rem);
    border-top: 1px solid var(--border);
    background: rgba(58, 35, 40, 0.015);
}

/* Варианты карточек дизайн-системы добавляются к базовому .card только
   там, где нужна соответствующая роль. Поэтому административные таблицы
   сохраняют собственную горизонтальную прокрутку, а карточки книг и hero
   могут получать выразительное поведение без глобальных побочных эффектов. */
.card-interactive {
    isolation: isolate;
    transition:
        transform var(--duration-base) var(--ease-standard),
        border-color var(--duration-fast) var(--ease-standard),
        box-shadow var(--duration-base) var(--ease-standard);
}

.card-interactive:focus-within {
    border-color: rgba(var(--accent-rgb), 0.32);
    box-shadow: var(--shadow-interactive);
}

.card-media {
    overflow: hidden;
    border-radius: calc(var(--radius-card) - var(--space-2));
}

.card-media img {
    display: block;
    width: 100%;
    transition: transform var(--duration-slow) var(--ease-standard);
}

@media (hover: hover) and (pointer: fine) {
    .card-interactive:hover {
        border-color: rgba(var(--accent-rgb), 0.28);
        box-shadow: var(--shadow-interactive);
        transform: translateY(-4px);
    }

    .card-interactive:hover .card-media img {
        transform: scale(1.02);
    }
}

.card-featured {
    isolation: isolate;
    overflow: hidden;
    border-color: rgba(var(--accent-rgb), 0.18);
    border-radius: var(--radius-feature);
    background:
        linear-gradient(135deg, rgba(255, 253, 249, 0.98), rgba(241, 226, 229, 0.76));
    box-shadow: var(--shadow-raised);
}

.card-featured::before {
    content: "";
    position: absolute;
    z-index: 0;
    top: clamp(-8rem, -10vw, -4rem);
    right: clamp(-7rem, -8vw, -3rem);
    width: clamp(11rem, 24vw, 19rem);
    aspect-ratio: 1;
    border: 1px solid rgba(var(--accent-rgb), 0.14);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(var(--accent-rgb), 0.11), transparent 68%);
    pointer-events: none;
}

.card-featured > * {
    position: relative;
    z-index: 1;
}

/* Первый экран главной: редакционная композиция строится из уже выбранной
   сервером книги и не вводит отдельную палитру или локальные кнопки. */
.home-page-heading {
    margin: 0 0 var(--space-6);
    padding: clamp(var(--space-2), 1.2vw, var(--space-4))
        clamp(var(--space-2), 1.5vw, var(--space-4));
    text-align: center;
}

.home-page-heading-accent {
    display: block;
    width: clamp(3.5rem, 7vw, 5.5rem);
    height: 2px;
    margin: var(--space-3) auto;
    border-radius: var(--radius-pill);
    background: linear-gradient(
        90deg,
        var(--color-gold) 0%,
        var(--color-primary) 100%
    );
}

.home-page-heading-copy p {
    margin: 0 0 var(--space-1);
    color: var(--color-gold-ink);
    font-size: clamp(0.68rem, 0.8vw, 0.78rem);
    font-weight: 750;
    letter-spacing: 0.13em;
    line-height: 1.4;
    text-transform: uppercase;
}

.home-page-heading h1 {
    max-width: 52rem;
    margin: 0 auto;
    color: var(--text);
    font-family: var(--font-literary);
    font-size: clamp(1.35rem, 2.25vw, 2.05rem);
    font-weight: 620;
    letter-spacing: -0.025em;
    line-height: 1.25;
    text-wrap: balance;
}

.home-hero {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(15rem, 0.8fr);
    align-items: center;
    gap: clamp(var(--space-6), 3.5vw, var(--space-12));
    min-height: clamp(29rem, calc(100vh - 8.5rem), 35rem);
    padding: clamp(var(--space-6), 3vw, 2.5rem);
}

.home-hero-copy {
    max-width: 47rem;
}

.home-hero-eyebrow,
.home-hero-featured-label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-4);
    color: var(--color-gold-ink);
    font-size: 0.75rem;
    font-weight: 750;
    letter-spacing: 0.08em;
    line-height: 1.35;
    text-transform: uppercase;
}

.home-hero-eyebrow::before {
    content: "";
    width: 2.5rem;
    height: 1px;
    background: var(--color-gold);
}

.home-hero-title {
    max-width: 12ch;
    margin: 0 0 var(--space-6);
    color: var(--text);
    font-family: var(--font-literary);
    font-weight: 700;
    font-size: clamp(2.4rem, 4.7vw, 4.75rem);
    line-height: 0.98;
    text-wrap: balance;
}

.home-hero-lead {
    max-width: 40rem;
    margin: 0;
    color: var(--muted);
    font-size: clamp(1.025rem, 1.4vw, 1.2rem);
    line-height: 1.65;
}

.home-hero-actions {
    margin: var(--space-6) 0 var(--space-4);
}

.home-hero-author {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    color: var(--text);
    font-weight: 700;
}

.home-hero-author:hover,
.home-hero-author:focus-visible {
    color: var(--accent);
    text-decoration: none;
}

.home-hero-author-action {
    color: var(--muted);
    font-size: 0.875rem;
    font-weight: 600;
}

.home-hero-featured {
    display: grid;
    justify-items: center;
    gap: var(--space-4);
    margin: 0;
    text-align: center;
}

.home-hero-cover {
    position: relative;
    display: block;
    width: min(100%, 12.75rem);
    aspect-ratio: 2 / 3;
    border-radius: 0.6rem 1rem 1rem 0.6rem;
    background: var(--color-surface-muted);
    box-shadow: 0 24px 55px rgba(58, 35, 40, 0.25);
    transform: rotate(1.2deg);
    transition:
        transform var(--duration-slow) var(--ease-standard),
        box-shadow var(--duration-slow) var(--ease-standard);
}

.home-hero-cover::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset: 0.7rem -0.65rem -0.7rem 0.65rem;
    border: 1px solid rgba(var(--accent-rgb), 0.16);
    border-radius: inherit;
}

.home-hero-cover img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
}

@media (hover: hover) and (pointer: fine) {
    .home-hero-cover:hover {
        transform: rotate(0deg) translateY(-4px);
        box-shadow: 0 30px 68px rgba(58, 35, 40, 0.3);
    }
}

.home-hero-featured figcaption {
    display: grid;
    justify-items: center;
    gap: var(--space-1);
    max-width: 22rem;
}

.home-hero-featured-label {
    margin-bottom: var(--space-1);
}

.home-hero-featured figcaption strong {
    font-family: var(--font-literary);
    font-size: 1.25rem;
    line-height: 1.25;
}

.home-hero-featured figcaption > span:not(.home-hero-featured-label) {
    color: var(--muted);
    font-size: 0.875rem;
}

.home-hero-featured-description {
    display: -webkit-box;
    margin-top: var(--space-2);
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-height: 1.5;
}

.home-section {
    margin: clamp(var(--space-12), 6vw, var(--space-16)) 0;
}

.home-section-heading {
    max-width: 48rem;
    margin-bottom: var(--space-6);
}

.home-section-heading h2 {
    margin-bottom: var(--space-3);
}

.home-section-heading > p:last-child {
    max-width: 42rem;
    margin: 0;
    color: var(--muted);
    font-size: 1.0625rem;
}

.home-section-kicker {
    margin: 0 0 var(--space-2);
    color: var(--color-gold-ink);
    font-size: 0.75rem;
    font-weight: 750;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.home-release {
    display: grid;
    grid-template-columns: minmax(8.5rem, 10.5rem) minmax(0, 1fr);
    gap: clamp(var(--space-6), 4vw, var(--space-12));
    align-items: center;
    padding: clamp(var(--space-6), 4vw, var(--space-12));
}

.home-release-cover {
    display: block;
    aspect-ratio: 2 / 3;
    overflow: hidden;
    border-radius: 0.5rem 0.8rem 0.8rem 0.5rem;
    background: var(--color-surface-muted);
    box-shadow: var(--shadow-raised);
    transition:
        transform var(--duration-base) var(--ease-standard),
        box-shadow var(--duration-base) var(--ease-standard);
}

.home-release-cover img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

@media (hover: hover) and (pointer: fine) {
    .home-release-cover:hover {
        transform: translateY(-4px);
        box-shadow: var(--shadow-interactive);
    }
}

.home-release-content {
    min-width: 0;
}

.home-release-meta,
.home-release-stats {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.home-release-description {
    max-width: 50rem;
    margin: var(--space-6) 0 var(--space-4);
    color: var(--text);
    font-size: 1.0625rem;
    line-height: 1.7;
}

.home-release-stats {
    color: var(--muted);
    font-size: 0.875rem;
    font-weight: 600;
}

.home-release-stats > * + *::before {
    content: "·";
    margin-right: var(--space-2);
    color: var(--color-gold);
}

.home-release-actions {
    margin: var(--space-6) 0 0;
}

.home-section-heading-row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-6);
    max-width: none;
}

.home-section-heading-row > div {
    max-width: 48rem;
}

.home-section-link {
    flex: 0 0 auto;
    padding: var(--space-2) 0;
    font-weight: 750;
}

.home-book-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 13.5rem), 18rem));
    justify-content: center;
    gap: var(--space-6);
}

.home-book-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    margin: 0;
    padding: 0;
    overflow: hidden;
}

.home-book-card-cover {
    aspect-ratio: 2 / 3;
    border-radius: 0;
    background: var(--color-surface-muted);
}

.home-book-card-cover img {
    height: 100%;
    object-fit: cover;
}

.home-book-card-body {
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: flex-start;
    padding: var(--space-6);
}

.home-book-card-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.home-book-card-meta .tag:nth-of-type(n + 3) {
    display: none;
}

.home-book-card h3 {
    margin-bottom: var(--space-2);
    font-size: 1.25rem;
    line-height: 1.25;
}

.home-book-card h3 a {
    color: var(--text);
}

.home-book-card h3 a:hover,
.home-book-card h3 a:focus-visible {
    color: var(--accent);
}

.home-book-card-author {
    margin: 0 0 var(--space-3);
    color: var(--muted);
    font-size: 0.875rem;
}

.book-card-author,
.catalog-book-authors {
    font-family: var(--font-literary);
    font-style: italic;
}

.home-book-card-rating {
    min-height: 1.5rem;
    margin-bottom: var(--space-4);
    font-size: 0.875rem;
}

.home-book-card-action {
    width: 100%;
    margin-top: auto;
}

.home-mood-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-4);
}

.home-mood-card {
    position: relative;
    display: flex;
    min-height: 15rem;
    flex-direction: column;
    padding: clamp(var(--space-6), 3vw, var(--space-8));
    overflow: hidden;
    color: var(--text);
    background: linear-gradient(145deg, var(--surface), var(--color-primary-soft));
    border: 1px solid rgba(var(--accent-rgb), 0.14);
    border-radius: var(--radius-card);
    transition:
        transform var(--duration-base) var(--ease-standard),
        border-color var(--duration-fast) var(--ease-standard),
        box-shadow var(--duration-base) var(--ease-standard);
}

.home-mood-card:nth-child(3n + 2) {
    background: linear-gradient(145deg, var(--surface), var(--color-warning-soft));
    border-color: rgba(169, 120, 50, 0.18);
}

.home-mood-card:nth-child(3n) {
    background: linear-gradient(145deg, var(--surface), var(--color-surface-muted));
    border-color: var(--border);
}

.home-mood-card::after {
    content: "";
    position: absolute;
    right: -3.5rem;
    bottom: -4.5rem;
    width: 10rem;
    aspect-ratio: 1;
    border: 1px solid rgba(var(--accent-rgb), 0.12);
    border-radius: 50%;
}

.home-mood-number {
    margin-bottom: auto;
    color: var(--color-gold-ink);
    font-family: var(--font-literary);
    font-size: 0.875rem;
    font-style: italic;
}

.home-mood-card h3 {
    position: relative;
    z-index: 1;
    margin: var(--space-8) 0 var(--space-3);
    font-size: clamp(1.25rem, 2vw, 1.55rem);
}

.home-mood-card p {
    position: relative;
    z-index: 1;
    margin: 0 0 var(--space-6);
    color: var(--muted);
    font-size: 0.9rem;
    line-height: 1.6;
}

.home-mood-count {
    position: relative;
    z-index: 1;
    color: var(--accent);
    font-size: 0.8125rem;
    font-weight: 750;
}

@media (hover: hover) and (pointer: fine) {
    .home-mood-card:hover {
        color: var(--text);
        border-color: rgba(var(--accent-rgb), 0.3);
        box-shadow: var(--shadow-interactive);
        text-decoration: none;
        transform: translateY(-4px);
    }
}

.home-mood-card:focus-visible {
    color: var(--text);
    text-decoration: none;
}

.home-search-panel {
    display: grid;
    grid-template-columns: minmax(15rem, 0.8fr) minmax(18rem, 1.2fr);
    align-items: center;
    gap: var(--space-6) var(--space-12);
    padding: clamp(var(--space-6), 4vw, var(--space-12));
    background: var(--color-surface-muted);
}

.home-search-panel h2 {
    margin-bottom: var(--space-2);
}

.home-search-panel p {
    margin: 0;
    color: var(--muted);
}

.home-search-panel .search-form {
    margin: 0;
}

.home-search-actions {
    grid-column: 2;
    margin: 0;
}

.home-author-spotlight {
    display: grid;
    grid-template-columns: minmax(11rem, 14rem) minmax(0, 1fr);
    align-items: center;
    gap: clamp(var(--space-8), 5vw, var(--space-16));
    padding: clamp(var(--space-8), 5vw, var(--space-16));
}

.home-author-photo {
    aspect-ratio: 1;
    overflow: hidden;
    border: 1px solid rgba(var(--accent-rgb), 0.16);
    border-radius: 48% 52% 46% 54% / 52% 44% 56% 48%;
    background: var(--color-surface-muted);
    box-shadow: var(--shadow-raised);
}

.home-author-photo img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.home-author-content h2 {
    margin-bottom: var(--space-4);
}

.home-author-biography {
    max-width: 48rem;
    margin: 0 0 var(--space-6);
    color: var(--muted);
    font-size: 1.0625rem;
    line-height: 1.75;
}

.home-workshop-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-6);
}

.home-workshop-card {
    display: grid;
    grid-template-columns: minmax(6.5rem, 8rem) minmax(0, 1fr);
    gap: var(--space-5, 1.25rem);
    margin: 0;
    padding: var(--space-4);
}

.home-workshop-cover {
    align-self: start;
    aspect-ratio: 2 / 3;
    background: var(--color-surface-muted);
}

.home-workshop-cover img {
    height: 100%;
    object-fit: cover;
}

.home-workshop-card-content {
    display: flex;
    min-width: 0;
    flex-direction: column;
    align-items: flex-start;
}

.home-workshop-card h3 {
    margin: var(--space-3) 0 var(--space-2);
    font-size: 1.125rem;
}

.home-workshop-card h3 a {
    color: var(--text);
}

.home-workshop-card-content > .muted {
    margin: 0 0 var(--space-3);
    font-size: 0.8125rem;
}

.home-workshop-stats {
    display: grid;
    gap: var(--space-1);
    margin-bottom: var(--space-4);
    color: var(--muted);
    font-size: 0.8125rem;
    font-weight: 600;
}

.home-workshop-action {
    width: 100%;
    margin-top: auto;
}

.home-lower-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(17rem, 0.8fr);
    gap: var(--space-6);
    align-items: stretch;
}

.home-lower-grid--community-only {
    grid-template-columns: minmax(0, 1fr);
}

.home-post-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-6);
}

.home-post-card {
    display: flex;
    flex-direction: column;
    margin: 0;
}

.home-post-card time {
    color: var(--color-gold-ink);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.home-post-card h3 {
    margin: var(--space-4) 0 var(--space-3);
}

.home-post-card h3 a {
    color: var(--text);
}

.home-post-card p {
    margin: 0 0 var(--space-6);
    color: var(--muted);
}

.home-post-link {
    margin-top: auto;
    font-weight: 750;
}

.home-community-panel {
    display: flex;
    min-height: 100%;
    flex-direction: column;
    align-items: flex-start;
    margin: 0;
    padding: clamp(var(--space-8), 4vw, var(--space-12));
}

.home-community-panel h2 {
    margin-bottom: var(--space-4);
}

.home-community-panel > p:not(.home-section-kicker) {
    margin: 0 0 var(--space-8);
    color: var(--muted);
}

.home-community-panel .button {
    margin-top: auto;
}

/* Публичная страница автора использует ту же редакционную систему, что и
   главная, но сохраняет полную биографию и библиографию. */
.author-profile-hero {
    display: grid;
    grid-template-columns: minmax(12rem, 17rem) minmax(0, 1fr);
    align-items: center;
    gap: clamp(var(--space-8), 6vw, var(--space-16));
    padding: clamp(var(--space-8), 5vw, var(--space-16));
}

.author-profile-photo {
    aspect-ratio: 1;
    overflow: hidden;
    border: 1px solid rgba(var(--accent-rgb), 0.16);
    border-radius: 48% 52% 46% 54% / 52% 44% 56% 48%;
    background: var(--color-surface-muted);
    box-shadow: var(--shadow-raised);
}

.author-profile-photo img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.author-profile-intro h1 {
    max-width: 14ch;
    margin-bottom: var(--space-6);
}

.author-profile-genres {
    margin-bottom: var(--space-6);
}

.author-profile-actions {
    margin: 0 0 var(--space-4);
}

.author-profile-actions .rabbit-award-form {
    margin: 0;
}

.author-profile-member-since {
    margin: 0;
    color: var(--muted);
    font-size: 0.8125rem;
}

.author-private-meta {
    flex-wrap: wrap;
    margin-top: var(--space-6);
    margin-bottom: 0;
    font-size: 0.875rem;
}

.author-biography-section {
    width: 100%;
    margin: clamp(var(--space-12), 7vw, var(--space-16)) auto;
    padding: clamp(var(--space-8), 5vw, var(--space-16));
    background: var(--color-surface);
}

.author-biography-section .home-section-heading,
.author-biography {
    width: min(100%, var(--container-reading));
    margin-inline: auto;
}

.author-biography-section .home-section-heading {
    margin-bottom: var(--space-6);
}

.author-biography {
    color: var(--text);
    font-family: var(--font-literary);
    font-size: 1.0625rem;
    line-height: 1.85;
}

.author-biography > :first-child { margin-top: 0; }
.author-biography > :last-child { margin-bottom: 0; }
.author-biography p { margin: 0 0 1.25em; }
.author-biography h2,
.author-biography h3 { margin-top: 1.8em; }

.author-recommended-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-6);
}

.author-recommended-card {
    display: grid;
    grid-template-columns: minmax(8rem, 11rem) minmax(0, 1fr);
    align-items: center;
    gap: var(--space-6);
    margin: 0;
    overflow: hidden;
}

.author-recommended-cover {
    aspect-ratio: 2 / 3;
    background: var(--color-surface-muted);
}

.author-recommended-cover img,
.author-book-cover img {
    height: 100%;
    object-fit: cover;
}

.author-recommended-card h3 {
    margin-bottom: var(--space-6);
}

.author-recommended-card h3 a,
.author-book-card h3 a {
    color: var(--text);
}

.author-book-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-6);
}

.author-book-card {
    display: flex;
    height: 100%;
    flex-direction: column;
    margin: 0;
    padding: 0;
    overflow: hidden;
}

.author-book-cover {
    display: block;
    width: 100%;
    flex: 0 0 auto;
    aspect-ratio: 2 / 3;
    border-radius: 0;
    background: var(--color-surface-muted);
}

.author-book-card h3 {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 4.75rem;
    padding: var(--space-4) var(--space-3);
    margin: 0;
    border-top: 1px solid var(--border);
    font-family: var(--font-literary);
    font-size: 1.1rem;
    line-height: 1.35;
    text-align: center;
    text-wrap: balance;
}

.author-follow-panel {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-6);
    padding: var(--space-8);
    background: var(--color-surface-muted);
}

.author-follow-panel h2,
.author-follow-panel .actions {
    margin: 0;
}

/* Каталог — единый редакционный экран поиска, фильтрации и выбора книги. */
.catalog-page-heading {
    max-width: 52rem;
    margin-inline: auto;
    text-align: center;
}

.catalog-page-heading h1 {
    margin-bottom: var(--space-4);
}

.catalog-page-heading > p:last-child {
    max-width: 46rem;
    margin: 0 auto;
    color: var(--muted);
    font-size: 1.0625rem;
    line-height: 1.65;
}

.catalog-controls {
    margin-bottom: var(--space-8);
    padding: var(--space-6);
    background: var(--color-surface-muted);
}

.catalog-search-control {
    margin-bottom: var(--space-5);
}

.catalog-filter-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-4);
}

.catalog-filter-grid label {
    display: grid;
    gap: var(--space-2);
    color: var(--muted);
    font-family: var(--font-ui);
    font-size: 0.8125rem;
    font-weight: 700;
}

.catalog-filter-grid select {
    width: 100%;
    margin: 0;
    color: var(--text);
    background: var(--surface);
}

.catalog-control-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-top: var(--space-5);
    color: var(--muted);
    font-size: 0.875rem;
}

.catalog-author-action {
    justify-content: flex-end;
    margin-top: calc(var(--space-4) * -1);
}

.book-list.catalog-book-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    align-items: stretch;
}

.catalog-book-card {
    gap: 0;
    padding: 0;
    overflow: hidden;
    text-align: left;
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
}

.catalog-book-cover,
.catalog-book-cover .book-cover-frame {
    width: 100%;
    border: 0;
    border-radius: 0;
}

.catalog-book-cover .book-cover-thumb {
    aspect-ratio: 2 / 3;
}

.catalog-book-content {
    flex: 1;
    gap: var(--space-3);
    padding: var(--space-5);
}

.book-list-item-body.catalog-book-content h2,
.book-list-item-body.catalog-book-content h3 {
    margin: var(--space-2) 0 0;
    font-family: var(--font-literary);
    font-size: clamp(1.3rem, 1.65vw, 1.48rem);
    font-weight: 720;
    line-height: 1.25;
    text-align: center;
    text-wrap: balance;
}

.catalog-book-content h2 a,
.catalog-book-content h3 a {
    color: var(--text);
}

.catalog-book-statuses,
.catalog-book-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.catalog-book-card .catalog-book-statuses {
    justify-content: center;
}

.catalog-book-authors {
    margin: 0;
    color: var(--muted);
    font-size: 0.875rem;
    text-align: center;
}

.catalog-book-rating {
    margin-top: auto;
    text-align: center;
}

.catalog-book-actions {
    justify-content: space-between;
    padding-top: var(--space-3);
    border-top: 1px solid var(--border);
}

.catalog-book-read-action {
    flex: 1 1 9rem;
}

.catalog-book-actions .continue-reading:empty {
    display: none;
}

.catalog-book-actions .continue-reading a {
    font-size: 0.8125rem;
    font-weight: 700;
}

.page-document {
    width: min(100%, 54rem);
    margin-inline: auto;
    padding: clamp(var(--space-8), 6vw, var(--space-16));
}

.page-document h1 {
    max-width: 18ch;
}

.page-document .page-body {
    font-family: var(--font-literary);
    font-size: 1.0625rem;
    line-height: 1.85;
}

.page-document .page-body > :first-child {
    margin-top: 0;
}

.page-document .page-body > :last-child {
    margin-bottom: 0;
}

.page-document .page-body h2 {
    margin-top: 1.8em;
    font-size: clamp(1.3rem, 2vw, 1.75rem);
}

.page-document .page-body a {
    font-family: var(--font-ui);
    font-weight: 700;
}
h1,
h2,
h3,
h4 {
    margin-top: 0;
    color: var(--text);
    font-family: var(--font-literary);
    font-weight: 650;
    text-wrap: balance;
}
h1 {
    margin-bottom: var(--space-6);
    font-size: clamp(2rem, 4vw, 3.75rem);
    line-height: 1.02;
    letter-spacing: -0.035em;
}
h2 {
    margin-bottom: var(--space-4);
    font-size: clamp(1.5rem, 2.6vw, 2.5rem);
    line-height: 1.08;
    letter-spacing: -0.025em;
    text-transform: none;
}
h3 {
    margin-bottom: var(--space-3);
    font-size: clamp(1.2rem, 1.7vw, 1.625rem);
    line-height: 1.2;
}
input[type="text"], input[type="number"], input[type="email"], input[type="password"],
input[type="file"], input[type="datetime-local"], input[type="url"], textarea, select {
    width: 100%;
    padding: 0.65rem 0.8rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    font-size: 0.95rem;
    font-family: inherit;
    margin-bottom: 0.5rem;
    background: var(--surface);
    color: var(--text);
    transition:
        border-color var(--duration-fast) var(--ease-standard),
        box-shadow var(--duration-fast) var(--ease-standard),
        background var(--duration-fast) var(--ease-standard);
}
textarea { min-height: 300px; }
/* Раньше фокус на полях ввода не был виден вообще (браузерный
   дефолтный outline нигде не сбрасывался и не заменялся) — добавлен
   явный focus-ring тем же акцентным цветом, тот же приём, что уже
   применён к .locale-select ниже, только теперь общий для всех
   полей формы на сайте, не только для одного select. */
input:focus, textarea:focus, select:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}
button,
.button,
.button-secondary,
.button-ghost,
.button-danger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    border-radius: var(--radius-control);
    min-height: 2.75rem;
    padding: 0.65rem 1.2rem;
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    transition:
        background var(--duration-fast) var(--ease-standard),
        border-color var(--duration-fast) var(--ease-standard),
        color var(--duration-fast) var(--ease-standard),
        box-shadow var(--duration-base) var(--ease-standard),
        transform var(--duration-fast) var(--ease-standard);
}
button,
.button {
    background: var(--accent);
    color: #fff;
    border: 1px solid transparent;
}
button:hover, .button:hover {
    background: var(--accent-dark);
    text-decoration: none;
    box-shadow: 0 8px 24px rgba(var(--accent-rgb), 0.22);
}
/* .button-secondary (02.08.26, forum/index.blade.php "Cancel" рядом с
   "Post topic") — первый реальный потребитель второстепенного действия
   рядом с основным .actions-акцентом (второй прецедент оправдал бы вынос
   в общий .actions-модификатор, сейчас не нужен, см. AI_RULES §2.5).
   Тот же паддинг/радиус, что у .button, но приглушённый фон вместо
   --accent — не отвлекает от основной кнопки формы. */
.button-secondary {
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
}
.button-secondary:hover {
    color: var(--accent);
    background: var(--color-primary-soft);
    border-color: rgba(var(--accent-rgb), 0.35);
    text-decoration: none;
}
.button-ghost {
    color: var(--accent);
    background: transparent;
    border: 1px solid transparent;
    box-shadow: none;
}
.button-ghost:hover {
    color: var(--accent-dark);
    background: var(--color-primary-soft);
    border-color: rgba(var(--accent-rgb), 0.16);
    text-decoration: none;
    box-shadow: none;
}
.button-danger {
    color: #fff;
    background: var(--color-danger-ink);
    border: 1px solid var(--color-danger-ink);
}
.button-danger:hover {
    color: #fff;
    background: var(--color-danger-hover);
    border-color: var(--color-danger-hover);
    text-decoration: none;
    box-shadow: 0 8px 24px rgba(155, 38, 59, 0.20);
}
button:active,
.button:active,
.button-secondary:active,
.button-ghost:active,
.button-danger:active {
    transform: translateY(1px);
    box-shadow: none;
}
.button-large {
    min-height: 3.25rem;
    padding-inline: 1.5rem;
    font-size: 1rem;
}
button:disabled,
.button[aria-disabled="true"],
.button-secondary[aria-disabled="true"],
.button-ghost[aria-disabled="true"],
.button-danger[aria-disabled="true"] {
    opacity: 0.48;
    cursor: not-allowed;
    pointer-events: none;
    box-shadow: none;
    transform: none;
}
button[aria-busy="true"],
.button[aria-busy="true"],
.button-secondary[aria-busy="true"],
.button-ghost[aria-busy="true"],
.button-danger[aria-busy="true"] {
    position: relative;
    color: transparent;
    pointer-events: none;
}
button[aria-busy="true"]::after,
.button[aria-busy="true"]::after,
.button-secondary[aria-busy="true"]::after,
.button-ghost[aria-busy="true"]::after,
.button-danger[aria-busy="true"]::after {
    content: "";
    position: absolute;
    width: 1rem;
    height: 1rem;
    border: 2px solid rgba(255, 255, 255, 0.45);
    border-top-color: #fff;
    border-radius: 50%;
    animation: button-loading-spin 700ms linear infinite;
}
.button-secondary[aria-busy="true"]::after,
.button-ghost[aria-busy="true"]::after {
    border-color: rgba(var(--accent-rgb), 0.25);
    border-top-color: var(--accent);
}
@keyframes button-loading-spin {
    to { transform: rotate(360deg); }
}
/* БАГ (найден автором визуально, 29.07.26): кнопки/ссылки-действия
   слипались без зазора в нескольких не связанных друг с другом
   местах — .book-title-row (заголовок книги + "Edit"/"Tree Editor"
   подряд), "+ Создать новую книгу" сразу перед формой поиска
   (books/index.blade.php, home.blade.php), "Начать читать"/
   "Продолжить чтение" (books/show.blade.php). Общая причина у всех:
   не было ни одного переиспользуемого класса "группа действий" —
   gap между инлайн-элементами добавлялся не везде, а margin вокруг
   одиночных <p><a class="button">...</a></p> полагался на дефолтный
   margin браузера у <p>, не на явное правило проекта (хрупко: любой
   будущий сброс margin у p сломал бы отступ незаметно).

   .actions — новый общий класс (не дублирует .search-form/
   .book-title-row, применяется РЯДОМ с ними как обёртка вокруг
   группы кнопок/ссылок и не привязан к конкретной форме). display:
   flex + flex-wrap: wrap — не разъезжается на узких экранах, gap
   работает и для инлайн-, и для block-элементов одинаково (в отличие
   от margin у отдельных детей, который пришлось бы сбрасывать у
   последнего). margin вокруг самого блока — тот же вертикальный
   отступ, что и у .search-form/.card (1.25rem), для единообразия
   ритма страницы, не собственное магическое число. */
.actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin: 1.25rem 0;
}
.actions:first-child { margin-top: 0; }
.actions:last-child { margin-bottom: 0; }
/* .actions-inline — модификатор для случая "группа действий внутри
   уже готового flex-ряда" (.book-title-row, books/show.blade.php:
   <h1> + .actions рядом, .book-title-row сам уже даёт gap между
   ними и вертикальный ритм страницы) — без внешнего margin/wrap,
   только горизонтальный gap между самими действиями. */
.actions-inline { margin: 0; flex-wrap: nowrap; }
/* .actions-center (29.07.26) — модификатор для одиночной акцентной кнопки
   посреди страницы (reader/access-required.blade.php, "Читать на {площадка}")
   — в отличие от остальных мест .actions (группы кнопок формы/навигации,
   выровненные по левому краю), здесь это единственное действие на всю
   ширину .card, по прямому запросу автора — по центру. */
.actions-center { justify-content: center; }
/* Поиск — один составной control, а не разнесённые поле и кнопка.
   Общая рамка и focus-within визуально объединяют элементы; кнопка без
   промежутка примыкает к правому краю и продолжает геометрию формы. */
.search-form {
    display: flex;
    align-items: stretch;
    gap: 0;
    margin-bottom: 1.25rem;
    padding: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    overflow: hidden;
    transition:
        border-color var(--duration-fast) var(--ease-standard),
        box-shadow var(--duration-fast) var(--ease-standard);
}
.search-form:focus-within {
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}
.search-form input[type="text"] {
    flex: 1;
    min-width: 0;
    margin: 0;
    padding-inline: var(--space-3);
    background: transparent;
    border: 0;
    border-radius: calc(var(--radius-control) - 1px) 0 0 calc(var(--radius-control) - 1px);
    box-shadow: none;
}
.search-form input[type="text"]:focus {
    border-color: transparent;
    box-shadow: none;
}
.search-form button {
    flex: 0 0 auto;
    min-height: 2.75rem;
    padding-inline: var(--space-4);
    border-radius: 0 calc(var(--radius-control) - 1px) calc(var(--radius-control) - 1px) 0;
}
ul.plain { list-style: none; margin: 0; padding: 0; }
ul.plain li { padding: 0.4rem 0; border-bottom: 1px solid var(--border); }
ul.plain li:last-child { border-bottom: none; }
.muted { color: var(--muted); }
.error { color: #c0293d; font-size: 0.9rem; margin: -0.25rem 0 0.5rem; }
.tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* Единая геометрия компактных меток. Семантический цвет задаётся
   модификатором, а не размером или случайным локальным классом. */
.pill,
.tag,
.status-progress,
.status-completed,
.publication-status-draft,
.publication-status-scheduled,
.publication-status-published,
.publication-status-unpublished,
.workshop-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    min-height: 1.75rem;
    padding: 0.25rem 0.7rem;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    font-family: var(--font-ui);
    font-size: 0.8125rem;
    font-weight: 700;
    line-height: 1.2;
    vertical-align: middle;
}

.pill-neutral,
.publication-status-draft {
    color: var(--muted);
    background: var(--color-surface-muted);
    border-color: var(--border);
}

.pill-accent,
.tag,
.workshop-badge {
    color: var(--color-primary);
    background: var(--color-primary-soft);
    border: 1px solid rgba(var(--accent-rgb), 0.16);
}

.pill-warning,
.status-progress,
.publication-status-scheduled {
    color: var(--color-warning-ink);
    background: var(--color-warning-soft);
    border-color: rgba(169, 120, 50, 0.24);
}

.pill-success,
.status-completed,
.publication-status-published {
    color: var(--success-text);
    background: var(--success-bg);
    border-color: rgba(47, 107, 80, 0.22);
}

.pill-danger,
.publication-status-unpublished {
    color: var(--danger-text);
    background: var(--danger-bg);
    border-color: rgba(155, 38, 59, 0.22);
}

a.tag,
a.workshop-badge {
    text-decoration: none;
    transition:
        color var(--duration-fast) var(--ease-standard),
        background-color var(--duration-fast) var(--ease-standard),
        border-color var(--duration-fast) var(--ease-standard);
}

a.tag:visited,
a.workshop-badge:visited {
    color: var(--color-primary);
}

@media (hover: hover) and (pointer: fine) {
    a.tag:hover,
    a.workshop-badge:hover {
        color: var(--accent-dark);
        background: #ead4d9;
        border-color: rgba(var(--accent-rgb), 0.32);
    }
}
.book-title-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
}
.book-overview {
    display: flex;
    gap: 1.25rem;
    align-items: flex-start;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
/* Колонка метаданных (02.08.26, уточнение автора: теги должны идти сразу
   после .book-meta-list, а не отдельной строкой под всей обложкой) —
   второй flex-элемент .book-overview, наравне с .book-cover-wrap.
   flex-basis: 0 (не auto!) — найденный баг: .tags внутри сам display:flex;
   flex-wrap:wrap (жанры), а многострочный flex-контейнер по спецификации
   отдаёт наружу ширину ТАК, будто не переносится (сумма чипов в один
   ряд) — именно эта раздутая ширина участвовала в решении браузера
   "помещается ли .book-overview-details на той же строке, что обложка"
   (это решение принимается ДО flex-shrink, поэтому min-width:200px ниже
   сам по себе не спасал) — колонка целиком переносилась под обложку.
   flex-basis:0 убирает контент из этого решения, min-width — пол при
   реальном сжатии. */
.book-overview-details {
    flex: 1 1 0%;
    min-width: 200px;
}
/* Теги/жанры (02.08.26) — теперь внутри .book-overview-details, сразу под
   .book-meta-list, не отдельным flex-ребёнком — только отступ сверху.
   .tags сам не трогаем — общий класс чипов, используется и вне этой
   страницы. */
.book-overview-tags {
    margin-top: 0.5rem;
}
.book-meta-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.book-meta-list li {
    padding: 0.2rem 0;
}
/* Правка даты задним числом, только администратор (09.08.26, импорт старых
   книг/комментариев с другого сайта с сохранением исходных дат) —
   .import-date-row/.import-date-toggle/.import-date-form общие для
   books/show.blade.php (дата книги) и comments/_thread.blade.php (дата
   каждого комментария), тот же класс в обоих местах. */
.import-date-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
}
.import-date-toggle {
    background: none;
    border: none;
    color: var(--muted);
    cursor: pointer;
    font-size: 0.95rem;
    line-height: 1;
    padding: 0.1rem 0.3rem;
    border-radius: 4px;
}
.import-date-toggle:hover {
    background: var(--bg);
    color: var(--text);
}
.import-date-form {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
}
.import-date-form input[type="date"] {
    padding: 0.2rem 0.4rem;
}
.book-cover-wrap {
    width: 196px;
    flex-shrink: 0;
    /* "Избранное" (02.08.26) — тот же relative-контейнер, что
       .book-cover-container у карточек списка (см. её докблок), позволяет
       переиспользовать .favorite-toggle-overlay без ещё одного класса. */
    position: relative;
}
.book-cover {
    display: block;
    width: 100%;
    aspect-ratio: 196 / 280;
    object-fit: cover;
    border-radius: 4px;
    border: 1px solid var(--border);
}
.author-avatar-wrap {
    width: 140px;
    flex-shrink: 0;
}
.author-avatar {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: 50%;
    border: 1px solid var(--border);
}
/* БАГ (найден автором визуально, 30.07.26): жёсткий repeat(4, 1fr) не
   имел нижней границы для ширины колонки — на узких экранах браузер
   продолжал сжимать все 4 колонки одновременно (обложка + текст внутри
   каждой карточки), пока контент карточки физически не переставал
   влезать (min-content текста/отступов), и тогда весь .book-list, а с
   ним и вся страница, получал горизонтальную прокрутку вместо переноса
   карточек на следующую строку — тот же класс проблемы, что и у шапки
   ниже (.topbar nav), просто не был замечен как общий раньше.

   Исправлено repeat(auto-fill, minmax(220px, 1fr)) — стандартный CSS
   Grid приём "сам знает, сколько колонок влезет", без отдельных медиа-
   запросов под каждую ширину экрана/каждое сочетание сайдбаров (более
   простое решение, чем набор breakpoint'ов, ADR §5 в AI_RULES.md — не
   вводит абстракцию, использует уже существующую возможность Grid).
   220px — минимум, ПОДОБРАННЫЙ под текущую ширину контента (не с
   потолка): на самом широком варианте страницы (.container 1200px,
   без сайдбаров, минус padding .container/.card) 5 колонок при этом
   минимуме уже не влезают, 4 влезают всегда — визуальный ряд "4 книги"
   на десктопе, который уже был задуман автором, сохраняется как
   максимум, а не жёстко фиксируется. На более узких экранах (или с
   сайдбарами, см. layouts/public.blade.php) колонок автоматически
   становится меньше вплоть до одной, без горизонтальной прокрутки на
   любой ширине. */
.book-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 1.5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}
.book-list-item {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    text-align: center;
    gap: 0.35rem;
    padding: 0.75rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.book-list-item:hover {
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
    transform: translateY(-2px);
}
/* Визуальные маркеры статуса на карточке списка (books/partials/_list.blade.php,
   прямой запрос автора: "не ясно что с книгой", путался, почему книгу не
   видит читатель). Неопубликованная книга (Draft/Scheduled/Unpublished) —
   приглушённый серый фон + сниженная непрозрачность: книга требует
   внимания автора, не готова к показу — единственный из двух маркеров,
   меняющий фон (правка дизайна ограничена этим случаем по прямому запросу
   автора). Завершённая (writingStatus completed) И опубликованная —
   ТОЛЬКО цветная рамка (border), не фон — правка по прямому запросу
   автора: "у завершенной не фон изменить а бордер, иначе мы рушим весь
   дизайн". Цвет рамки — светло-зелёный (#a8d5ab), НЕ --success-text:
   первая версия переиспользовала --success-text (тёмно-зелёный текстовый
   цвет), автор отметил результат как "слишком тёмный" для рамки —
   --success-text остаётся только текстовым цветом (.status-completed и
   т.п.), для рамки нужен отдельный, более светлый оттенок. Приоритет —
   неопубликованность важнее завершённости: если книга одновременно
   completed и не Published, применяется только серый фон, поэтому
   .book-list-item--completed в разметке никогда не ставится одновременно
   с --unpublished. */
.book-list-item--unpublished {
    background: var(--bg);
    opacity: 0.72;
}
.book-list-item--completed {
    border-color: #a8d5ab;
}
.book-list-item-body {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}
/* Заголовок книги в карточке списка (books/index.blade.php,
   authors/show.blade.php) — семантически h2/h3 (звено в иерархии
   заголовков страницы, не просто ссылка: список карточек — это
   список отдельных сущностей, каждой нужен свой заголовок для
   навигации по заголовкам в скринридерах), но визуально должен
   остаться неотличим от обычной ссылки — той же карточке ничего не
   известно про то, какой уровень (h2 на /books, h3 внутри "Books" на
   /authors/{id}, см. эти шаблоны) корректен именно на этой странице,
   поэтому сброс общий по классу, не по тегу. */
.book-list-item-body h2,
.book-list-item-body h3 {
    margin: 0;
    font: inherit;
    /* Заголовок книги в карточке — жирным, прямой запрос автора,
       28.07.26. font: inherit выше сбрасывает и вес шрифта, поэтому
       переопределяем его отдельно после шорткаты. */
    font-weight: 700;
}
/* "Избранное" (01.08.26, уточнение 02.08.26: "больше и на изображении книги
   сверху справа") — оверлей поверх обложки, не рядом с заголовком.
   .book-cover-container — общий relative-контейнер для .book-cover-frame
   (books/partials/_list.blade.php) и .book-cover-wrap (books/show.blade.php,
   см. её собственное правило ниже) — оверлей позиционируется ОТНОСИТЕЛЬНО
   этого контейнера, не самой обложки, чтобы не зависеть от aspect-ratio
   img/border обложки. Полупрозрачный белый круг-подложка — иначе символ
   без контраста терялся бы на тёмных/пёстрых обложках. */
.book-cover-container {
    position: relative;
}
.favorite-toggle-form {
    display: inline;
}
.favorite-toggle-overlay {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
}
.favorite-toggle {
    background: rgba(255, 255, 255, 0.85);
    border: none;
    border-radius: 50%;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--accent);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
/* Иконка сердца (02.08.26, замена символов ♥/♡ — жалоба автора: "узкое...
   не контурное а залитое чёрным"). SVG-контур всегда виден (stroke), заливка
   появляется только в состоянии "уже в избранном" (.is-active) — так пустое
   сердце читается как настоящий контур, а не мелкий чёрный символ. */
.heart-icon {
    width: 1.35rem;
    height: 1.35rem;
    fill: none;
    stroke: var(--accent);
    stroke-width: 1.6;
    stroke-linejoin: round;
    stroke-linecap: round;
}
.favorite-toggle.is-active .heart-icon {
    fill: var(--accent);
}
/* Интерактивная оценка книги: геометрия звёзд не меняется между обычным,
   hover/focus и выбранным состоянием. Незаполненная звезда светлая с
   золотым контуром; выбранные и все звёзды до наведённой заполняются. */
.rating-form {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
}
.rating-input-stars {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
}
.rating-star {
    flex: 0 0 1.75rem;
    width: 1.75rem;
    min-width: 1.75rem;
    height: 1.75rem;
    min-height: 1.75rem;
    padding: 0;
    border: 0;
    border-radius: 0;
    color: var(--surface);
    background: transparent;
    box-shadow: none;
    cursor: pointer;
    font-size: 1.55rem;
    line-height: 1;
    -webkit-text-stroke: 1px var(--color-gold);
    transform: none;
}
.rating-star.is-selected {
    color: var(--color-gold);
}
.rating-input-stars:hover .rating-star.is-selected,
.rating-input-stars:focus-within .rating-star.is-selected {
    color: var(--surface);
}
.rating-star:hover,
.rating-star:active,
.rating-star:focus,
.rating-star:has(~ .rating-star:hover),
.rating-star:has(~ .rating-star:focus) {
    color: var(--color-gold);
    background: transparent;
    border: 0;
    box-shadow: none;
    transform: none;
}
.rating-star:focus-visible {
    border-radius: var(--radius-sm);
}
/* RewardAuthorWithRabbits — упрощено по прямому запросу автора (08.08.26):
   только иконка+инпут+кнопка, без label/подписи баланса (см.
   rabbits/_award_form.blade.php). Собственный фон/рамка/скругление —
   раньше форма визуально сливалась с соседними кнопками (жалоба автора:
   "все кнопки и блоки сплываются стилистически") — тот же приём
   выделенного "острова" внутри карточки, что .book-tabs использует для
   переключателя вкладок, здесь применён к самой форме.
   align-items: center само по себе не выравнивает inline-элементы разной
   реальной высоты, если у них разные margin — input/button переопределены
   явно (margin: 0) вместо общего правила input[type=number] (margin-bottom:
   0.5rem, рассчитано на вертикальные формы), это и была причина "не ровно".
   display: flex (не inline-flex, 08.08.26) — форма переехала внутрь узкой
   .book-overview-details (min-width: 200px, books/show.blade.php: между
   .book-meta-list и .book-overview-tags), inline-flex мог вылезти за
   пределы колонки на узких экранах вместо переноса/сжатия по её ширине;
   width: fit-content — не растягивается на всю ширину колонки, как это
   сделал бы обычный flex-блок. */
.rabbit-award-form {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    width: fit-content;
    margin-top: 0.5rem;
    padding: 0.6rem 0.9rem;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
}
.rabbit-award-form input[type="number"] {
    width: 4.5rem;
    margin: 0;
}
.rabbit-award-form .button {
    margin: 0;
    white-space: nowrap;
}
/* /rabbits — приход/расход в истории операций (08.08.26, прямой запрос
   автора), тот же семантический цвет "хорошо/плохо", что уже применён по
   всему проекту (--success-text — Published/завершённая книга/активный
   toggle; --danger-text — снято с публикации), не новая цветовая пара. */
.rabbit-amount-credit {
    color: var(--success-text);
    font-weight: 600;
}
.rabbit-amount-debit {
    color: var(--danger-text);
    font-weight: 600;
}
/* Средний рейтинг звёздами (02.08.26, books/partials/_rating_stars.blade.php,
   уточнение автора: "выдели его цветом, а то не ясно что это как будто он
   не активный") — заполненные звёзды тем же акцентным цветом, что
   интерактивные .rating-star выше (единый цвет звёзд по всему сайту),
   пустые — блёкло-серым (var(--border)), а не унаследованным .muted на
   всём блоке целиком (тот и обесцвечивал заполненные звёзды тоже). */
.rating-stars {
    font-size: 1rem;
}
.star-filled {
    color: var(--accent);
}
.star-empty {
    color: var(--border);
}
/* Раздел "Мастерская" — вкладка "Идеи" (07.08.26, books/show.blade.php,
   INTEGRATION_NOTES.md §157). Тот же textarea-стиль, что .comment-form,
   форма/список — простая карточка-строка, не переиспользует .comment-list
   (другая модель: тело + счёт + голосование, не реплика/тред). */
.suggestion-form textarea {
    width: 100%;
    min-height: 4rem;
    resize: vertical;
}
.suggestion-list {
    list-style: none;
    margin: 1.5rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.suggestion-item {
    padding: 0.85rem 1rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg);
}
.suggestion-item-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.5rem;
}
.suggestion-body {
    margin: 0 0 0.5rem;
    white-space: pre-wrap;
}
/* Меню "⋮" удаления идеи (07.08.26, доработка по фидбэку автора — тот же
   стиль, что .reply-menu на forum/show.blade.php, скопирован сюда без
   переиспользования общего класса: разные страницы, независимые delegated
   click-обработчики, дублирование трёх правил дешевле новой абстракции
   поверх обеих (AI_RULES §3 п.9 — нет второго места, где это было бы общим
   компонентом). */
.suggestion-menu {
    position: relative;
    flex-shrink: 0;
}
.suggestion-menu-toggle {
    background: none;
    border: none;
    color: var(--muted);
    cursor: pointer;
    font-size: 1.1rem;
    line-height: 1;
    padding: 0.15rem 0.4rem;
    border-radius: 4px;
}
.suggestion-menu-toggle:hover {
    background: var(--bg);
    color: var(--text);
}
.suggestion-menu-dropdown {
    position: absolute;
    top: 100%;
    right: 0;
    z-index: 10;
    display: flex;
    flex-direction: column;
    min-width: 120px;
    margin-top: 0.25rem;
    padding: 0.4rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
}
.suggestion-menu-dropdown form {
    margin: 0;
}
.suggestion-menu-dropdown button {
    display: block;
    width: 100%;
    background: none;
    color: var(--text);
    border: none;
    border-radius: 4px;
    padding: 0.4rem 0.6rem;
    text-align: left;
    font-weight: 400;
    font-size: 0.9rem;
    cursor: pointer;
}
.suggestion-menu-dropdown button:hover {
    background: var(--bg);
}
.suggestion-meta {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    font-size: 0.9rem;
}
.suggestion-vote-form {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
/* Голосование пальцем вверх/вниз (07.08.26, доработка по фидбэку автора —
   см. books/partials/_thumb_icon.blade.php). Одна и та же SVG-иконка для
   обеих кнопок — "вниз" получается разворотом на 180°, второго файла не
   заводится. */
.suggestion-vote-button {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.15rem 0.5rem;
    cursor: pointer;
    font-size: 0.85rem;
    color: inherit;
}
.suggestion-vote-button .thumb-icon {
    fill: currentColor;
}
.suggestion-vote-button--down .thumb-icon {
    transform: rotate(180deg);
}
.suggestion-vote-button.is-active {
    border-color: var(--accent);
    color: var(--accent);
}
/* Обёртка-рамка над обложкой (31.07.26, прямой запрос автора: эффект
   наведения "как на tai-ecosafe.com" — картинка увеличивается ВНУТРИ своих
   границ, не поверх соседних карточек). Раньше scale() был прямо на самом
   <img> без overflow:hidden ни на одном предке — при наведении обложка
   визуально вылезала за рамку/тень карточки. border/border-radius
   перенесены сюда, с самой картинки — рамка должна оставаться на месте,
   пока увеличивается только содержимое внутри неё; card-level тень/подъём
   (.book-list-item:hover выше) не трогали — он не клипается, это другой
   элемент. */
.book-cover-frame {
    display: block;
    overflow: hidden;
    border-radius: 4px;
    border: 1px solid var(--border);
}
.book-cover-thumb {
    display: block;
    width: 100%;
    aspect-ratio: 196 / 280;
    object-fit: cover;
    transition: transform 0.25s ease;
}
.book-list-item a:hover .book-cover-thumb {
    transform: scale(1.08);
}
/* /rabbits (баланс + история, публичная страница) — тот же отступ, что
   .card снизу (margin-bottom: 1.25rem выше), балансу нужен такой же зазор
   от следующей за ним .card с таблицей, иначе текст визуально слипается с
   карточкой (найдено автором визуально, 07.08.26). */
.rabbits-balance {
    margin: 0 0 1.25rem;
    font-size: 1.05rem;
}
/* Второй потребитель (admin/users, admin/books) — переносится сюда,
   не дублируется в @push('styles') по каждой странице (PROJECT_CONTEXT.md
   §3 п.9 — абстракция/общий стиль по факту второго прецедента). */
.admin-table {
    width: 100%;
    border-collapse: collapse;
}
.admin-table th, .admin-table td {
    text-align: left;
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid var(--border);
}
/* Ховер на строки (07.08.26, прямой запрос автора — /rabbits, тот же класс
   .admin-table переиспользован на публичной странице истории кроликов):
   раньше ни у одной таблицы проекта не было построчного hover вообще.
   background вместо изменения border/цвета текста — не конфликтует с
   .admin-table-cell-center/.admin-table-icon-active, которые уже задают
   text-align/color на th/td, а не на tr. :has(td) — не подсвечивает
   <thead><tr><th>...</tr></thead>, только строки данных (<tr><td>...) —
   тот же приём, что уже используется для .admin-table-cell-center выше,
   локальный к этому классу, не глобальный tr:hover. */
.admin-table tbody tr:hover {
    background: var(--bg);
}
/* Центрирование содержимого колонки (02.08.26, admin/users — Модератор/
   Редактор, прямой запрос автора: "выровняй их по центру... кнопка,
   горизонтально и вертикально") — text-align: center действует на
   inline-block .admin-table-icon-form внутри (горизонталь), vertical-align:
   middle — на саму ячейку как table-cell (вертикаль, тот же CSS-механизм,
   которым браузер вертикально центрирует ЛЮБОЙ td/th по умолчанию для
   содержимого, отличного от inline-текста на baseline). На <th> тот же
   класс — иначе заголовок колонки остался бы слева, а кнопка под ним по
   центру, визуально не совпадая.

   БАГ (найден автором визуально, 02.08.26, тот же класс проблемы, что уже
   был с цветом активной иконки): составной селектор .admin-table th,
   .admin-table td (выше, задаёт text-align: left) имеет specificity
   (0,1,1) — класс + тег элемента, выше одиночного класса
   .admin-table-cell-center (0,1,0), поэтому text-align: left побеждал
   center независимо от порядка правил в файле. Исправлено явными
   составными селекторами .admin-table th.admin-table-cell-center/
   .admin-table td.admin-table-cell-center той же specificity — та же
   техника фикса, что уже применена к .admin-table button.admin-table-icon-active. */
.admin-table th.admin-table-cell-center,
.admin-table td.admin-table-cell-center {
    text-align: center;
    vertical-align: middle;
}
/* БАГ (найден автором визуально, 29.07.26): несколько действий подряд
   в одной ячейке (edit-ссылка + toggle-форма + delete-форма — admin/
   blocks, admin/users, admin/comments) визуально слипались без
   зазора — display: inline не даёт горизонтального отступа сам по
   себе, а перенос строки/пробел между тегами в самой Blade-разметке
   не гарантирован (зависит от того, как шаблонизатор схлопывает
   whitespace между закрывающим и следующим открывающим тегом).
   Исправлено переносом отступа в CSS, а не добавлением &nbsp;/пробелов
   в каждый из трёх шаблонов по отдельности — иначе пришлось бы
   синхронизировать зазор вручную в нескольких местах. inline-block
   (не inline) — margin действует только у inline-block/block. Только
   у форм (не у ссылки "Edit" — у неё и так нет margin, ей нечего
   сбрасывать), :first-child на форме сбрасывает левый отступ, если
   форма — первое действие в ячейке (admin/comments, где нет отдельной
   edit-ссылки перед toggle-формой). */
.admin-table form { display: inline-block; margin-left: 0.5rem; }
.admin-table form:first-child { margin-left: 0; }
/* БАГ (найден автором визуально, 02.08.26): после добавления колонки "Дата
   добавления" в admin/comments и перевода Скрыть/Показать/Удалить на
   icon-кнопки — обе inline-block-формы переносились одна под другую
   ("столбиком") вместо горизонтального ряда. Причина — не сам inline-block
   (тот работал верно и раньше, см. докблок выше), а нехватка
   горизонтального места в последней ячейке: без ограничения ширины
   браузер ужимает саму ячейку действий, чтобы освободить место контенту
   комментария (самая длинная колонка), и inline-block-элементы, которым
   тесно, переносятся по своим правилам обтекания, как и любой другой
   inline-контент. white-space: nowrap на последней колонке запрещает этот
   перенос — вместе с ограничением ширины колонки комментария ниже это
   гарантирует, что у действий всегда есть место в одну строку. */
.admin-table td:last-child {
    white-space: nowrap;
}
.admin-table-comment-body {
    max-width: 320px;
    word-break: break-word;
}
.admin-table button {
    background: none;
    border: 1px solid var(--border);
    color: var(--muted);
    padding: 0.25rem 0.6rem;
    font-size: 0.85rem;
    border-radius: 6px;
    cursor: pointer;
}
.admin-table button:hover { color: var(--accent); border-color: var(--accent); }
/* Иконки-действия admin/books (02.08.26, прямой запрос автора: "структуру
   сделать книжечкой, детали карандашиком" — были текстовые ссылки
   "Структура"/"Детали"). inline-block + margin-left, тот же приём, что
   .admin-table form выше — зазор между двумя иконками подряд без лишнего
   маркапа между ними. */
.admin-table-icon-link {
    display: inline-block;
    color: var(--muted);
    vertical-align: middle;
    margin-left: 0.5rem;
}
.admin-table-icon-link:first-child { margin-left: 0; }
.admin-table-icon-link:hover { color: var(--accent); }
.admin-table-icon-link svg { display: block; }
/* Icon-кнопки внутри форм admin-таблиц (02.08.26, admin/comments —
   Скрыть/Показать/Удалить: "иконкой... для экономия места", прямой запрос
   автора). Отдельные классы от .admin-table button (тот текстовый паттерн
   с рамкой/паддингом остаётся как есть в остальных местах, где кнопки не
   переведены на иконки, например admin/blocks) — здесь без рамки/фона,
   тот же визуальный вес, что .admin-table-icon-link рядом, просто
   <button> вместо <a> (POST-действие с CSRF, не переход). */
.admin-table-icon-form {
    display: inline-block;
    vertical-align: middle;
    margin: 0 0 0 0.5rem;
}
.admin-table-icon-form:first-child { margin-left: 0; }
.admin-table-icon-button {
    display: block;
    background: none;
    border: none;
    padding: 0;
    color: var(--muted);
    cursor: pointer;
}
.admin-table-icon-button:hover { color: var(--accent); }
.admin-table-icon-button svg { display: block; }
/* БАГ (найден автором визуально, 02.08.26, тот же класс проблемы, что и
   ниже с цветом активной галочки): .admin-table button задаёт border: 1px
   solid var(--border) с specificity (0,1,1) — выше, чем одиночный класс
   .admin-table-icon-button (0,1,0) — поэтому background: none/border: none
   из этого класса не применялись. Составной селектор той же specificity,
   что .admin-table button, гарантированно её перебивает — та же техника
   фикса, что чуть ниже для .admin-table-icon-active. Рамка НЕ убрана
   целиком (правка 02.08.26 "не убрать а сделать зелёной вместо серой" —
   пересмотр более ранней версии этого шага, которая убирала border: none):
   остаётся тот же 1px рамки, что и у обычных текстовых кнопок
   .admin-table, только перекрашивается в active-состоянии ниже. */
.admin-table button.admin-table-icon-button {
    background: none;
}
/* Активное состояние icon-кнопки (02.08.26, admin/users — галочка
   "Модератор"/"Редактор", прямой запрос автора: "выделить зелёным,
   активные значки выделить активным цветом", далее "сделай галочку
   зелёной как было до этого", далее "не убрать а сделать зелёной вместо
   серой" — рамка вокруг кнопки красится в тот же зелёный, что и сама
   галочка, не убирается) — переопределяет color/border-color базового
   .admin-table-icon-button (var(--muted)/var(--border)) на var(--success-text),
   ту же переменную, что уже красит "хорошее" состояние в других местах
   проекта (.status-completed чуть ниже).

   БАГ (найден автором визуально, 02.08.26): первая версия правила была
   просто .admin-table-icon-active { color: ... } — не сработало, галочка
   оставалась серой даже после hard refresh. Причина — специфичность CSS,
   не кэш браузера: составной селектор .admin-table button (админ-таблицы
   выше, задаёт color: var(--muted) для ЛЮБОЙ <button> внутри .admin-table)
   имеет специфичность (0,1,1) — класс + тег элемента, тогда как одиночный
   класс .admin-table-icon-active — только (0,1,0). При равенстве остальных
   компонентов (0,1,1) побеждает (0,1,0) независимо от порядка правил в
   файле — .admin-table button оказывался "сильнее" и оставлял серый цвет.
   Исправлено явным составным селектором ниже той же специфичности что и
   .admin-table button, плюс class-класс поверх — гарантированно побеждает. */
.admin-table button.admin-table-icon-active {
    color: var(--success-text);
    border-color: var(--success-text);
}
.admin-table button.admin-table-icon-active:hover {
    color: var(--accent);
    border-color: var(--accent);
}
/* Статусные Да/Нет-иконки (02.08.26, admin/users — "Активирован", email) —
   <span>, не <button>: не кликабельны, только показывают состояние (в
   отличие от соседних Модератор/Редактор, которые одновременно и статус,
   и действие toggle). inline-flex + align-items:center + vertical-align —
   тот же приём, что обычно применяют для "иконка вместе с текстом", не
   требует трогать сам <svg>.

   Рамка (02.08.26, прямой запрос автора: "почему новые галочки без
   контура... добавить рамку для визуальной консистентности") — та же 1px
   рамка, что у .admin-table button рядом (border-radius/padding
   скопированы буквально, не через общий класс с кнопкой: это разные теги,
   табличная specificity-игра с .admin-table button их бы не задела,
   отдельные явные значения проще, чем городить составной селектор ради
   <span>, которого .admin-table button не касается). Цвет рамки — тот же
   var(--border)/var(--success-text) через .admin-table-icon-active рядом,
   что уже красит границу активных Модератор/Редактор. */
.admin-table-status-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.25rem 0.6rem;
}
.admin-table-status-icon.admin-table-icon-active {
    color: var(--success-text);
    border-color: var(--success-text);
}
/* Sidebar-layout админки (02.08.26, layouts/admin.blade.php, прямой запрос
   автора: "полноценная админка как у сайтов" — постоянное левое меню вместо
   плоского списка ссылок на прежней /admin). Простой flex: фиксированная
   ширина sidebar, .admin-content забирает остальное — тот же уровень
   сложности, что .settings-columns (grid) чуть выше, без отдельного
   JS-фреймворка разметки. Живёт внутри уже существующего .container
   (max-width: 1200px) — не полноширинный экран поверх topbar, тот же приём,
   что у всего остального контента сайта. */
.admin-layout {
    display: flex;
    gap: 2rem;
    align-items: flex-start;
}
.admin-sidebar {
    flex: 0 0 220px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 1rem 0;
    position: sticky;
    top: 1.5rem;
}
.admin-sidebar-heading {
    padding: 0 1rem 0.75rem;
    margin-bottom: 0.5rem;
    border-bottom: 1px solid var(--border);
    font-weight: 600;
    color: var(--muted);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.admin-sidebar-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.admin-sidebar-list a {
    display: block;
    padding: 0.5rem 1rem;
    color: var(--text);
    font-weight: 500;
}
.admin-sidebar-list a:hover {
    background: var(--bg);
    text-decoration: none;
}
.admin-sidebar-list a.admin-sidebar-active {
    background: var(--bg);
    color: var(--accent);
    border-left: 3px solid var(--accent);
    padding-left: calc(1rem - 3px);
}
.admin-sidebar-divider {
    height: 1px;
    background: var(--border);
    margin: 0.5rem 1rem;
}
/* "Выйти" (02.08.26) — единственный пункт личного блока внизу sidebar,
   рендерящийся как <form><button> (CSRF logout, тот же паттерн, что
   .user-menu-dropdown в topbar), не голая <a> — без этого правила кнопка
   получила бы стиль браузера по умолчанию, выбиваясь из остальных пунктов
   списка. Копирует .admin-sidebar-list a один в один (тот же padding/
   font-weight/цвет), только сброшены рамка/фон формы-элемента. */
.admin-sidebar-logout-form {
    margin: 0;
}
.admin-sidebar-logout-form button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.5rem 1rem;
    color: var(--text);
    font-weight: 500;
    font-size: 1rem;
    font-family: inherit;
    background: none;
    border: none;
    cursor: pointer;
}
.admin-sidebar-logout-form button:hover {
    background: var(--bg);
}
.admin-content {
    flex: 1;
    min-width: 0;
}
/* Мобильная ширина (тот же брейкпоинт 860px, что уже использует .nav-toggle
   в layouts/app.blade.php, для единообразия) — sidebar перестаёт быть
   sticky-колонкой слева и ложится горизонтальной полосой сверху над
   контентом, пункты меню в строку с переносом, не вертикальным списком:
   вертикальный список на всю ширину экрана растянул бы страницу вниз ещё
   до самого контента. */
@media (max-width: 860px) {
    .admin-layout {
        flex-direction: column;
        gap: 1rem;
    }
    .admin-sidebar {
        position: static;
        width: 100%;
        padding: 0.75rem;
    }
    .admin-sidebar-heading {
        display: none;
    }
    .admin-sidebar-list {
        display: flex;
        flex-wrap: wrap;
        gap: 0.25rem;
    }
    .admin-sidebar-list a {
        padding: 0.4rem 0.7rem;
        border-radius: 6px;
    }
    .admin-sidebar-list a.admin-sidebar-active {
        border-left: none;
        padding-left: 0.7rem;
    }
    .admin-sidebar-divider {
        display: none;
    }
}
/* Хлебные крошки — на всех страницах, кроме главной (см.
   layouts/partials/_breadcrumbs.blade.php PHPDoc). Живут ВНУТРИ
   .container (см. разметку layout) — та же ширина/центрирование
   (max-width: 1200px, margin: 0 auto), что и у остального контента
   страницы, никакого отдельного фона/полосы во всю ширину экрана
   (правка 26.07.26 — первая версия визуально выглядела вторым
   хедером, автор попросил стиль/ширину как у контента). */
.breadcrumbs {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-6);
    font-size: 0.8125rem;
    color: var(--muted);
    text-align: center;
}
.breadcrumbs a {
    padding: 0.2rem 0.35rem;
    color: var(--muted);
    border-radius: var(--radius-sm);
    font-weight: 600;
}
.breadcrumbs a:hover,
.breadcrumbs a:focus-visible {
    color: var(--accent);
    background: var(--color-primary-soft);
    text-decoration: none;
}
.breadcrumb-sep { color: var(--border); }
.breadcrumb-current { color: var(--text); font-weight: 700; }

/* Laravel Tailwind pagination остаётся функциональной, но получает
   геометрию и состояния общей дизайн-системы независимо от utility-классов. */
.container nav[role="navigation"] {
    margin: var(--space-8) 0 var(--space-4);
    color: var(--muted);
    font-family: var(--font-ui);
}

.container nav[role="navigation"] .shadow-sm {
    gap: var(--space-1);
    box-shadow: none;
}

.container nav[role="navigation"] a,
.container nav[role="navigation"] [aria-current="page"] > span,
.container nav[role="navigation"] [aria-disabled="true"] > span,
.container nav[role="navigation"] > div:first-child > span {
    min-width: 2.75rem;
    min-height: 2.75rem;
    margin-left: 0;
    justify-content: center;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    box-shadow: none;
    text-decoration: none;
}

.container nav[role="navigation"] a:hover,
.container nav[role="navigation"] a:focus-visible {
    color: var(--accent);
    background: var(--color-primary-soft);
    border-color: rgba(var(--accent-rgb), 0.28);
    text-decoration: none;
}

.container nav[role="navigation"] a:active {
    color: var(--accent-dark);
    background: #ead4d9;
    transform: translateY(1px);
}

.container nav[role="navigation"] [aria-current="page"] > span {
    color: #fff;
    background: var(--accent);
    border-color: var(--accent);
    font-weight: 750;
}

.container nav[role="navigation"] [aria-disabled="true"] > span,
.container nav[role="navigation"] > div:first-child > span {
    color: var(--muted);
    background: var(--color-surface-muted);
    opacity: 0.62;
}
/* Страница чтения (reader/show.blade.php, no-content.blade.php,
   access-required.blade.php) — 26.07.26, редизайн по образцу
   litnet.com (PROJECT_CONTEXT.md §10s): заголовок книги-ссылка +
   выпадающий список глав вместо бокового дерева, кнопки пред/след
   прямоугольные, во всю ширину. */
.reader-book-title {
    margin: 0 0 0.75rem;
    font-size: 1.5rem;
    font-weight: 700;
    text-align: center;
}
.reader-book-title a { color: var(--text); }
.reader-book-title a:hover { color: var(--accent); }
.reader-toolbar {
    display: flex;
    justify-content: center;
    margin-bottom: 1.5rem;
}
.reader-toc-select {
    width: auto;
    max-width: 100%;
    min-width: 260px;
    margin-bottom: 0;
}
/* .reader-pager используется дважды на странице (над и под текстом
   главы, по прямому запросу автора) — margin с обеих сторон, не
   только margin-top, чтобы одинаково хорошо смотреться что перед
   <h1>, что после текста. */
.reader-pager {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    margin: 1.5rem 0;
}
.reader-pager-btn {
    display: block;
    flex: 1;
    text-align: center;
    padding: 0.65rem 1rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text);
    font-weight: 600;
    text-transform: uppercase;
    font-size: 0.85rem;
    letter-spacing: 0.03em;
}
.reader-pager-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
    text-decoration: none;
}
/* Комментарии (create_comments_table, PROJECT_CONTEXT.md §10w/§10z) —
   один и тот же класс .comments на books/show (список + форма,
   comments/_thread.blade.php) и reader/show (только форма,
   comments/_form.blade.php). */
.comments {
    margin-top: 1.5rem;
}
.comment-list {
    list-style: none;
    margin: 0 0 1rem;
    padding: 0;
}
.comment {
    display: flex;
    gap: 0.9rem;
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--border);
}
.comment:last-child {
    border-bottom: none;
}
/* Фото автора — отдельная колонка слева (08.08.26, прямой запрос автора:
   "в комментариях должно отображаться фото автора", правка по месту после
   показанного образца — референс-скриншот стороннего сайта: крупный
   круглый аватар слева, имя/дата/текст справа, не мелкая иконка в строке
   метаданных). .comment стал flex-контейнером (колонка аватара +
   .comment-body-col), .comment-avatar здесь крупнее, чем в форуме
   (см. .reply-bubble-header ниже — там мелкий 28px кружок в одну строку с
   именем внутри пузыря, другой контекст, тот же класс не подошёл бы без
   визуальной порчи одного из двух мест). */
.comment-avatar-wrap {
    flex-shrink: 0;
}
.comment-avatar {
    display: block;
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--border);
}
.comment-body-col {
    flex: 1;
    min-width: 0;
}
.comment-meta {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
    margin-bottom: 0.25rem;
}
.comment-author {
    font-weight: 600;
}
.comment-date {
    font-size: 0.85rem;
}
.comment-body {
    margin: 0;
    white-space: pre-wrap;
}
/* .comment-body-html (30.07.26) — модификатор для темы/ответа болталки,
   которые с этой правки хранятся и выводятся как санитизированный HTML
   (Quill), не чистый текст. .comment-body сама по себе рассчитана на
   ПРОСТОЙ текст (book/chapter-комментарии, §10z — они не тронуты, остаются
   {{ }}) — white-space: pre-wrap для настоящего HTML с собственными <p>/<br>
   добавлял бы лишние отступы поверх уже готовой разметки. Картинки внутри
   контента (новая кнопка "image" в тулбаре) — max-width: 100%, чтобы не
   раздвигали карточку/страницу на узких экранах (см. правки под адаптацию
   выше). */
.comment-body-html {
    white-space: normal;
}
.comment-body-html img {
    max-width: 100%;
    height: auto;
    border-radius: 4px;
}
/* .page-body (blog/show.blade.php) — та же причина, что .comment-body-html
   img выше: с появлением загрузки картинок (30.07.26) пост блога тоже может
   содержать изображение шире экрана, без этого правила это была бы точно
   та же категория бага, что уже найдена и исправлена на /books (горизонтальная
   прокрутка на узких экранах). */
.page-body img {
    max-width: 100%;
    height: auto;
    border-radius: 4px;
}
/* Компактное поле ввода — общее правило textarea (min-height: 300px,
   выше) рассчитано на содержимое главы, для короткого комментария
   это слишком много места. */
.comment-form textarea {
    min-height: 100px;
}

/* Статус процесса написания книги (writingStatus) использует общий pill:
   ожидание получает warning-тему, завершение — success. Иконка остаётся
   псевдоэлементом, поэтому текст перевода и Blade-шаблоны не дублируются. */
.status-progress::before {
    content: "\23F0";
}
.status-completed::before {
    content: "\2713";
}

/* PublicationState использует те же семантические темы: draft — neutral,
   scheduled — warning, published — success, unpublished — danger. */
/* Бейдж "В Мастерской" (08.08.26, прямой запрос автора: читатель,
   особенно пришедший по внешней ссылке, не понимает, чем книга/глава из
   раздела "Мастерская" отличается от книг основного раздела) — тот же
   принцип, что статус написания книги выше (.status-progress/
   .status-completed): цветной текст, --accent — тот же цвет, что уже занят
   под "в процессе/ожидании" (status-progress, publication-status-scheduled),
   семантика "ещё не готово, промежуточное состояние" совпадает буквально.
   Общее место (не push-стиль внутри одного blade-файла), потому что
   используется на двух независимых страницах — books/show.blade.php (у
   заголовка книги) и reader/show.blade.php (у заголовка книги над текстом
   главы), второй реальный потребитель сразу с рождения класса. */
.workshop-badge {
    white-space: nowrap;
    /* Кликабельно, ведёт на /workshop (08.08.26, прямой запрос автора) —
       <a>, не <span> с этим же классом. text-decoration/:visited сброшены
       явно: без этого браузер подчеркнул бы текст и мог бы перекрасить
       посещённую ссылку своим дефолтным фиолетовым поверх --accent. */
    text-decoration: none;
}
.workshop-badge::before {
    content: "\1F6E0";
}

/* Описание раздела "Мастерская" (/workshop, 08.08.26, прямой запрос автора:
   "выделить текст не просто серый, а сделать стильным блоком, который
   привлекает внимание") — было обычным <p class="muted">, теперь акцентная
   карточка: левая цветная полоса + мягкий тонированный фон, тот же приём,
   что типичные "callout"-блоки (сообщение привлекает взгляд, не сливается с
   остальным текстом страницы, но не выглядит как предупреждение об ошибке).
   --accent — та же переменная, что .workshop-badge выше (единая цветовая
   тема раздела "Мастерская" на странице), фон — rgba(var(--accent-rgb), ...),
   тот же приём, что focus-ring в начале файла (см. её комментарий: color-mix()
   ещё не везде надёжен, поэтому в проекте используется явный rgb-триплет
   --accent-rgb вместо него). */
.workshop-intro {
    margin: 0 0 1.25rem;
    padding: 0.9rem 1.1rem;
    border-left: 4px solid var(--accent);
    border-radius: 6px;
    background: rgba(var(--accent-rgb), 0.08);
}
.workshop-intro p {
    margin: 0;
    color: var(--text);
}
.workshop-intro p + p {
    margin-top: 0.6rem;
}
/* ========================================================================== 
   Адаптация под мобильные/узкие экраны (30.07.26, прямой запрос автора:
   "проверь и измени адаптацию страниц под разные устройства... особенно
   books страница, в 4 книги сжимается до 705px, потом появляется
   прокрутка"). До этой правки в проекте был ровно один медиа-запрос
   (layouts/public.blade.php, max-width: 900px — переключение 3-колоночного
   сайдбар-грида в одну колонку); весь остальной layouts/app.blade.php был
   полностью фиксирован под широкий экран: шапка на 5 ссылок + меню
   пользователя без переноса строки, .book-list (исправлен выше отдельно,
   auto-fill/minmax — сам не даёт горизонтальной прокрутки ни на одной
   ширине, отдельного брейкпоинта под него здесь НЕ требуется), .container
   с одинаковым padding что на десктопе, что на телефоне. Ниже — то, что
   требовало явного брейкпоинта: шапка (не умеет переноситься сама по себе,
   flex без wrap) и точечные уменьшения отступов/размеров под очень узкие
   экраны.

   После добавления полной навигации и CTA фактическая ширина гостевого nav
   составляет 896px при viewport 1280px. Порог 1240px оставляет запас для
   личных действий авторизованного пользователя и включает компактное меню
   до появления горизонтального переполнения. */
@media (max-width: 1240px) {
    .topbar {
        flex-wrap: wrap;
    }
    .nav-toggle {
        display: inline-block;
    }
    /* nav по умолчанию скрыт на узком экране — показывается только когда
       .topbar получает класс .nav-open (JS-переключатель на .nav-toggle,
       см. layouts/app.blade.php). flex-basis: 100% — переносит nav на
       вторую строку внутри уже flex-wrap: wrap .topbar, а не пытается
       ужать его в оставшееся место рядом с логотипом. */
    .topbar nav {
        display: none;
        flex-basis: 100%;
        flex-direction: column;
        align-items: stretch;
        gap: 0.35rem;
        margin-top: 0.85rem;
        padding-top: var(--space-3);
        border-top: 1px solid var(--border);
    }
    .topbar.nav-open nav {
        display: flex;
    }
    .topbar nav a,
    .topbar nav form,
    .locale-select,
    .user-menu {
        margin-left: 0;
    }
    .topbar nav form button {
        text-align: left;
    }
    /* Выпадашка .user-menu-dropdown в десктопной версии открывается по
       :hover — на тачскрине ховера физически нет. В мобильном (уже
       развёрнутом вертикально) меню она просто всегда видна как часть
       общего списка ссылок, без отдельного открытия/закрытия — те же
       3-4 пункта, что и на десктопе, лишний тап не нужен. */
    .user-menu-dropdown {
        display: block;
        position: static;
        border: none;
        box-shadow: none;
        padding: 0.35rem 0 0 0.75rem;
    }
    .user-menu-dropdown .user-menu-name {
        padding: 0 0 0.35rem;
    }
}

@media (max-width: 1100px) {
    .book-list.catalog-book-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .author-book-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .author-recommended-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .home-hero {
        grid-template-columns: minmax(0, 1fr);
        min-height: auto;
        text-align: center;
    }
    .home-hero-copy,
    .home-hero-title,
    .home-hero-lead {
        margin-inline: auto;
    }
    .home-hero-eyebrow,
    .home-hero-actions,
    .home-hero-author {
        justify-content: center;
    }
    .home-hero-cover {
        width: min(68vw, 14rem);
    }
    .home-book-grid,
    .home-mood-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .home-search-panel {
        grid-template-columns: minmax(0, 1fr);
    }
    .home-search-actions {
        grid-column: auto;
    }
    .home-workshop-grid {
        grid-template-columns: minmax(0, 1fr);
    }
    .home-lower-grid {
        grid-template-columns: minmax(0, 1fr);
    }
    .home-community-panel {
        min-height: 22rem;
    }
}

@media (max-width: 700px) {
    .book-list.catalog-book-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .author-book-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .author-profile-hero {
        grid-template-columns: minmax(0, 1fr);
        text-align: center;
    }

    .author-profile-photo {
        width: min(62vw, 14rem);
        justify-self: center;
    }

    .author-profile-genres,
    .author-profile-actions {
        justify-content: center;
    }

    .author-recommended-card {
        grid-template-columns: minmax(6.5rem, 9rem) minmax(0, 1fr);
    }

    .author-follow-panel {
        align-items: flex-start;
        flex-direction: column;
    }

    .catalog-filter-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .catalog-control-footer {
        align-items: flex-start;
        flex-direction: column;
    }


    .catalog-author-action {
        justify-content: stretch;
    }

    .catalog-author-action .button-secondary {
        width: 100%;
    }

    .home-release {
        grid-template-columns: minmax(0, 1fr);
    }
    .home-release-cover {
        width: min(58vw, 10rem);
        justify-self: center;
    }
    .home-section-heading,
    .home-release-content {
        text-align: center;
    }
    .home-release-meta,
    .home-release-stats,
    .home-release-actions {
        justify-content: center;
    }
    .home-section-heading-row {
        align-items: flex-start;
        flex-direction: column;
    }
    .home-book-grid,
    .home-mood-grid {
        grid-template-columns: minmax(0, 1fr);
    }
    .home-book-card {
        width: min(100%, 22rem);
        justify-self: center;
    }
    .home-mood-card {
        min-height: 13rem;
    }
    .home-author-spotlight {
        grid-template-columns: minmax(0, 1fr);
        text-align: center;
    }
    .home-author-photo {
        width: min(58vw, 12rem);
        justify-self: center;
    }
    .home-post-list {
        grid-template-columns: minmax(0, 1fr);
    }
    .home-workshop-card {
        grid-template-columns: minmax(5.5rem, 7rem) minmax(0, 1fr);
    }
}

@media (max-width: 600px) {
    .book-list.catalog-book-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .author-book-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    /* .container/.card padding — подобран под десктоп (1.5rem/1.25rem),
       на телефоне съедает заметную долю и без того узкого экрана. */
    .container,
    .page-header {
        padding-left: 1rem;
        padding-right: 1rem;
    }
    .card {
        padding: 1rem;
    }
    /* Обложка книги/аватар автора — фиксированные 196px/140px (см. выше)
       не переполняют экран сами по себе (.book-overview уже flex-wrap:
       wrap, обложка просто переносится на свою строку), но на маленьком
       телефоне выглядят непропорционально крупными рядом с более узкой
       колонкой метаданных — чисто эстетическая, не анти-overflow правка. */
    .book-cover-wrap {
        width: 150px;
    }
    .author-avatar-wrap {
        width: 110px;
    }
    /* min-width: 260px (десктопное значение) на очень узких телефонах
       (~320-360px логической ширины) вместе с padding .container/.card
       оставляет впритык — понижаем минимум, select остаётся auto-шириной
       (см. базовое правило выше), просто может стать уже. */
    .reader-toc-select {
        min-width: 0;
    }
}

/* Общая граница доступности для новой дизайн-системы: пользовательское
   предпочтение уменьшенного движения сильнее любых локальных анимаций.
   Оставляем практически мгновенное изменение состояния вместо полного
   удаления transition, чтобы компоненты не зависали в промежуточном виде. */
@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        scroll-behavior: auto !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* Баннер согласия на cookies (20.08.26, layouts/app.blade.php, прямой запрос
   автора: сайт ориентирован на европейский рынок, GDPR/ePrivacy Directive).
   Фиксированная полоска внизу экрана (согласовано с автором) — не закрывает
   контент, z-index выше обычного контента страницы, но ниже возможных
   модалок (--z-modal не заведён в проекте, 1000 — достаточный запас над
   .site-footer/.topbar, которые своего z-index не задают). Кнопки внутри
   переиспользуют существующие button/.button-secondary (см. выше в этом
   файле), новых цветов/паддингов для кнопок здесь не вводим. */
.cookie-consent-banner {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.5rem;
    background: var(--bg);
    border-top: 1px solid var(--border);
    box-shadow: var(--shadow-raised);
}

.cookie-consent-text {
    margin: 0;
    color: var(--text);
    font-size: 0.9rem;
    flex: 1 1 280px;
}

.cookie-consent-text a {
    color: var(--accent);
    white-space: nowrap;
}

.cookie-consent-actions {
    display: flex;
    gap: 0.75rem;
    flex-shrink: 0;
}

@media (max-width: 600px) {
    .cookie-consent-banner {
        padding: 1rem;
    }

    .cookie-consent-actions {
        width: 100%;
    }

    .cookie-consent-actions button {
        flex: 1 1 0;
    }
}

/* ==========================================================================
   Тёмная шапка/футер (22.08.26, docs/HOME_DESIGN_SPEC_v2.md, редизайн Home)
   — согласовано явно с автором: масштаб ЭТОЙ правки — ТОЛЬКО .topbar и
   .site-footer становятся общесайтовыми (тёмная тема, красный accent),
   тело всех страниц КРОМЕ Home продолжает использовать текущую светлую
   тему (--color-canvas и т.д. выше в файле) без изменений. Полный редизайн
   всего сайта — не эта задача (см. открытый вопрос в PROJECT_CONTEXT.md).

   Блок стоит в конце файла и переопределяет более ранние правила той же
   специфичности через порядок каскада (не !important) — тот же приём, что
   уже применяет .public-layout override в других местах файла.

   Логотип — изначально снят из шапки на время редизайна (заглушка-
   иллюстрация кролика от копии annamozgovaya.com, RGB без альфа-канала,
   на тёмном фоне рендерилась бы белым прямоугольником) и временно заменён
   текстовым wordmark (.topbar .brand-wordmark). Автор прислал настоящий
   логотип mozgovyi.com тем же вечером (public/images/template/logo.png,
   2172×724, PNG с альфа-каналом) — <img> вернулся в layouts/app.blade.php,
   класс .brand-wordmark и это правило больше нигде не используются,
   удалены как мёртвый CSS (не оставляем неиспользуемые классы "на
   всякий случай", см. общий принцип AI_RULES). */
.topbar {
    background: rgba(5, 6, 7, 0.92);
    border-bottom: 1px solid var(--dj-border);
    box-shadow: none;
}

.topbar nav a {
    color: var(--dj-muted);
}

.topbar nav a:hover,
.topbar nav a:focus-visible,
.topbar nav a.is-active,
.topbar nav a[aria-current="page"] {
    color: var(--dj-accent);
}

.topbar nav form button {
    color: var(--dj-muted);
}

.topbar nav form button:hover {
    color: var(--dj-accent);
}

.nav-toggle {
    border-color: var(--dj-border);
    color: var(--dj-text);
}

.nav-toggle:hover {
    border-color: var(--dj-accent);
    color: var(--dj-accent);
}

.locale-select {
    color: var(--dj-muted);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%239b9b9b' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.locale-select:hover,
.locale-select:focus-visible {
    color: var(--dj-accent);
    border-color: var(--dj-accent);
}

.locale-select option {
    /* Нативная выпадашка <select> рендерится ОС/браузером — часть не
       наследует --dj-text автоматически на всех платформах, задаём явно,
       чтобы текст опций не оставался тёмным на тёмном фоне на тех
       движках, где фон уже подхватывает color-scheme страницы. */
    color: var(--dj-text);
    background: var(--dj-surface);
}

.user-menu .user-menu-trigger {
    color: var(--dj-muted);
}

.user-menu:hover .user-menu-trigger,
.user-menu .user-menu-trigger:hover {
    color: var(--dj-accent);
}

.user-menu-dropdown {
    background: var(--dj-surface);
    border-color: var(--dj-border);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}

.user-menu-dropdown .user-menu-name {
    color: var(--dj-text);
}

.user-menu .user-menu-dropdown a,
.user-menu .user-menu-dropdown form button {
    color: var(--dj-muted);
}

.user-menu .user-menu-dropdown a:hover,
.user-menu .user-menu-dropdown form button:hover {
    color: var(--dj-accent);
    background: var(--dj-surface-hover);
}

@media (max-width: 1240px) {
    .topbar nav {
        border-top-color: var(--dj-border);
    }
}

.site-footer {
    background: var(--dj-bg-soft);
    border-top-color: var(--dj-border);
    color: var(--dj-muted);
}

.site-footer-links a {
    color: var(--dj-muted);
}

.site-footer-links a:hover {
    color: var(--dj-accent);
}

.site-footer-copy {
    color: var(--dj-muted);
}
