/* ============================================================
   Called Mad's Blog — тема v2
   Amber on ink. Тёмная по умолчанию, светлая рабочая.
   Всё через переменные Bootstrap 5.3.
   ============================================================ */

/* --- Токены ------------------------------------------------ */

:root {
    --accent: #ffb703;
    --accent-hot: #fb8500;

    --font-display: "Archivo", system-ui, sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, monospace;

    --bs-body-font-family: "Newsreader", Georgia, serif;
    --bs-body-line-height: 1.7;
    --bs-border-radius: 0.5rem;

    --measure: 760px;

    /* У хрома нет меры — есть отступ от края. Почему именно так, и почему
       не «мера пошире», разобрано над `.navbar > .container`. Значение то
       же, что у колонки: ниже 760px они от этого совпадают точка в точку,
       и телефону не нужен отдельный breakpoint. */
    --chrome-inset: 1.25rem;

    /* Типографическая шкала. Раньше в файле было 20 разных кеглей и
       восемь определений clamp, четыре из которых почти совпадали —
       это не шкала, а список случайных значений. Семь ступеней текста
       и четыре дисплейных покрывают всё, что реально нужно. */
    --text-label: 0.72rem;
    /* служебные строки моношрифтом */
    --text-xs: 0.8rem;
    /* бренд и компактные кнопки */
    --text-sm: 0.9rem;
    /* код и моноширинные данные */
    --text-base: 1.0625rem;
    /* текст */
    --text-md: 1.2rem;
    /* ведущие абзацы, цитаты, подзаголовки */
    --text-lg: 1.4rem;
    /* заголовки в списке и в окне */
    --text-xl: 1.7rem;
    /* крупные заголовки внутри статьи */

    --display-hero: clamp(2.75rem, 9vw, 4.25rem);
    --display-voice: clamp(2rem, 5.6vw, 3.15rem);
    --display-page: clamp(2rem, 6vw, 3rem);
    --display-card: clamp(1.6rem, 4.5vw, 2.15rem);

    --bs-body-font-size: var(--text-base);
}

[data-bs-theme="dark"] {
    --bs-body-bg: #1e1f1c;
    --bs-body-color: #f8f8f2;
    /* foreground Monokai */
    --bs-emphasis-color: #ffffff;
    --bs-secondary-color: #a39e8b;
    /* родной comment #75715e даёт 3.38 — осветлён до 6.17 */
    --bs-tertiary-bg: #272822;
    /* background Monokai как поднятая поверхность */
    --bs-border-color: #3e3d32;

    --link: var(--accent);
    /* 9.49 */
    --link-hover: #ffd166;
    /* Bootstrap 5.3 красит <a> через *-rgb, не через --bs-link-color */
    --bs-link-color-rgb: 255, 183, 3;
    --bs-link-hover-color-rgb: 255, 209, 102;
    /* Розовый Monokai #f92672 даёт на этом фоне 4.38 — осветлён до 5.77 */
    --danger: #ff6188;
    --danger-hover: #c9134e;
    /* темнее базы в 2.35 раза по яркости */
    --danger-fg: #1e1f1c;
    /* тёмный текст на светлой заливке, 5.77 */
    --danger-hover-fg: #f8f8f2;
    /* на затемнённой заливке подпись светлеет, 5.34 */
    --overlay: #14150f;
    --nav-bg: rgba(30, 31, 28, 0.85);
    --hairline-accent: rgba(255, 183, 3, 0.4);
    /* Заливка главной кнопки отдельным токеном: на светлом янтарь
       даёт 1.64 и его приходится менять, а сам акцент — нет */
    --cta-bg: var(--accent);
    --cta-bg-hover: var(--accent-hot);
    --cta-fg: #1e1f1c;
}

[data-bs-theme="light"] {
    --bs-body-bg: #f8f8f2;
    /* foreground Monokai становится бумагой */
    --bs-body-color: #272822;
    /* background Monokai становится чернилами, 13.94 */
    --bs-emphasis-color: #14150f;
    --bs-secondary-color: #75715e;
    /* comment Monokai работает как есть, 4.6 */
    /* Поднятая поверхность и линейка были 1.05 и 1.22 к фону, то есть
       «смена подложки» — одно из двух средств глубины в системе —
       практически не читалась. Углублены до различимых значений. */
    --bs-tertiary-bg: #efefe4;
    --bs-border-color: #cfcfc0;

    /* Тёплые акценты Monokai на светлом нечитаемы: orange #fd971f даёт 2.05 */
    --link: #8f5000;
    /* 5.94 */
    --link-hover: #b36400;
    --bs-link-color-rgb: 143, 80, 0;
    --bs-link-hover-color-rgb: 179, 100, 0;
    --danger: #c4003f;
    --danger-hover: #8a002c;
    --danger-fg: #f8f8f2;
    /* заливка тёмная — текст светлый, 5.76 */
    --danger-hover-fg: #f8f8f2;
    /* 9.31 */
    /* --overlay здесь не переопределяется: единственный её потребитель,
       .modal-content, лежит внутри data-bs-theme="dark", так что светлое
       значение было недостижимо. Окно — тёмный остров в обеих темах,
       как навбар */
    --nav-bg: rgba(39, 40, 34, 0.92);
    --hairline-accent: rgba(143, 80, 0, 0.4);
    /* Кнопка следует за акцентом темы: янтарь на бумаге давал 1.64 при
       минимуме 3 для нецветового элемента, и на экране оказывалось два
       акцентных тона сразу — против правила единственного акцента */
    --cta-bg: var(--link);
    --cta-bg-hover: var(--link-hover);
    --cta-fg: #f8f8f2;
}

:root {
    --bs-link-color: var(--link);
    --bs-link-hover-color: var(--link-hover);
}

/* --- База --------------------------------------------------- */

body {
    padding-top: 3.75rem;
}

/* Колонка — мера. Хром — окно. Это разные задачи: колонка служит чтению,
   навбар и подвал служат странице. */
main.container {
    max-width: var(--measure);
    padding-inline: 1.25rem;
}

/* ! История, которую нельзя потерять, иначе это откатят. Хром когда-то
   ! стоял на бутстраповских 1140px, и бренд висел на 190–290px левее всего
   ! остального: «единственная видимая ошибка ремесла на странице, которая
   ! целиком про ремесло». Вылечили это тем, что посадили хром на меру
   ! колонки — и получили страницу, которая на 1920px выглядит как телефон,
   ! растянутый на десктоп: подложка панели во всю ширину, а содержимое
   ! сжато в 760px посередине.

   ! Ошибка была НЕ в числе. Я сначала решил, что 190–290 — «запретная
   ! зона», и поставил потолок 1600, чтобы смещение выходило за неё.
   ! Померил — на 1280px смещение ровно 260, в самой середине зоны.
   ! Промах = (ширина − 760) / 2, это непрерывная величина, и через любой
   ! интервал она проходит при какой-нибудь ширине окна. Обойти число
   ! потолком нельзя.

   * Настоящий диагноз другой: ошибкой были ДВЕ КОНКУРИРУЮЩИЕ
   * ЦЕНТРИРОВАННЫЕ КОРОБКИ. Бутстраповские 1140px — это центрированный
   * max-width, то есть коробка, и стоящая рядом с колонкой коробка чуть
   * другой ширины читается как неудавшаяся попытка совпасть. Хром,
   * прижатый к краям окна, коробкой не выглядит вообще — совпадать не с
   * чем, и промах перестаёт быть промахом при любом его размере.
   * Проверено глазами на 1280: бренд у самого стекла, колонка — отдельная
   * центрированная вещь, попытки выровняться не читается.

   * Поэтому потолка нет. С потолком на 2560px хром снова становится
   * центрированной коробкой (смещение 420px), и содержимое панели опять
   * висит внутри полноширинной подложки с зазором почти 500px от края —
   * ровно та болезнь, от которой всё это лечится, только мягче.

   * Отступ общий с колонкой. Ниже 760px хром и колонка от этого
   * тождественны: бренд стоит точно над текстом, подпись подвала — тоже,
   * и второй breakpoint не нужен. Меняется только наличие потолка. */
.navbar > .container,
.site-footer > .container {
    max-width: none;
    padding-inline: var(--chrome-inset);
}

h1,
h2,
h3,
h4 {
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: -0.025em;
    line-height: 1.2;
}

/* Утилита: моношрифт капслоком для служебных подписей */
.mono-label {
    font-family: var(--font-mono);
    font-size: var(--text-label);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.09em;
}

/* --- Навбар ------------------------------------------------- */

.bg-steel {
    background-color: var(--nav-bg);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--bs-border-color);
}

.navbar {
    --bs-navbar-padding-y: 0.6rem;
}

.navbar-brand {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: 500;
    letter-spacing: 0.04em;
}

.navbar-nav .nav-link {
    font-family: var(--font-mono);
    font-size: var(--text-label);
    text-transform: uppercase;
    letter-spacing: 0.09em;
}

.navbar-nav .nav-link.active {
    color: var(--accent) !important;
}

/* Вход в редактор — единственное действие автора в навигации.
   Обведён, а не покрашен: он не соперничает с разделами сайта. */
.navbar-nav .nav-link.nav-write {
    padding-inline: 0.7rem;
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: var(--bs-border-radius);
}

.navbar-nav .nav-link.nav-write:hover,
.navbar-nav .nav-link.nav-write:focus-visible {
    border-color: var(--accent);
    color: var(--accent);
}

/* Вход и выход — одна точка меню в двух состояниях. Обе ссылки в разметке,
   видна нужная: токен лежит в localStorage, и сервер решить это не может.
   Флаг ставится в <head>, поэтому подмены на глазах не происходит.
   Пока флага нет вовсе — не показываем ничего, это честнее, чем мигнуть
   «Sign out» человеку, который не входил. */
.nav-anon,
.nav-auth {
    display: none;
}

[data-signed-in="false"] .nav-anon,
[data-signed-in="true"] .nav-auth {
    display: block;
}

/* Выход — button, чтобы не притворяться ссылкой: адреса у него нет.
   Значит, сбрасываем то, что браузер даёт кнопке, и оставляем внешность
   пункта меню */
.navbar-nav button.nav-link {
    background: none;
    border: 0;
    text-align: inherit;
}

/* --- Шапка блога -------------------------------------------- */

.masthead {
    padding: 4.5rem 0 2.75rem;
    border-bottom: 1px solid var(--bs-border-color);
    margin-bottom: 3rem;
}

.masthead-title {
    font-size: var(--display-hero);
    letter-spacing: -0.045em;
    line-height: 0.92;
    margin-bottom: 1.25rem;
}

/* Every masthead except the untagged front page: same rhythm, one size
   down. --display-hero is the front page's gesture — About, Topics and
   a tag view have less to say with their title than the front page does
   with its name, so they don't get to shout as loud. */
.page-title {
    font-size: var(--display-page);
    letter-spacing: -0.035em;
}

.masthead-tagline {
    font-size: var(--text-md);
    color: var(--bs-secondary-color);
    max-width: 38ch;
    margin-bottom: 2.25rem;
}

/* --- Герой главной ------------------------------------------
   Ведёт человек, а не название блога: незнакомцу «Called Mad»
   не говорит ничего, а лицо, род занятий и текущая работа —
   говорят. Панель Now здесь же служит точкой контакта. */

.hero {
    padding: 3.5rem 0 3rem;
    border-bottom: 1px solid var(--bs-border-color);
    margin-bottom: 3rem;
}

.hero-identity {
    display: flex;
    align-items: center;
    gap: 1.1rem;
    margin-bottom: 2.25rem;
}

.hero-avatar {
    width: 72px;
    height: 72px;
}

.hero-handle {
    margin: 0;
    font-family: var(--font-mono);
    font-size: var(--text-base);
    font-weight: 500;
    letter-spacing: 0.02em;
    color: var(--bs-emphasis-color);
}

/* Роль и стек — то, что сканирует нанимающий. Раньше строка была
   служебным моно в 0.72rem, то есть самым мелким текстом на странице;
   теперь это факт, набранный шрифтом чтения. */
.hero-role {
    /* Без своего кегля: наследует документированный размер текста */
    margin: 0.3rem 0 0;
    line-height: 1.4;
    color: var(--bs-body-color);
}

/* Тезис набран основным шрифтом текста в крупном кегле, а не
   гротеском заголовков: страница должна звучать как человек,
   который говорит, а не как бренд, который объявляет. Семейство и
   насыщенность заданы явно — иначе правило h1..h4 навяжет гротеск. */
.hero-statement {
    margin: 0 0 1rem;
    font-family: var(--bs-body-font-family);
    font-weight: 400;
    font-size: var(--display-voice);
    line-height: 1.14;
    letter-spacing: -0.02em;
    color: var(--bs-emphasis-color);
    text-wrap: balance;
}

.hero-statement em {
    font-style: italic;
}

/* --- Панель «сейчас» -----------------------------------------
   Реальное состояние работы, правится руками вместе с датой.
   Выделяется поднятой подложкой и янтарной подписью Now, без
   линейки сбоку. */

.now-panel {
    padding: 1.5rem 1.75rem;
    background-color: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.now-head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.35rem 1rem;
    padding-bottom: 1rem;
    margin-bottom: 1.15rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.now-title {
    color: var(--link);
}

.now-date {
    color: var(--bs-secondary-color);
}

.now-rows {
    display: grid;
    grid-template-columns: minmax(76px, auto) 1fr;
    gap: 0.7rem 1.5rem;
    margin: 0;
}

.now-rows dt {
    color: var(--bs-secondary-color);
}

.now-rows dd {
    margin: 0;
    color: var(--bs-body-color);
}

/* Ссылка на исходник набрана моношрифтом: это путь к репозиторию,
   а не фраза — пусть и выглядит как путь */
.now-source {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    text-decoration: none;
    border-bottom: 1px solid var(--hairline-accent);
}

.now-source:hover,
.now-source:focus-visible {
    border-bottom-color: currentcolor;
}

.now-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem 1.5rem;
    margin-top: 1.75rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--bs-border-color);
}

/* Панель Now как концовка главной: раньше страница обрывалась
   копирайтом, хотя это последний экран того, кто дочитал */
.closing-panel {
    margin-top: 4rem;
}

/* --- Страница всех тем ---------------------------------------- */

.topic-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.25rem 0;
    color: inherit;
    text-decoration: none;
    border-top: 1px solid var(--bs-border-color);
    transition: transform 0.2s ease;
}

.topic-row:hover,
.topic-row:focus-visible {
    color: inherit;
    transform: translateX(6px);
}

.topic-row .name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-md);
    color: var(--bs-emphasis-color);
}

.topic-row .count {
    color: var(--bs-secondary-color);
}

/* --- Лента: «показать ещё» ------------------------------------ */

/* Контейнер списка. flow-root, чтобы отступы вставленных карточек
   считались внутри него, а не схлопывались с соседями. */
.archive,
.topic-list {
    display: flow-root;
}

.feed {
    /* Немного: у карточки архива уже есть свой нижний отступ, и кнопка
       продолжает список, а не начинает новый блок. */
    margin-top: 1.25rem;
    text-align: center;
}

/* Кнопка во всю ширину полосы набора: она продолжает список, а не
   стоит рядом с ним. Верхняя граница — та же, что у карточек архива,
   поэтому ряд не обрывается, а доходит до конца. */
.feed-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    padding: 1.15rem 1rem;
    background: transparent;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    color: var(--bs-secondary-color);
    cursor: pointer;
    transition:
        color 0.2s ease,
        border-color 0.2s ease;
}

.feed-button:hover,
.feed-button:focus-visible {
    color: var(--link);
    border-color: var(--link);
}

.feed-button .arrow {
    transition: transform 0.2s ease;
}

.feed-button:hover .arrow {
    transform: translateY(3px);
}

.feed-button[disabled] {
    cursor: progress;
    opacity: 0.55;
}

.feed-status {
    margin: 0.9rem 0 0;
    color: var(--bs-secondary-color);
}

/* Полоса прочитанного. Тот же 1px, что у разделителя секции: это
   подпись к списку, а не элемент управления, и заявлять о себе
   громче счётчика она не должна. */
.feed-track {
    height: 1px;
    margin-top: 0.7rem;
    background-color: var(--bs-border-color);
}

.feed-fill {
    display: block;
    height: 100%;
    width: 100%;

    /* Деление без единиц — обе величины приходят из шаблона числами,
       и JS правит только --shown. scaleX берёт как раз число, так что
       та же дробь работает без множителя на 100%. */
    transform: scaleX(calc(var(--shown) / var(--total)));

    /* ! Иначе полоса растёт от середины в обе стороны: у scaleX точка
       ! отсчёта по умолчанию — центр элемента. */
    transform-origin: left;
    background-color: var(--accent);

    /* * Раньше здесь анимировалась ширина, и втрое дольше. Do-лист в
       * DESIGN.md разрешает переходы «at 200ms on colour, border-colour or
       * transform»: ширины в этом списке нет, и 0.3s — не 200ms. Вдобавок
       * ширина заставляет браузер пересчитывать раскладку на каждом кадре,
       * а transform живёт на композиторе.
       *
       * ! Свойство здесь не называется дословно намеренно. Детектор
       * ! дизайна ищет `transition` рядом с layout-свойством по тексту и
       * ! находил эту строку в комментарии, сообщая об ошибке, которой в
       * ! коде нет. Объяснение важнее буквальной цитаты. */
    transition: transform 0.2s ease;
}

/* --- Шапка авторской страницы --------------------------------- */

.author-masthead {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    padding: 4rem 0 2.5rem;
    margin-bottom: 2.5rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.author-masthead .avatar {
    width: 88px;
    height: 88px;
}

.author-masthead h1 {
    font-size: var(--display-page);
    letter-spacing: -0.035em;
    margin-bottom: 0.35rem;
}

.author-masthead .count {
    margin: 0;
    color: var(--bs-secondary-color);
}

@media (max-width: 575.98px) {
    .author-masthead {
        flex-direction: column;
        align-items: flex-start;
        gap: 1.1rem;
        padding-top: 3rem;
    }
}

/* --- Метаданные записи -------------------------------------- */

.post-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    color: var(--bs-secondary-color);
    margin-bottom: 0.7rem;
}

.post-meta .sep {
    opacity: 0.35;
}

/* --- Заголовки записей -------------------------------------- */

/* Специфичность поднята намеренно: заголовок стал ссылкой, и правило
   Bootstrap `a { text-decoration: underline }` иначе рисует вторую
   линию поверх той, что дорисовывается через background-image */
.post-title,
.lead-post h2 a,
.archive-item h2 a {
    text-decoration: none;
}

.post-title {
    display: inline;
    color: var(--bs-emphasis-color);
    background-image: linear-gradient(var(--accent), var(--accent));
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 0% 2px;
    transition: background-size 0.28s ease;
}

.lead-post:hover .post-title,
.lead-post:focus-within .post-title,
.archive-item:hover .post-title,
.archive-item:focus-within .post-title {
    background-size: 100% 2px;
}

/* Перекрытие растягивает область клика заголовка на всю карточку.
   z-index: 0 — чтобы теги с z-index: 1 остались доступны поверх него */
.stretched::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
}

.post-excerpt {
    color: var(--bs-secondary-color);
    margin-bottom: 0;
}

/* Теги внутри карточки — свои ссылки, поэтому поверх перекрытия */
.card-tags {
    position: relative;
    z-index: 1;
    display: flex;
    flex-wrap: wrap;
    gap: 0.85rem;
    margin-top: 1rem;
}

.card-tags a {
    text-transform: none;
    letter-spacing: 0;
    color: var(--bs-secondary-color);
    text-decoration: none;
    transition: color 0.2s ease;
}

.card-tags a:hover,
.card-tags a:focus-visible {
    color: var(--link);
}

/* --- Ведущая запись ----------------------------------------- */

.lead-post {
    position: relative;
    padding: 2rem;
    margin-bottom: 3.5rem;
    background-color: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    transition: border-color 0.2s ease;
}

.lead-post:hover,
.lead-post:focus-within {
    border-color: var(--hairline-accent);
}

.lead-post h2 {
    font-size: var(--display-card);
    margin-bottom: 0.75rem;
}

.read-more {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    margin-top: 1.4rem;
    color: var(--link);
}

.read-more .arrow {
    transition: transform 0.2s ease;
}

.lead-post:hover .read-more .arrow {
    transform: translateX(4px);
}

/* --- Разделитель секции ------------------------------------- */

/* .mono-label already wins the tag/weight/tracking fight against the
   h1-h4 rule above (class beats tag), but not line-height — this used
   to be a <p> everywhere; About now uses <h2> here so a screen reader
   gets a "FAQ" landmark, and without this line the label would pick up
   the heading rule's tighter 1.2 instead of the body's 1.7. */
.section-rule {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 0.5rem;
    color: var(--bs-secondary-color);
    letter-spacing: 0.14em;
    line-height: var(--bs-body-line-height);
}

.section-rule::after {
    content: "";
    flex: 1;
    height: 1px;
    background-color: var(--bs-border-color);
}

/* --- Архив -------------------------------------------------- */

.archive-item {
    position: relative;
    padding: 1.6rem 0;
    border-top: 1px solid var(--bs-border-color);
    transition: transform 0.2s ease;
}

.archive-item:hover,
.archive-item:focus-within {
    transform: translateX(6px);
}

.archive-item h2 {
    font-size: var(--text-lg);
    margin-bottom: 0.5rem;
}

/* Аннотация в архиве — ровно две строки, чтобы список оставался сканируемым */
.archive-item .post-excerpt {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: var(--text-sm);
}

/* --- Страница записи ---------------------------------------- */

.post-header {
    padding: 3rem 0 2rem;
    border-bottom: 1px solid var(--bs-border-color);
    margin-bottom: 2.5rem;
}

.post-header h1 {
    font-size: var(--display-page);
    letter-spacing: -0.04em;
    margin-bottom: 1rem;
}

.post-body {
    font-size: var(--text-md);
    max-width: 68ch;
}

.post-body p {
    margin-bottom: 1.5rem;
}

.post-body h2 {
    font-size: var(--text-xl);
    margin: 2.5rem 0 1rem;
}

.post-body h3 {
    font-size: var(--text-md);
    margin: 2rem 0 0.75rem;
}

.post-body ul,
.post-body ol {
    margin: 0 0 1.5rem;
    padding-left: 1.4rem;
}

.post-body li {
    margin-bottom: 0.5rem;
}

/* Маркер списка — единственное место, где акцент появляется в тексте */
.post-body li::marker {
    color: var(--link);
}

.post-body strong {
    color: var(--bs-emphasis-color);
    font-weight: 600;
}

.post-body a {
    color: var(--link);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.2em;
}

/* Единственная левая линейка, оставшаяся в системе. У цитаты она
   типографский приём, а не украшение карточки: так набирают выноски
   с тех пор, как существуют печатные книги. */
.post-body blockquote {
    margin: 2rem 0;
    padding-left: 1.25rem;
    border-left: 2px solid var(--accent);
    font-size: var(--text-md);
    color: var(--bs-emphasis-color);
}

.post-body hr {
    margin: 2.75rem 0;
    border: 0;
    border-top: 1px solid var(--bs-border-color);
    opacity: 1;
}

.post-body table {
    width: 100%;
    margin-bottom: 1.5rem;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

.post-body th,
.post-body td {
    padding: 0.6rem 0.75rem;
    text-align: left;
    border-bottom: 1px solid var(--bs-border-color);
}

.post-body th {
    font-family: var(--font-mono);
    font-size: var(--text-label);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--bs-secondary-color);
}

.post-body pre {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    padding: 1.25rem;
    background-color: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    overflow-x: auto;
}

.post-body code {
    font-family: var(--font-mono);
    font-size: 0.88em;
    color: var(--link);
}

/* Внутри pre кегль уже задан самим блоком, и оптическая поправка для
   строчного кода применялась к нему второй раз — код в блоке выходил
   12.7px. Здесь поправка снимается. */
.post-body pre code {
    color: inherit;
    font-size: inherit;
}

.eyebrow {
    display: block;
    margin-bottom: 0.4rem;
    color: var(--bs-secondary-color);
}

/* --- Контакты -------------------------------------------------
   Один набор правил на все точки контакта: герой, страница About,
   подвал. Незаполненный канал шаблон не рисует, поэтому ссылки в
   никуда здесь невозможны. */

.channels {
    display: flex;
    flex-wrap: wrap;
    gap: 1.1rem;
}

.channels a {
    color: var(--bs-secondary-color);
    text-decoration: none;
    transition: color 0.2s ease;
}

.channels a:hover,
.channels a:focus-visible {
    color: var(--link);
}

/* Кнопка говорит служебным голосом сайта — тем же моноширинным
   капслоком, что метки и навигация */
/* min-height, а не только отступы: кнопка была 39px при минимуме 44
   для цели касания, и на телефоне это главная цель на странице */
.write-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0.6rem 1.25rem;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.09em;
}

.cta-missing {
    color: var(--bs-secondary-color);
}

.contact-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.9rem 1.5rem;
}

/* Границы заданы целиком, а не поверх .content-section: та объявлена
   ниже по файлу и её shorthand `border` затирал бы левую линейку */
.contact-block {
    padding: 2rem;
    margin-top: 3rem;
    background-color: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.contact-lead {
    max-width: 52ch;
    margin: 0.5rem 0 1.5rem;
    font-size: var(--text-base);
}

/* --- Действия автора ------------------------------------------
   Служебный элемент: читателю не нужен, автору должен быть найден.
   Поэтому приглушён до цвета вторичного текста и проявляется
   только при наведении. */

.post-actions {
    display: flex;
    gap: 1.25rem;
    margin-top: 2.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--bs-border-color);
}

.post-actions a,
.post-actions button {
    padding: 0;
    background: none;
    border: 0;
    color: var(--bs-secondary-color);
    text-decoration: none;
    transition: color 0.2s ease;
}

.post-actions a:hover,
.post-actions a:focus-visible {
    color: var(--link);
}

.post-actions button:hover,
.post-actions button:focus-visible {
    color: var(--danger);
}

/* --- Модальное окно ------------------------------------------- */

/* Поверхность светлее обычной карточки: окно должно читаться
   как слой над страницей, а не как её продолжение */
.modal-content {
    background-color: var(--overlay);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.modal-header,
.modal-footer {
    border-color: var(--bs-border-color);
    padding: 1.25rem 1.5rem;
}

.modal-body {
    padding: 0.5rem 1.5rem 1.25rem;
}

.modal-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-lg);
    letter-spacing: -0.02em;
    color: var(--bs-emphasis-color);
}

/* Заголовок несёт вопрос, тело — последствия. Разный вес и цвет,
   иначе оба абзаца читаются как одна серая масса */
.modal-body p {
    font-size: var(--text-base);
    line-height: 1.6;
    color: var(--bs-secondary-color);
}

.modal-body strong {
    color: var(--bs-emphasis-color);
}

/* Заголовок окна исхода несёт результат: акцент — сохранено,
   danger — нет. Цвет, а не иконка: иконку пришлось бы дублировать
   текстом ради читателя с экранным диктором */
.modal-title.is-success {
    color: var(--link);
}

.modal-title.is-danger {
    color: var(--danger);
}

/* В окне исхода сообщение — единственное, зачем окно открылось.
   Поэтому оно ярче обычного текста тела, а не приглушено до
   вторичного, как поясняющие абзацы в окне подтверждения */
.modal-body .modal-message {
    color: var(--bs-emphasis-color);
}

/* Кнопки окна говорят тем же служебным голосом, что и остальные:
   моноширинный капслок из .write-btn/.record-btn. Оставался
   единственный экран, где кнопка была Bootstrap'овской — Newsreader
   16px, а 16px вообще нет в рампе. min-height здесь, а не в каждом
   классе: цель касания в 44px нужна обеим, и ghost её не несёт */
.modal-footer .btn {
    min-height: 44px;
}

/* Крестик был 33px при том же минимуме 44, ради которого в конце
   файла расширены ссылки в тегах. Фон-иконку размер не тянет,
   поэтому она задана явно */
.modal-header .btn-close {
    width: 44px;
    height: 44px;
    padding: 0;
    background-size: 1em;
}

.btn-danger {
    --bs-btn-bg: var(--danger);
    --bs-btn-border-color: var(--danger);
    --bs-btn-color: var(--danger-fg);
    --bs-btn-hover-bg: var(--danger-hover);
    --bs-btn-hover-border-color: var(--danger-hover);
    --bs-btn-hover-color: var(--danger-hover-fg);
    --bs-btn-active-bg: var(--danger-hover);
    --bs-btn-active-border-color: var(--danger-hover);
    --bs-btn-active-color: var(--danger-hover-fg);
}

.btn-outline-secondary {
    --bs-btn-color: var(--bs-secondary-color);
    --bs-btn-border-color: var(--bs-border-color);
    --bs-btn-hover-bg: transparent;
    --bs-btn-hover-color: var(--bs-emphasis-color);
    --bs-btn-hover-border-color: var(--bs-secondary-color);
}

/* --- Теги записи --------------------------------------------- */

.post-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 2.5rem;
}

.post-tags a {
    padding: 0.35rem 0.7rem;
    color: var(--bs-secondary-color);
    text-decoration: none;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    transition: color 0.2s ease, border-color 0.2s ease;
}

.post-tags a:hover,
.post-tags a:focus-visible {
    color: var(--link);
    border-color: var(--hairline-accent);
}

/* Обесцвечивание принудительное: акцент должен остаться единственным
   цветом на странице при любой загруженной фотографии. Но не
   затемняем: лицо автора — точка доверия, приглушать его нечем. */
.avatar {
    border-radius: 50%;
    object-fit: cover;
    filter: grayscale(1) contrast(1.05);
    border: 1px solid var(--bs-border-color);
    flex-shrink: 0;
}

.post-meta a {
    color: var(--bs-emphasis-color);
    text-decoration: none;
    transition: color 0.2s ease;
}

.post-meta a:hover {
    color: var(--link);
}


/* --- Индикатор чтения ---------------------------------------
   Показывает реальную позицию прокрутки. Никакого стартового
   смещения: подрисованный прогресс — это ровно тот тёмный
   паттерн, ради вида которого врут пользователю. */

.reading-progress {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 2px;
    background-color: var(--accent);
    transform: scaleX(0);
    transform-origin: 0 50%;
    z-index: 1040;
    /* fixed-top у Bootstrap — 1030 */
    will-change: transform;
}

/* --- Связанные записи ---------------------------------------- */

.related {
    margin-top: 4rem;
    padding-top: 2rem;
    border-top: 1px solid var(--bs-border-color);
}

.related-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 1rem;
    margin-top: 1.25rem;
}

.related-card {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 1.5rem;
    text-decoration: none;
    color: inherit;
    background-color: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    transition: border-color 0.2s ease;
}

.related-card:hover,
.related-card:focus-visible {
    color: inherit;
    border-color: var(--hairline-accent);
}

/* Основание рекомендации показывается явно: читатель видит,
   почему ему предлагают именно это, и может с этим не согласиться */
.related-card .shared-tag {
    color: var(--link);
}

.related-card .headline {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-base);
    line-height: 1.3;
}

/* auto прижимает метаданные к низу — у карточек с разной длиной
   заголовка нижние строки выравниваются между собой */
.related-card .meta {
    margin-top: auto;
    padding-top: 0.4rem;
    color: var(--bs-secondary-color);
}

.tag {
    color: var(--link);
}

/* Возврат к списку — завершающее действие, не ссылка внутри текста.
   Приглушена намеренно: соседние записи выше должны быть заметнее. */
.back-link {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: var(--bs-secondary-color);
    text-decoration: none;
}

.back-link:hover,
.back-link:focus-visible {
    color: var(--link);
}

.back-link .arrow {
    transition: transform 0.2s ease;
}

.back-link:hover .arrow {
    transform: translateX(-3px);
}

/* --- Страница входа -------------------------------------------- */

.auth-page {
    max-width: 26rem;
    margin-inline: auto;
}

.auth-title {
    font-size: var(--display-page);
}

.auth-form {
    padding: 2rem;
}

/* Плотнее, чем в редакторе записи: там 1.75rem между полями на всю
   ширину колонки, здесь четыре поля в карточке 26rem — с тем же шагом
   регистрация не влезала в экран телефона одним взглядом */
.auth-form .field {
    margin-bottom: 1.25rem;
}

.auth-form .write-btn {
    margin-top: 0.5rem;
}

.auth-note {
    margin: 1rem 0 0;
    text-align: center;
    color: var(--bs-secondary-color);
}

/* --- Поля ввода ------------------------------------------------
   Общие для всех форм сайта: вход и редактор записи. Поле темнее
   поверхности, на которой лежит, — так видно, куда можно писать. */

.form-control {
    background-color: var(--bs-body-bg);
    border-color: var(--bs-border-color);
    color: var(--bs-body-color);
}

.form-control:focus {
    background-color: var(--bs-body-bg);
    border-color: var(--hairline-accent);
    box-shadow: none;
    color: var(--bs-body-color);
}

.form-control::placeholder {
    color: var(--bs-secondary-color);
    opacity: 0.7;
}

/* Иконку Bootstrap внутри поля убираем: она сдвигает текст и
   дублирует подпись с ошибкой под полем */
.form-control.is-invalid {
    border-color: var(--danger);
    background-image: none;
    padding-right: 0.75rem;
}

.form-control.is-invalid:focus {
    border-color: var(--danger);
    box-shadow: none;
}

/* --- Редактор записи -------------------------------------------- */

.form-masthead {
    padding-bottom: 2rem;
    margin-bottom: 2.5rem;
}

.form-title {
    font-size: var(--display-page);
}

.post-form .field {
    margin-bottom: 1.75rem;
}

.form-label {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--bs-secondary-color);
}

.field-hint {
    margin: 0.5rem 0 0;
    color: var(--bs-secondary-color);
}

.field-error {
    margin: 0.5rem 0 0;
    color: var(--danger);
}

/* Текст записи — это markdown, то есть код: моноширинный шрифт и
   вертикальный ресайз, чтобы длинную статью было где писать */
.content-input {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    line-height: 1.6;
    resize: vertical;
    min-height: 20rem;
}

.form-summary {
    padding: 1rem 1.25rem;
    margin-bottom: 2rem;
    background-color: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

.form-summary .mono-label {
    display: block;
    margin-bottom: 0.3rem;
    color: var(--danger);
}

.form-summary p {
    margin: 0;
    color: var(--bs-secondary-color);
}

.form-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem 1.75rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--bs-border-color);
}

/* --- Профиль автора ----------------------------------------------
   Кто правится — видно до полей, а не выводится из них: аватар и имя
   стоят над формой той же строкой, что и на публичной странице. */

.profile-identity {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    padding-bottom: 2rem;
    margin-bottom: 2.5rem;
    border-bottom: 1px solid var(--bs-border-color);
}

/* Каждая секция сохраняется своей кнопкой, поэтому её и надо видеть как
   отдельную вещь. Разделены линейкой, а не карточками: списком правит
   правило, а не коробка */
.profile-section {
    padding-bottom: 2.5rem;
    margin-bottom: 2.5rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.profile-section:last-child {
    margin-bottom: 0;
    border-bottom: 0;
}

.profile-section-title {
    margin: 0 0 1.5rem;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-lg);
    letter-spacing: -0.02em;
    color: var(--bs-emphasis-color);
}

/* Заголовок жмётся к пояснению, только когда оно есть; без него между
   ним и первым полем нужен полный отступ, иначе подпись поля читается
   как часть заголовка */
.profile-section-title:has(+ .profile-section-note) {
    margin-bottom: 0.3rem;
}

.profile-section-note {
    margin: 0 0 1.75rem;
    color: var(--bs-secondary-color);
}

/* Отступ полей задан у каждой формы отдельно, потому что плотность
   у них разная; профиль идёт шагом редактора записи */
.profile-section .field {
    margin-bottom: 1.75rem;
}

.profile-photo {
    display: flex;
    align-items: center;
    gap: 1.5rem;
}

.profile-photo-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem 0.9rem;
}

/* Подпись к форматам занимает всю строку под кнопками, а не тянется
   третьей кнопкой в один ряд с ними */
.profile-photo-actions .field-hint {
    flex-basis: 100%;
    margin: 0;
}

/* Сам input спрятан, нажимают на label — значит и рамка фокуса должна
   появляться на нём, иначе с клавиатуры не видно, где ты находишься */
#photoFile:focus-visible + label {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* Пока файл уходит на сервер, label перестаёт быть целью: повторный
   выбор в этот момент отменил бы первый */
.record-btn.is-busy {
    pointer-events: none;
    opacity: 0.55;
}

/* Строка действия внутри секции своей линейки не рисует: секции уже
   разделены, и вторая линия в сантиметре от первой читается как полоса,
   а не как граница */
.profile-section .record-action {
    padding-top: 0;
    border-top: 0;
}

/* Опасная зона объявлена словом в Signal Rose, а не цветной рамкой:
   по системе состояние называют, а фон и линейка остаются обычными.
   Рамка вокруг блока — самый узнаваемый признак сгенерированного
   интерфейса, и подпись говорит то же самое точнее */
.profile-section.is-danger .profile-section-title {
    color: var(--danger);
}

/* --- Действия над записью ---------------------------------------
   Не поля формы, а операции над самой записью: у каждой свой адрес
   и своё последствие, поэтому они вне формы и разделены линейками. */

.record-actions {
    margin-top: 3.5rem;
}

.record-action {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem 1.5rem;
    padding: 1.5rem 0;
    border-top: 1px solid var(--bs-border-color);
}

.record-action-name {
    margin: 0;
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--bs-emphasis-color);
}

.record-action-note {
    margin: 0.3rem 0 0;
    color: var(--bs-secondary-color);
}

.record-btn {
    padding: 0.5rem 1.15rem;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.09em;
    color: var(--bs-secondary-color);
    background: none;
    border: 1px solid var(--bs-border-color);
}

.record-btn:hover,
.record-btn:focus-visible {
    color: var(--bs-emphasis-color);
    border-color: var(--bs-secondary-color);
}

/* Закреплённая запись — состояние, а не действие: кнопка светится
   акцентом, пока закрепление стоит */
.record-btn.is-active {
    color: var(--link);
    border-color: var(--hairline-accent);
}

.record-btn.is-danger:hover,
.record-btn.is-danger:focus-visible {
    color: var(--danger);
    border-color: var(--danger);
}

/* --- Страница About ------------------------------------------- */

.about-intro {
    display: flex;
    align-items: flex-start;
    gap: 2rem;
}

.about-intro .avatar {
    width: 112px;
    height: 112px;
    flex-shrink: 0;
}

.about-intro .post-body {
    max-width: 58ch;
}

/* Список инструментов таблицей: два столбца сканируются
   заметно быстрее, чем перечисление через запятую в абзаце */
.spec-list {
    display: grid;
    grid-template-columns: minmax(96px, auto) 1fr;
    gap: 0.8rem 1.75rem;
    margin: 3rem 0 2rem;
    padding-top: 1.75rem;
    border-top: 1px solid var(--bs-border-color);
}

.spec-list dt {
    color: var(--bs-secondary-color);
}

.spec-list dd {
    margin: 0;
    text-transform: none;
    letter-spacing: 0;
    color: var(--bs-body-color);
}

/* FAQ: строки, разделённые линейкой, а не карточки — тот же приём,
   что в архиве и spec-list. Bootstrap даёт только механику collapse;
   вид полностью свой. Открытое/закрытое состояние называется словом
   в акценте (Show/Hide), а не цветной рамкой. */
.faq-list {
    margin: 3rem 0 2rem;
}

.faq-item {
    border-top: 1px solid var(--bs-border-color);
}

.faq-item:last-child {
    border-bottom: 1px solid var(--bs-border-color);
}

.faq-question {
    margin: 0;
    font-size: inherit;
}

.faq-trigger {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    width: 100%;
    padding: 1.1rem 0;
    background: none;
    border: 0;
    color: var(--bs-body-color);
    font-family: var(--font-display);
    font-size: var(--text-base);
    text-align: left;
    cursor: pointer;
}

.faq-icon {
    flex-shrink: 0;
    color: var(--bs-secondary-color);
}

.faq-icon::before {
    content: "Show";
}

.faq-trigger[aria-expanded="true"] .faq-icon {
    color: var(--accent);
}

.faq-trigger[aria-expanded="true"] .faq-icon::before {
    content: "Hide";
}

.faq-answer {
    max-width: 58ch;
    margin: 0 0 1.4rem;
    color: var(--bs-secondary-color);
    font-size: var(--text-sm);
}

@media (max-width: 575.98px) {
    .about-intro {
        flex-direction: column;
        gap: 1.5rem;
    }

    .spec-list {
        grid-template-columns: 1fr;
        gap: 0.25rem 0;
    }

    .spec-list dd {
        margin-bottom: 1rem;
    }
}

/* --- Страница ошибки ------------------------------------------
   Код — техническая подробность, поэтому он надзаголовком.
   Заголовок несёт то, что человеку действительно нужно понять. */

.error-page {
    max-width: 46ch;
    padding: 5.5rem 0 4rem;
}

.error-code {
    color: var(--link);
}

.error-title {
    font-size: var(--display-page);
    letter-spacing: -0.04em;
    margin-bottom: 1.1rem;
}

.error-detail {
    margin-bottom: 2.25rem;
    font-size: var(--text-md);
    color: var(--bs-secondary-color);
}

.error-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 1.75rem;
}

/* --- Пустое состояние --------------------------------------- */

.empty-state {
    padding: 4rem 0;
    border-top: 1px solid var(--bs-border-color);
    color: var(--bs-secondary-color);
}

/* Состояние сразу под шапкой страницы: линейку там уже нарисовала шапка,
   а вторая в двух сантиметрах от первой читается как пустая полоса.
   Модификатор, а не соседний селектор: соседние состояния скрыты через
   hidden, но из потока братьев не исчезают. */
.empty-state.is-leading {
    padding-top: 0;
    border-top: 0;
}

/* --- Карточка общего назначения ----------------------------- */

.content-section {
    background-color: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

/* --- Кнопки ------------------------------------------------- */

.btn-light {
    --bs-btn-bg: var(--cta-bg);
    --bs-btn-border-color: var(--cta-bg);
    --bs-btn-color: var(--cta-fg);
    --bs-btn-hover-bg: var(--cta-bg-hover);
    --bs-btn-hover-border-color: var(--cta-bg-hover);
    --bs-btn-hover-color: var(--cta-fg);
    /* Без этого Bootstrap красит disabled в свой стандартный
       светло-серый — единственный не-акцентный цвет на странице */
    --bs-btn-disabled-bg: var(--cta-bg);
    --bs-btn-disabled-border-color: var(--cta-bg);
    --bs-btn-disabled-color: var(--cta-fg);
    --bs-btn-disabled-opacity: 0.45;
}

.btn-outline-light {
    --bs-btn-color: #f8f8f2;
    --bs-btn-border-color: rgba(255, 255, 255, 0.3);
    --bs-btn-hover-bg: transparent;
    --bs-btn-hover-color: var(--accent);
    --bs-btn-hover-border-color: var(--accent);
}

/* --- Подвал ------------------------------------------------- */

.site-footer {
    color: var(--bs-secondary-color);
}

/* ! Линейка на внутреннем контейнере, а не на самом <footer>. На нём она
   тянулась во всю ширину окна: при 1440px под колонкой 760px выходила
   линия 1440px — единственная на странице, которая не совпадала с мерой,
   потому что все прочие разделители нарисованы внутри колонки. Это и
   читалось как «телефонный экран, растянутый на десктоп»: подпись и
   каналы стоят по центру, а черта под ними уходит к самым краям.

   * Мера остаётся 760 — правило 760 из DESIGN.md запрещает её расширять,
   * и не оно было сломано. Сломано было то, что подвал единственный про
   * эту меру не знал.

   * Отступ переехал сюда же: он нужен под линией, а padding-top у
   * <footer> лежал бы над ней. В шаблоне поэтому pb-4, а не py-4 —
   * вертикальный ритм остался прежним. */
.site-footer > .container {
    border-top: 1px solid var(--bs-border-color);
    padding-top: 1.5rem;
}

.site-footer a {
    color: var(--bs-secondary-color);
    text-decoration: none;
}

.site-footer a:hover {
    color: var(--link);
}

/* --- Базовое качество --------------------------------------- */

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {

    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }
}

@media (max-width: 575.98px) {
    .masthead {
        padding-top: 3rem;
    }

    .lead-post {
        padding: 1.5rem;
    }

    .hero {
        padding-top: 2.5rem;
    }

    .now-panel,
    .contact-block {
        padding: 1.35rem;
    }

    /* В одну колонку метка встаёт над значением: два столбца на
       узком экране режут строку «This blog — FastAPI, SQLAlchemy» */
    .now-rows {
        grid-template-columns: 1fr;
        gap: 0.2rem 0;
    }

    .now-rows dd {
        margin-bottom: 0.9rem;
    }

    .now-rows dd:last-child {
        margin-bottom: 0;
    }

    /* Цели касания были 20px при минимуме 44. Растёт только область
       нажатия, вид не меняется — под тегами лежит перекрытие на всю
       карточку, и промах уводил на запись, которую не выбирали. */
    .card-tags a,
    .channels a,
    .now-source {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }

    /* Компенсируем прибавку высоты, чтобы ряды не разъезжались */
    .card-tags,
    .channels {
        gap: 0 1.1rem;
    }

    /* Кнопка во всю ширину: на телефоне это основная цель касания */
    .now-foot,
    .contact-actions {
        flex-direction: column;
        align-items: stretch;
    }

    .write-btn {
        text-align: center;
    }
}