/* ===== FONTS (локальные, latin+cyrillic) ===== */
@font-face {
    font-family: 'Manrope';
    src: url('/static/fonts/manrope-v20-cyrillic_latin-regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Manrope';
    src: url('/static/fonts/manrope-v20-cyrillic_latin-500.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Manrope';
    src: url('/static/fonts/manrope-v20-cyrillic_latin-600.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Manrope';
    src: url('/static/fonts/manrope-v20-cyrillic_latin-700.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Manrope';
    src: url('/static/fonts/manrope-v20-cyrillic_latin-800.woff2') format('woff2');
    font-weight: 800;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Yeseva One';
    src: url('/static/fonts/yeseva-one-v24-cyrillic_latin-regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

/* ===== RESET & BASE ===== */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

:root {
    --bg: #12141d;
    --bg2: #1b1f2e;
    --text: #f3efe6;
    --text-muted: #a9adc4;
    --accent: #92B2F4;
    --purple: #a58ce0;
    --purple2: #7c93e0;
    --border: rgba(255,255,255,0.08);
    --grad: linear-gradient(135deg, #7c93e0, #a58ce0);
    /* Всё, что говорит покупателю об остатке: малый остаток на странице товара
       и предупреждения «в корзине больше, чем есть». Переменной, а не тремя
       копиями значения, — иначе при следующей смене цвета одно место останется
       прежним и заметить это будет нечем. */
    --accent-stock: #FF4589;
}

/* Без overflow-x: hidden — и это не упущение. Правило отменяло sticky у шапки:
   элемент с любым overflow, кроме visible, становится контейнером прокрутки для
   потомков, и шапка прилипала не к экрану, а к нему — то есть уезжала вверх
   вместе со страницей. Замер это подтверждал: после прокрутки на 452px верх
   шапки оказывался на −452.

   Появилось правило ради декоративных звёзд, разбросанных по странице
   абсолютным позиционированием; их давно заменил канвас с position: fixed,
   который на ширину документа не влияет (см. starfield.css). Причина ушла,
   правило осталось — и попутно прятало настоящее переполнение: растянутый
   флажок согласия на странице контактов и заголовок политики, не влезавший в
   ширину телефона. Обе поломки нашлись в ту же минуту, когда правило убрали.

   Сторож на будущее — TC_E2E_20: он обходит все страницы покупателя на двух
   ширинах и сравнивает scrollWidth с clientWidth. */
body {
    background: var(--bg);
    color: var(--text);
    font-family: 'Manrope', sans-serif;
    min-height: 100vh;
}

a { color: var(--text-muted); text-decoration: none; }
a:hover { color: var(--purple); }

.container { max-width: 1360px; margin: 0 auto; padding: 0 48px; }

/* Фон рисует starfield.js на канвасе; twinkle остался ради .success-icon */
@keyframes twinkle {
    0%, 100% { opacity: 0.35; transform: scale(1); }
    50% { opacity: 1; transform: scale(1.15); }
}

/* ===== HEADER ===== */
header {
    position: sticky;
    top: 0;
    z-index: 40;
    background: rgba(18,20,29,0.85);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border);
    padding: 20px 48px;
}

.header-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    max-width: 1360px;
    margin: 0 auto;
}

/* Логотип — нарисованный знак, а не набранная строка (frontend/templates/_logo.html).
   Ни шрифта, ни размера, ни трекинга здесь больше нет: применяться им не к чему.

   Цвета остались прежними, и это намеренно. В присланном файле всё залито
   холодным белым #F7FEFF, а текст сайта — тёплый кремовый; возьми мы цвет из
   файла, логотип выпал бы из палитры, да и подвал из акцентного стал бы белым.
   Меняются только формы букв. */
.logo {
    color: var(--text);
    --logo-star: var(--accent);
    display: flex;
    align-items: center;
}

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

/* Высота подобрана по ширине знака, а не по высоте букв, и вот почему. Прежняя
   строка растягивалась трекингом в 1.5px и занимала 283px; у нарисованного знака
   трекинг свой, гораздо плотнее, и при равной высоте букв он выходил всего
   222px — на телефоне в шапке оставалась заметная дыра перед бургером. 21px
   дают 276px, то есть примерно ту же длину строки, что была.

   Число завязано на пропорции знака (539:41), а не на высоту букв, поэтому при
   смене файла логотипа его нужно пересчитывать. Прежний файл был 530:43, и там
   на ту же длину строки уходило 22px.

   Высоту шапки это не двигает: на широком экране её задаёт меню (40px), на
   узком — бургер, и знак ни там ни там не самый высокий. Проверено замером на
   1360 и 375px.

   Ширину считает браузер по viewBox. Атрибуты width/height на самом svg нужны
   как запасной размер на те мгновения, пока CSS ещё не применился. */
.logo-mark {
    display: block;
    height: 21px;
    width: auto;
}

/* На самых узких экранах знак упирается в бургер. Число не на глаз: при 21px
   знак занимает 276px, отступы шапки съедают 32, бургер — ещё 32, и на зазор
   остаётся ширина минус 340. То есть на 340px он обращается в ноль, а на 320px
   знак и бургер налезали бы друг на друга. Ниже 370px уменьшаем до 17px — тогда
   даже на 320px между ними остаётся 33px. */
@media (max-width: 369px) {
    .logo-mark { height: 17px; }
}

nav { display: flex; align-items: center; gap: 32px; }

nav a {
    font-size: 15px;
    color: var(--text-muted);
    transition: color 0.2s;
}

nav a:hover { color: var(--text); }

.cart-btn {
    position: relative;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--bg2);
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 17px;
    color: var(--text) !important;
}

/* Размер значка задаётся здесь, а не в самом SVG: одна и та же тележка стоит в
   шапке и на кнопке в углу, а размеры у них разные. */
.cart-btn .icon-cart { width: 20px; height: 20px; }
.cart-fab .icon-cart { width: 26px; height: 26px; }

.cart-count {
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    border-radius: 9px;
    background: var(--grad);
    color: var(--bg);
    font-size: 11px;
    font-weight: 800;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ===== FOOTER ===== */
footer {
    background: var(--bg2);
    border-top: 1px solid var(--border);
    padding: 48px;
    text-align: center;
    margin-top: 80px;
}

/* В подвале знак целиком акцентный, как и был: --logo-star переводится в
   currentColor, и звёздочки берут тот же цвет, что буквы. */
.footer-logo {
    color: var(--accent);
    --logo-star: currentColor;
    margin-bottom: 10px;
}

.footer-logo .logo-mark { height: 19px; margin: 0 auto; }

.footer-sub { font-size: 14px; color: var(--text-muted); margin-bottom: 16px; }

/* Контакты подвала — значками. Отдельной строкой над документами: способ
   связи и юридический документ ищут в разные моменты, а вперемешку «Написать
   нам» терялось между офертой и политикой. */
.footer-contacts {
    display: flex;
    justify-content: center;
    gap: 14px;
    margin-bottom: 18px;
}

/* Круг 44×44 — это про палец, а не про красоту: сам значок 20px, и без
   обёртки цель нажатия вдвое меньше рекомендованной. Рядом с ним точно так же
   рассчитан отступ у текстовых ссылок ниже. */
.footer-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 1px solid var(--border);
    border-radius: 50%;
    color: var(--text-muted);
    transition: color 0.2s, border-color 0.2s;
}
.footer-icon svg { width: 20px; height: 20px; }
.footer-icon:hover { color: var(--text); border-color: rgba(255, 255, 255, 0.3); }
/* Фокус виден: по подвалу ходят с клавиатуры, а у круглой ссылки без обводки
   непонятно, где ты находишься. */
.footer-icon:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Ссылки подвала. Перенос по строкам, а не в одну линию: на телефоне пять
   пунктов в строку не помещаются и разъезжаются как попало. Зазор в 20px по
   вертикали держит цели нажатия врозь — на узком экране они оказываются друг
   под другом, и промахнуться мимо нужной легко. */
.footer-links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px 20px;
    margin-bottom: 16px;
    font-size: 14px;
}

/* Отступ сверху и снизу — ради размера цели нажатия: строка текста в 14px даёт
   21px высоты, а минимум по WCAG 2.5.8 — 24px. На телефоне эти ссылки встают
   друг под другом, и промах ведёт не туда, куда покупатель метил. */
.footer-links a {
    display: inline-block;
    padding: 6px 0;
    color: var(--text-muted);
}
.footer-links a:hover { color: var(--text); }
/* Внутри этого блока ссылка на политику конфиденциальности, а прежний #4a4f6a
   давал 2,04:1 при норме WCAG AA 4,5:1 — текст читался с трудом. */
.footer-copy { font-size: 13px; color: #8b90ad; }

/* ===== ГЛАВНАЯ СТРАНИЦА ===== */
.hero {
    display: flex;
    align-items: center;
    gap: 48px;
    padding: 88px 48px;
    max-width: 1360px;
    margin: 0 auto;
    flex-wrap: wrap;
}

.hero-text { flex: 1 1 460px; min-width: 300px; }

.hero-label {
    font-size: 13px;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 18px;
}

.hero h1 {
    font-family: 'Yeseva One', serif;
    font-weight: 400;
    font-size: 56px;
    line-height: 1.15;
    margin-bottom: 22px;
}

.hero p {
    font-size: 17px;
    line-height: 1.7;
    color: var(--text-muted);
    max-width: 480px;
    margin-bottom: 34px;
}

.hero-btns { display: flex; gap: 16px; flex-wrap: wrap; }

.btn-primary {
    cursor: pointer;
    border: none;
    padding: 16px 30px;
    border-radius: 30px;
    background: var(--grad);
    color: var(--bg);
    font-family: 'Manrope', sans-serif;
    font-weight: 800;
    font-size: 15px;
    text-decoration: none;
    display: inline-block;
    transition: opacity 0.2s;
}

.btn-primary:hover { opacity: 0.9; color: var(--bg); }

.btn-outline {
    cursor: pointer;
    border: 1px solid rgba(255,255,255,0.18);
    padding: 16px 30px;
    border-radius: 30px;
    background: transparent;
    color: var(--text);
    font-family: 'Manrope', sans-serif;
    font-weight: 700;
    font-size: 15px;
    text-decoration: none;
    display: inline-block;
    transition: border-color 0.2s;
}

.btn-outline:hover { border-color: rgba(255,255,255,0.4); color: var(--text); }

.hero-img {
    flex: 1 1 420px;
    min-width: 300px;
    height: 460px;
    position: relative;
}

.hero-img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 28px;
    box-shadow: 0 30px 70px rgba(0,0,0,0.5);
}

/* Промо-полоса */
.promo-strip {
    display: flex;
    justify-content: center;
    gap: 48px;
    flex-wrap: wrap;
    padding: 22px 48px;
    background: var(--bg2);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    font-size: 14px;
    color: var(--text-muted);
}

/* Секции */
.section { padding: 88px 48px; max-width: 1360px; margin: 0 auto; }

.section-label {
    font-size: 13px;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 14px;
    text-align: center;
}

.section-title {
    font-family: 'Yeseva One', serif;
    font-weight: 400;
    font-size: 34px;
    text-align: center;
    margin-bottom: 48px;
}

/* ===== СЕТКА ТОВАРОВ ===== */
.products-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 24px;
}

.product-card {
    background: var(--bg2);
    border-radius: 18px;
    overflow: hidden;
    border: 1px solid var(--border);
    transition: transform 0.2s, box-shadow 0.2s;
}

/* Наведение — только там, где оно есть.
   На тачскрине наведения не существует, но браузер всё равно применяет :hover
   после касания и держит его до следующего касания в другом месте. Карточка
   оставалась приподнятой и увеличенной, и это читалось как «товар выбран», хотя
   покупатель просто тронул её, чтобы перейти.
   Условие про указатель, а не про ширину экрана: ноутбук с узким окном потерял
   бы наведение, которое у него есть, а планшет с широким — сохранил бы залипание,
   которого быть не должно. Отвечает на вопрос само устройство. */
@media (hover: hover) and (pointer: fine) {
    .product-card:hover {
        transform: translateY(-4px);
        box-shadow: 0 12px 40px rgba(0,0,0,0.3);
    }

    .product-card:hover .product-card__img img { transform: scale(1.04); }

    .product-card__name:hover { color: var(--accent); }

    .category-card:hover { transform: translateY(-3px); }
}

.product-card__img {
    height: 210px;
    position: relative;
    overflow: hidden;
}

.product-card__img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    cursor: pointer;
    transition: transform 0.3s;
}

.product-card__tag {
    position: absolute;
    top: 10px;
    left: 10px;
    background: var(--accent);
    color: var(--bg);
    font-size: 11px;
    font-weight: 800;
    padding: 4px 10px;
    border-radius: 12px;
}

.product-card__body { padding: 16px 18px 20px; }

.product-card__type {
    font-size: 11px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--purple2);
    margin-bottom: 6px;
}

.product-card__name {
    font-family: 'Yeseva One', serif;
    font-weight: 400;
    font-size: 15px;
    margin-bottom: 10px;
    color: var(--text);
    cursor: pointer;
    display: block;
}

.product-card__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.product-card__price {
    font-size: 15px;
    font-weight: 700;
    color: var(--accent);
}

.btn-add-cart {
    cursor: pointer;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text);
    font-size: 12px;
    padding: 7px 12px;
    border-radius: 16px;
    font-family: 'Manrope', sans-serif;
    font-weight: 700;
    transition: background 0.2s, border-color 0.2s;
}

.btn-add-cart:hover { background: var(--bg); border-color: rgba(255,255,255,0.3); }
.btn-add-cart:disabled { opacity: 0.4; cursor: not-allowed; }

/* «Сообщить о поступлении» в карточке — ссылка, а не кнопка: она ведёт на
   страницу товара. Вид тот же, поэтому дописано только то, чего у ссылки нет
   по умолчанию. Блочность в подвале карточки дал бы и флекс, но карточку
   избранного собирает тот же шаблон, и полагаться на чужой контейнер не
   стоит. */
a.btn-add-cart { display: block; text-align: center; text-decoration: none; }

/* ===== КАТЕГОРИИ ===== */
.categories-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 22px;
}

/* ===== ОТЗЫВЫ ===== */
/* Три в ряд, а не четыре как у категорий: в карточке текст, и на четверти
   ширины он превращается в узкий столбик по три слова в строке. */
/* Лента отзывов: по одной карточке за раз. Четыре в ряд выглядели рвано —
   отзывы разной длины, и рядом с длинным соседи стояли полупустыми. Один отзыв
   на виду читается как страница, а не как таблица. */
.reviews-gallery {
    --review-gap: 22px;
    position: relative;
}

.reviews-track {
    display: flex;
    gap: var(--review-gap);
    overflow-x: auto;
    /* proximity, а не mandatory: при жёсткой привязке лента отказывается
       останавливаться между карточками, и короткий свайп отбрасывает назад. */
    /* proximity, а не mandatory. Разница здесь не в ощущении прокрутки —
       карточка равна ширине ленты, и точки привязки в обоих случаях те же, — а
       в том, что при mandatory Chromium отменяет плавную прокрутку из скрипта:
       стрелка сдвигала ленту на два пикселя и возвращала обратно. Проверено:
       instant срабатывал, smooth откатывался в ноль. */
    scroll-snap-type: x proximity;
    /* Полоса прокрутки убрана намеренно и только потому, что есть стрелки: она
       была последним указателем на прокручиваемость, и прятать её на странице
       без стрелок было бы нельзя. На узких экранах, где стрелки скрыты,
       прокрутка пальцем привычна и указателя не требует. */
    scrollbar-width: none;
    /* Место под тень фокуса, иначе она режется краем. */
    padding: 2px;
    margin: 0 -2px;
}
.reviews-track::-webkit-scrollbar { display: none; }

/* Лента получает фокус с клавиатуры (tabindex в разметке), и его обязано быть
   видно: иначе человек прокручивает страницу, не понимая, что управляет ей. */
.reviews-track:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
    border-radius: 20px;
}

.review-card {
    /* Ровно ширина ленты: следующий отзыв показывается прокруткой, а не
       краем кадра. mandatory здесь уместнее proximity — промежуточных
       положений между карточками больше нет и быть не должно. */
    flex: 0 0 100%;
    scroll-snap-align: center;
    /* Фотографии слева, текст справа: на всю ширину снимки вытянулись бы
       полосой, а строка в 1200px нечитаема. Переносится на узком экране. */
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 28px;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: 20px;
    padding: 28px 32px;
    margin: 0;
}

/* Колонка текста. Ограничение по ширине — не украшение: строка длиннее
   примерно 75 знаков читается заметно хуже, глаз теряет начало следующей. */
.review-card__content { flex: 1 1 420px; min-width: 0; max-width: 72ch; }

/* Стрелки. Появляются из main.js и только когда ленте есть куда прокручиваться;
   в разметке они с hidden, поэтому без JS нерабочих кнопок не видно. */
.reviews-gallery__arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    /* 40px — с запасом к минимальной цели нажатия 24px по WCAG 2.5.8. */
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--bg2);
    color: var(--text);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
}
.reviews-gallery__arrow:hover { background: var(--bg); }
.reviews-gallery__arrow[disabled] { opacity: .3; cursor: default; }
.reviews-gallery__arrow--prev { left: -18px; }
.reviews-gallery__arrow--next { right: -18px; }

/* Заголовок документа — оферта, политика, согласие. Стилем, а не инлайном в
   трёх шаблонах: инлайновый font-size не перебить медиазапросом, а на телефоне
   он и мешал. «Конфиденциальности» в 36px требует 412px при колонке в 279 —
   заголовок уезжал за правый край, и увидеть его конец было нельзя. Прятало это
   overflow-x: hidden у body, снятый ради работающей sticky-шапки.

   break-word — страховка на случай слова ещё длиннее: лучше некрасивый перенос
   посреди слова, чем текст за краем экрана. */
.doc-title {
    font-family: 'Yeseva One', serif;
    font-weight: 400;
    font-size: 36px;
    margin-bottom: 32px;
    overflow-wrap: break-word;
}

/* Точки под лентой. Перенос по строкам — на случай, когда отзывов станет много:
   двенадцать помещаются в строку и на телефоне, а сорок лягут в две. */
.reviews-dots {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
    margin-top: 20px;
}
/* Атрибут hidden работает через `[hidden] { display: none }` в стилях самого
   браузера, и любое авторское правило с display его отменяет — точки оставались
   на странице и при единственном отзыве, хотя скрипт честно ставил hidden.
   У стрелок такого нет: им display не задан. Тот же приём уже применён к
   `.cart-fab[hidden]` и строке «в корзине». */
.reviews-dots[hidden] { display: none; }

/* Сама точка 8px, а кнопка вокруг неё 24×24 — минимум по WCAG 2.5.8. По восьми
   пикселям пальцем не попасть, и на телефоне, где стрелок нет, это
   единственный способ переключать отзывы нажатием. */
.reviews-dots__dot {
    width: 24px;
    height: 24px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}
.reviews-dots__dot::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.25);
    transition: background 0.2s, transform 0.2s;
}
/* Текущая — цветом и размером сразу: одного цвета мало на монохромном экране и
   при дальтонизме, а понять, где ты в ленте, нужно с одного взгляда. */
.reviews-dots__dot[aria-current="true"]::before {
    background: var(--accent);
    transform: scale(1.5);
}
.reviews-dots__dot:hover::before { background: var(--text-muted); }
.reviews-dots__dot:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 50%;
}

/* Сколько карточек в ряду. Меняется одно число — остальное считает calc выше.
   На узком экране карточка одна: две по 150px нечитаемы, а прокрутка пальцем
   там и так привычна. Стрелки на узком не нужны — их прячет тот же запрос. */

/* Полоса снимков покупателя над цитатой. Переносится, а не прокручивается:
   внутри прокручиваемой ленты вторая горизонтальная прокрутка означает, что
   свайп по фотографии листает фотографии, а не отзывы, и попасть пальцем в
   нужную область почти нельзя. Разная высота карточек при этом не мешает — в
   ряду они и так тянутся до самой высокой. */
.review-card__photos {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0;
    /* Колонка слева от текста: две плитки в ряд, дальше переносом. */
    flex: 0 0 316px;
}
/* Размер плитки задан у ссылки, а не у картинки. Если положиться на размеры
   самой картинки, до её загрузки место не занято — а картинки здесь ленивые, и
   вёрстка прыгала бы в момент долистывания. Пропорции снимков покупателей
   разные, вертикальные и горизонтальные вперемешку, поэтому лишнее срезается:
   полный кадр открывается по клику.

   Ширина в долях карточки, а не в пикселях: карточка теперь то треть ленты, то
   четверть, и фиксированные 150px на узкой карточке оставляли бы по одному
   снимку в строке, вытягивая её вниз. Две плитки в ряд при любой ширине. */
.review-card__photo {
    flex: 0 0 calc(50% - 4px);
    height: 110px;
    border-radius: 12px;
    overflow: hidden;
    line-height: 0;
    background: var(--bg);
}
.review-card__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Снимки в форме отзыва: тут карточки не сетка, поэтому просто переносим. */
.review-photos-admin { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 16px; }
.review-photos-admin__item { margin: 0; width: 160px; }
.review-photos-admin__item img {
    width: 160px; height: 120px; object-fit: cover;
    border-radius: 8px; display: block; margin-bottom: 8px;
}

.review-card__text {
    margin: 0 0 16px;
    color: var(--text);
    font-size: 15px;
    line-height: 1.7;
}

/* Свёртывание длинного отзыва — только на телефоне.

   Замеры настоящих отзывов (308–727 знаков) показали: на 1440px и даже на 900px
   все они помещаются в 4–9 строк, и обрезать нечего. Весь механизм работает
   ради узких экранов, где самый длинный отзыв занимает 21 строку.

   Поэтому по умолчанию раскрытия нет вовсе — ни обрезки, ни чекбокса, ни
   подписи. Не «скрипт погасил», а нет: даже если JS не отработает, на десктопе
   покупатель увидит полный текст и ни одного лишнего элемента.

   display:none у чекбокса здесь не косметика — он убирает его из порядка обхода
   клавиатурой. Раньше за это отвечала строчка в скрипте, то есть доступность
   зависела от того, выполнился ли JS. */
.review-card__text--clamped { position: relative; }
.review-card__expand,
.review-card__toggle { display: none; }

/* Надпись переключателя — двумя элементами, а не подменой content: у подписи
   есть содержимое, и content его бы затёр. */
.review-card__toggle-close { display: none; }
.review-card__expand:checked ~ .review-card__toggle .review-card__toggle-open { display: none; }
.review-card__expand:checked ~ .review-card__toggle .review-card__toggle-close { display: inline; }

@media (max-width: 767px) {
    /* Восемь строк. Обрезка визуальная: текст в разметке остаётся целиком,
       иначе отзыв пропал бы из выдачи и из копии страницы. */
    .review-card__body {
        display: -webkit-box;
        -webkit-line-clamp: 8;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    .review-card__expand:checked ~ .review-card__body,
    /* Короткий хвост — одна-две строки сверх восьми. Прятать его под подпись
       бессмысленно: нажатие выглядит как «ничего не произошло». Класс ставит
       main.js, замерив настоящее переполнение; до этого текст обрезан, поэтому
       без скрипта хвост не пропадает, а остаётся под рабочей подписью. */
    .review-card__text--full .review-card__body {
        display: block;
        overflow: visible;
    }

    /* Чекбокс уводится с глаз, но остаётся в порядке обхода: скрыть его через
       display:none значило бы отнять раскрытие у клавиатуры. */
    .review-card__expand {
        display: block;
        position: absolute;
        width: 1px;
        height: 1px;
        opacity: 0;
        pointer-events: none;
    }

    .review-card__toggle {
        display: inline-block;
        margin-top: 8px;
        color: var(--accent);
        font-size: 14px;
        cursor: pointer;
        /* Цель нажатия по WCAG 2.5.8 — не меньше 24px; строка в 14px даёт 21px. */
        padding: 3px 0;
    }
    .review-card__toggle:hover { color: var(--purple); }

    /* Фокус живёт на невидимом чекбоксе, поэтому показываем его на подписи —
       иначе человек, идущий с клавиатуры, не увидит, где он находится. */
    .review-card__expand:focus-visible ~ .review-card__toggle {
        outline: 2px solid var(--accent);
        outline-offset: 3px;
        border-radius: 4px;
    }
}

/* Узкий экран. Запрос стоит ПОСЛЕ правил, которые перекрывает: специфичность у
   селекторов одинаковая, и решает порядок в файле — стоя выше, он молча ничего
   не делал, а колонка снимков вылезала за край карточки.

   Порог в 1024px взят из арифметики, а не на глаз: рядом друг с другом колонки
   требуют 316 на снимки, 28 на зазор и хотя бы 420 на читаемую строку текста —
   это 764 плюс поля карточки и страницы. Ниже они всё равно переносятся, и
   снимки обязаны занять всю ширину: иначе они жмутся узкой полосой слева, а
   справа от них зияет пустота. */
@media (max-width: 1023px) {
    .review-card { padding: 20px; gap: 16px; }
    .review-card__photos { flex: 1 1 100%; }
}

@media (max-width: 767px) {
    .reviews-gallery__arrow { display: none; }
}


.review-card__author {
    color: var(--text-muted);
    font-size: 14px;
}

/* Источник отделён от имени точкой-разделителем через ::before, а не пробелом
   в разметке: между именем и ссылкой иначе появляется перенос строки в самом
   неудачном месте. */
.review-card__source::before { content: " · "; }

.category-card {
    border-radius: 20px;
    overflow: hidden;
    background: var(--bg2);
    border: 1px solid var(--border);
    cursor: pointer;
    transition: transform 0.2s;
}

.category-card__img { height: 150px; overflow: hidden; }
.category-card__img img { width: 100%; height: 100%; object-fit: cover; }

.category-card__name {
    padding: 16px 18px;
    font-family: 'Yeseva One', serif;
    font-weight: 400;
    font-size: 16px;
}

/* ===== ФИЛЬТРЫ КАТАЛОГА ===== */
.catalog-filters {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: center;
    margin-bottom: 44px;
}

.filter-chip {
    cursor: pointer;
    padding: 8px 20px;
    border-radius: 20px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-muted);
    font-family: 'Manrope', sans-serif;
    font-size: 14px;
    font-weight: 600;
    transition: all 0.2s;
}

/* Чипы-переключатели (наличие/плашки) можно включать и выключать, поэтому hover
   не должен выглядеть как выбранное состояние — градиент только у .active. */
.filter-chip:hover {
    color: var(--text);
    border-color: var(--accent);
}

.filter-chip.active {
    background: var(--grad);
    color: var(--bg);
    border-color: transparent;
}

/* Ряд «фильтры по наличию/плашкам + сортировка» */
.catalog-controls {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 44px;
}

.catalog-controls .catalog-filters {
    margin-bottom: 0;
    justify-content: flex-start;
}

.sort-form {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
}

.sort-label {
    color: var(--text-muted);
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
}

.sort-select {
    appearance: none;
    -webkit-appearance: none;
    background-color: var(--bg2);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2392B2F4' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 16px center;
    border: 1px solid var(--border);
    border-radius: 24px;
    padding: 11px 40px 11px 18px;
    color: var(--text);
    font-family: 'Manrope', sans-serif;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    outline: none;
    transition: border-color 0.2s;
}

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

.sort-select option { background: var(--bg2); color: var(--text); }

.sort-go {
    padding: 11px 18px;
    border-radius: 24px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-muted);
    font-family: 'Manrope', sans-serif;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}

/* Строка «Найдено: N ... Сбросить фильтры» */
.catalog-summary {
    color: var(--text-muted);
    margin-bottom: 24px;
    font-size: 14px;
}

.catalog-summary strong { color: var(--text); }
.catalog-summary a { color: var(--accent); margin-left: 12px; }
.catalog-summary a:hover { text-decoration: underline; }

/* ===== КАРТОЧКА ТОВАРА ===== */
.product-detail {
    display: flex;
    gap: 56px;
    max-width: 1200px;
    margin: 0 auto;
    padding: 48px 48px 110px;
    flex-wrap: wrap;
}

/* Ширина 450 px и без растягивания: при flex-grow: 1 колонка забирала свободное
   место и на широком экране доходила до 554 px, а с пропорцией 3:4 это 739 px
   высоты — фотография занимала весь экран и выталкивала описание с ценой вниз.
   Сжиматься по-прежнему может: на телефоне колонка становится по ширине экрана. */
.product-detail__gallery { flex: 0 1 450px; min-width: 300px; }

/* 3:4 по вертикали: фотографии товаров сняты вертикально, а блок был
   горизонтальным — 420 px высоты при ширине от 440, и object-fit: cover срезал у
   каждого снимка верх и низ. Именно здесь товар и разглядывают, поэтому форма
   блока должна совпадать с формой кадра. Пропорция, а не высота: колонка
   резиновая (flex-basis 440 px), и на узком экране блок ужмётся вместе с ней. */
.slider {
    aspect-ratio: 3 / 4;
    border-radius: 22px;
    overflow: hidden;
    margin-bottom: 16px;
    position: relative;
}

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

.slider-btn {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(0,0,0,0.5);
    color: #fff;
    border: none;
    padding: 10px 16px;
    font-size: 1.2rem;
    cursor: pointer;
    border-radius: 4px;
    transition: background 0.2s;
}

.slider-btn.prev { left: 10px; }
.slider-btn.next { right: 10px; }
.slider-btn:hover { background: rgba(0,0,0,0.8); }

.gallery-thumbs { display: flex; gap: 14px; }

.gallery-thumbs .thumb {
    flex: 1;
    height: 110px;
    border-radius: 14px;
    overflow: hidden;
    cursor: pointer;
    border: 2px solid transparent;
    transition: border-color 0.2s;
    object-fit: cover;
}

.gallery-thumbs .thumb:hover,
.gallery-thumbs .thumb.active { border-color: var(--accent); }

.product-detail__info { flex: 1 1 380px; min-width: 280px; }

.product-detail__type {
    font-size: 12px;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--purple2);
    margin-bottom: 10px;
}

.product-detail__name {
    font-family: 'Yeseva One', serif;
    font-weight: 400;
    font-size: 32px;
    margin-bottom: 14px;
}

.product-detail__price {
    font-size: 24px;
    font-weight: 800;
    color: var(--accent);
    margin-bottom: 22px;
}

.product-detail__sku {
    font-size: 13px;
    color: #787e97;
    margin-bottom: 16px;
}

.product-detail__desc {
    font-size: 16px;
    line-height: 1.7;
    color: var(--text-muted);
    margin-bottom: 28px;
}

.product-detail__actions {
    display: flex;
    align-items: center;
    gap: 18px;
    margin-bottom: 22px;
    /* На узком экране счётчик, наличие и кнопка втроём не помещаются в строку.
       Переносим ряд целиком — строка наличия при этом уезжает вниз готовой
       фразой, а не рвётся пополам, как было без переноса. */
    flex-wrap: wrap;
}

.qty-control {
    display: flex;
    align-items: center;
    border: 1px solid var(--border);
    border-radius: 24px;
    overflow: hidden;
}

.qty-btn {
    border: none;
    background: transparent;
    color: var(--text);
    width: 38px;
    height: 38px;
    font-size: 18px;
    cursor: pointer;
}

.qty-value { width: 32px; text-align: center; font-weight: 700; }

.btn-add-to-cart {
    flex: 1;
    cursor: pointer;
    border: none;
    padding: 16px 24px;
    border-radius: 24px;
    background: var(--grad);
    color: var(--bg);
    font-weight: 800;
    font-size: 15px;
    font-family: 'Manrope', sans-serif;
    transition: opacity 0.2s;
}

.btn-add-to-cart:hover { opacity: 0.9; }
.btn-add-to-cart:disabled { opacity: 0.4; cursor: not-allowed; }

.product-detail__note { font-size: 13px; color: #787e97; }

.btn-back { font-size: 14px; color: var(--text-muted); display: inline-block; margin-bottom: 24px; }
.btn-back:hover { color: var(--text); }

/* Похожие товары */
.related { max-width: 1200px; margin: 0 auto; padding: 0 48px 88px; }

.related-label {
    font-size: 13px;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 16px;
}

.related-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
}

/* ===== КОРЗИНА ===== */
.cart-page { max-width: 1000px; margin: 0 auto; padding: 56px 48px 110px; }
.cart-page h1 { font-family: 'Yeseva One', serif; font-weight: 400; font-size: 36px; margin-bottom: 32px; }

.cart-table { width: 100%; border-collapse: collapse; margin-bottom: 30px; }

.cart-table th {
    padding: 12px 16px;
    text-align: left;
    font-size: 12px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
}

.cart-table td {
    padding: 16px;
    border-bottom: 1px solid var(--border);
    color: var(--text);
}

.cart-table tfoot td { font-size: 16px; font-weight: 700; color: var(--accent); }

.cart-empty { text-align: center; padding: 80px 0; color: var(--text-muted); }
.cart-empty a { color: var(--accent); }

.cart-notices {
    background: rgba(249, 115, 22, 0.12);
    border: 1px solid rgba(249, 115, 22, 0.35);
    border-radius: 12px;
    padding: 14px 18px;
    margin-bottom: 20px;
    font-size: 14px;
    color: var(--text);
}
.cart-notices ul { margin: 6px 0 0 18px; }
.cart-notices li { margin-bottom: 4px; }
.cart-notices p:first-child { font-weight: 700; margin-bottom: 2px; }

/* Баннер «приём заказов приостановлен» (frontend/templates/_sales_pause.html).
   Тем же цветом, что и остальные предупреждения покупателю об остатке, —
   var(--accent-stock): это сообщение той же природы, «купить сейчас нельзя», и
   заводить под него третий цвет значило бы учить покупателя новому знаку.
   Отступ сверху, а не только снизу: баннер идёт первым внутри <main>, и без
   него он прилипает к шапке. */
.sales-pause {
    background: rgba(255, 69, 137, 0.12);
    border: 1px solid rgba(255, 69, 137, 0.4);
    border-radius: 12px;
    padding: 14px 18px;
    margin: 24px 0 4px;
    font-size: 15px;
    line-height: 1.5;
    color: var(--text);
}

/* Форма заказа */
.order-form { max-width: 560px; margin-top: 40px; }
.order-form h2 { font-family: 'Yeseva One', serif; font-weight: 400; font-size: 24px; margin-bottom: 20px; }

.order-form input,
.order-form select,
.order-form textarea {
    display: block;
    width: 100%;
    padding: 14px 16px;
    margin-bottom: 12px;
    background: var(--bg2);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 12px;
    color: var(--text);
    font-family: 'Manrope', sans-serif;
    /* Ровно 16px и не меньше: iOS Safari зумит страницу при фокусе на поле с
       более мелким шрифтом, и происходит это на каждом поле оформления заказа —
       страница прыгает, покупатель теряет место. */
    font-size: 16px;
}

/* Скрытое поле остаётся скрытым. Правило выше задаёт полям display, а любое
   авторское display отменяет `[hidden] { display: none }` из стилей браузера —
   тем же способом уже терялись точки отзывов (.reviews-dots[hidden] выше).
   Без этого поле нового типа товара висело бы в форме всегда, и вопрос «какой
   тип» задавался бы дважды. */
.order-form [hidden] { display: none; }

.order-form label {
    display: block;
    margin-bottom: 6px;
    font-size: 14px;
    color: var(--text-muted);
}

/* Пояснение под полем. Отрицательный отступ сверху съедает margin-bottom
   самого поля: иначе подпись отрывается от него и читается как заголовок
   следующего. Цвет тот же, что у label, — правило .footer-copy уже показало,
   чем кончается собственный приглушённый оттенок. */
.order-form .field-hint {
    margin: -8px 0 16px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* Фокус заметен и без outline — рамка меняет цвет и появляется свечение.
   Одной смены цвета рамки мало: на тёмном фоне она читается плохо. */
.order-form input:focus,
.order-form select:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(146, 178, 244, 0.25);
}

.order-form select option { background: var(--bg2); }

/* Поле промокода лежит выше формы и в .order-form не входит, поэтому не
   получало вообще никакого оформления: белый прямоугольник с чёрным текстом на
   фоне #12141d. Заодно 16px — без них iOS зумит страницу и на нём тоже.
   Отдельным правилом, а не добавлением в список выше, — там ещё display:block
   и width:100%, которые сломают строку с кнопкой «Применить». */
#promo-input {
    padding: 14px 16px;
    background: var(--bg2);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 12px;
    color: var(--text);
    font-family: 'Manrope', sans-serif;
    font-size: 16px;
}

#promo-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(146, 178, 244, 0.25);
}

/* Отметка о согласии на обработку персональных данных — в корзине и в форме
   обратной связи. Флажок и текст выровнены по первой строке, а не по центру:
   текст в две-три строки, и центрированный флажок уезжал бы к её середине. */
.consent-check {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-top: 20px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-muted);
    cursor: pointer;
}
/* Селектор с [type=checkbox] не для красоты, а ради веса. Формы задают своим
   полям ширину во всю строку — `.contacts-form input`, `.order-form input`, — и
   у этих правил тот же вес, что у голого `.consent-check input`: спор решает
   порядок в файле. На странице контактов правило формы стоит ниже, выигрывало
   его `width: 100%`, и флажок растягивался на всю форму, выталкивая подпись за
   правый край экрана. Прятало это `overflow-x: hidden` у body — пока его не
   убрали ради работающей sticky-шапки, и сторож переполнения не показал. */
.consent-check input[type="checkbox"] {
    /* Площадь нажатия: флажок в 13px попадёт пальцем не с первого раза. */
    width: 20px; height: 20px;
    flex: 0 0 auto;
    margin-top: 1px;
    accent-color: var(--accent);
    cursor: pointer;
}
.consent-check a { color: var(--accent); }

.btn-order {
    width: 100%;
    padding: 16px 24px;
    border-radius: 24px;
    background: var(--grad);
    color: var(--bg);
    border: none;
    font-weight: 800;
    font-size: 15px;
    font-family: 'Manrope', sans-serif;
    cursor: pointer;
    margin-top: 8px;
    transition: opacity 0.2s;
}

.btn-order:hover { opacity: 0.9; }

/* Недоступная кнопка обязана выглядеть недоступной. Отметка о согласии держит
   «Оформить заказ» отключённой, а выглядела она при этом ровно как рабочая:
   покупатель жал по горящей кнопке, ничего не происходило, и связать это с
   галочкой выше он не мог. Приглушение и курсор — те же, что у кнопки каталога
   (.btn-add-cart:disabled), чтобы отключённые кнопки на сайте выглядели
   одинаково.

   :hover перечислен здесь же намеренно: у него та же специфичность, и без
   этого наведение возвращало бы отключённой кнопке яркость.

   Правило задевает и остальные кнопки этого класса — так и нужно: форма
   обратной связи и оформление заказа отключают свою на время отправки, и
   выглядеть нажимаемой она в этот момент не должна. */
.btn-order:disabled,
.btn-order:disabled:hover {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ===== УСПЕШНЫЙ ЗАКАЗ ===== */
.success-page { text-align: center; padding: 100px 48px; }
.success-page h1 { font-family: 'Yeseva One', serif; font-weight: 400; font-size: 40px; margin-bottom: 20px; }
.success-page p { font-size: 16px; color: var(--text-muted); margin-bottom: 12px; }

/* Карточка заказа на странице «оформлен». Страница выровнена по центру, а
   таблица и список «поле — значение» по центру нечитаемы: глазу не за что
   зацепиться слева. Отсюда собственный text-align. */
.order-summary {
    max-width: 520px;
    margin: 40px auto 0;
    padding: 28px 32px;
    text-align: left;
    background: var(--bg2);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 16px;
}

.order-summary h2 {
    font-family: 'Yeseva One', serif;
    font-weight: 400;
    font-size: 20px;
    margin: 24px 0 12px;
}
.order-summary h2:first-child { margin-top: 0; }

.order-summary__track {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
    padding: 14px 16px;
    margin-bottom: 4px;
    background: rgba(146,178,244,0.10);
    border-radius: 12px;
    font-size: 16px;
}
.order-summary__label { color: var(--text-muted); font-size: 13px; }
.order-summary__track a { color: var(--accent); white-space: nowrap; }

.order-summary__items { width: 100%; border-collapse: collapse; font-size: 15px; }
.order-summary__items td { padding: 8px 0; vertical-align: top; }
.order-summary__items tbody tr + tr td { border-top: 1px solid rgba(255,255,255,0.06); }
.order-summary__qty { color: var(--text-muted); white-space: nowrap; padding-left: 12px; }
.order-summary__sum { text-align: right; white-space: nowrap; padding-left: 12px; }
.order-summary__discount { color: #4ade80; }

.order-summary__items tfoot td { color: var(--text-muted); }
.order-summary__items tfoot tr:first-child td { border-top: 1px solid rgba(255,255,255,0.12); padding-top: 12px; }
.order-summary__total td { color: var(--text); font-weight: 700; font-size: 17px; }

/* Пары «поле — значение» в две колонки. grid, а не float: длинный адрес ПВЗ
   переносится по строкам, оставаясь выровненным по своему столбцу. */
.order-summary__facts {
    display: grid;
    grid-template-columns: minmax(120px, auto) 1fr;
    gap: 8px 16px;
    margin: 0;
    font-size: 15px;
}
.order-summary__facts dt { color: var(--text-muted); }
.order-summary__facts dd { margin: 0; }

.order-summary__note {
    margin: 24px 0 0;
    font-size: 13px;
    line-height: 1.6;
    color: var(--text-muted);
}

@media (max-width: 600px) {
    .order-summary { padding: 20px; border-radius: 12px; }
    /* Две колонки на узком экране оставляют значению полосу в пару слов —
       адрес пункта выдачи рассыпается в столбик из отдельных букв. */
    .order-summary__facts { grid-template-columns: 1fr; gap: 2px; }
    .order-summary__facts dd { margin-bottom: 10px; }
}

/* ===== ИЗБРАННОЕ ===== */
/* Сердечко поверх фото карточки. 44×44 — не про красоту: это минимальный
   размер цели касания, при котором в неё попадают пальцем (WCAG 2.5.8 требует
   24, рекомендация — 44). Кнопка маленькая на вид, зона нажатия большая. */
.fav-btn {
    position: absolute;
    top: 8px; right: 8px;
    width: 44px; height: 44px;
    display: flex; align-items: center; justify-content: center;
    padding: 0;
    background: rgba(18,20,29,0.6);
    border: 1px solid rgba(255,255,255,0.14);
    border-radius: 50%;
    color: var(--text-muted);
    font-size: 20px; line-height: 1;
    cursor: pointer;
    transition: color .15s, background .15s;
}
.fav-btn:hover { background: rgba(18,20,29,0.85); color: var(--text); }
.fav-btn--active { color: #f472b6; border-color: rgba(244,114,182,0.5); }
.fav-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* На странице товара сердечко стоит в строке с названием, а не поверх фото:
   фото там крупное, и кнопка в углу читалась бы как часть иллюстрации. */
.product-detail__heading { display: flex; align-items: flex-start; gap: 12px; }
.product-detail__heading .product-detail__name { flex: 1; }
.fav-btn--inline { position: static; flex: 0 0 auto; }

/* По центру, как заголовок раздела над ним: .section-title центрирован, и
   прижатый влево текст под ним читается как сбой вёрстки. */
.favorites-empty {
    max-width: 480px;
    margin: 40px auto;
    text-align: center;
    color: var(--text-muted);
    font-size: 15px;
    line-height: 1.7;
}

/* ===== ПОДПИСКА «СООБЩИТЬ О ПОСТУПЛЕНИИ» ===== */
#notify-form { margin-top: 14px; max-width: 420px; }
#notify-form label { display: block; margin-bottom: 6px; font-size: 14px; color: var(--text-muted); }
/* В колонку, а не в строку. Строкой поле почты сжималось в полоску: у
   .btn-order объявлена width: 100%, во флекс-строке она забирала всю ширину, а
   поле с flex:1 и min-width:0 уходило почти в ноль. Разметка при этом
   оставалась правильной, и серверные проверки такого не видят — сторожит
   TC_E2E_31. */
.notify-row { display: flex; flex-direction: column; gap: 10px; }
.notify-row input {
    flex: 1; min-width: 0; padding: 12px 14px;
    background: var(--bg2); border: 1px solid rgba(255,255,255,0.12);
    border-radius: 12px; color: var(--text);
    font-family: 'Manrope', sans-serif;
    /* 16px — иначе iOS зумит страницу на фокусе. */
    font-size: 16px;
}
.notify-row input:focus {
    outline: none; border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(146, 178, 244, 0.25);
}
.notify-row .btn-order { margin: 0; }
#notify-form .field-hint { margin: 8px 0 0; font-size: 13px; line-height: 1.5; color: var(--text-muted); }
.notify-result { margin-top: 14px; font-size: 14px; color: #4ade80; }
/* Отказ отличается не только цветом: на монохромном экране и при дальтонизме
   зелёный от красного не отличить, а перепутать «подписался» с «не вышло»
   здесь дороже всего. */
.notify-result--error {
    padding: 10px 14px; color: var(--text);
    background: rgba(248,113,113,0.12); border-left: 3px solid #f87171;
    border-radius: 8px;
}

/* ===== МОЙ ЗАКАЗ ===== */
.order-find { max-width: 480px; margin: 0 auto; padding: 64px 24px 110px; }
.order-find h1 {
    font-family: 'Yeseva One', serif;
    font-weight: 400;
    font-size: 32px;
    margin-bottom: 16px;
}
.order-find__lead,
.order-find__note { color: var(--text-muted); font-size: 14px; line-height: 1.7; }
.order-find__note { margin-top: 24px; }
.order-find__lead code {
    padding: 1px 6px;
    background: var(--bg2);
    border-radius: 6px;
    font-size: 13px;
}

.order-find__form { margin-top: 28px; }
.order-find__form label {
    display: block;
    margin-bottom: 6px;
    font-size: 14px;
    color: var(--text-muted);
}
.order-find__form input {
    display: block;
    width: 100%;
    padding: 14px 16px;
    margin-bottom: 16px;
    background: var(--bg2);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 12px;
    color: var(--text);
    font-family: 'Manrope', sans-serif;
    /* 16px и не меньше — иначе iOS Safari зумит страницу на фокусе, как и в
       форме заказа. */
    font-size: 16px;
}
.order-find__form input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(146, 178, 244, 0.25);
}

/* Ошибка поиска. Не только цветом: на монохромном экране и при дальтонизме
   красный текст от обычного не отличается — отсюда рамка и подложка. */
.order-find__error {
    padding: 12px 16px;
    margin-bottom: 20px;
    background: rgba(248,113,113,0.12);
    border-left: 3px solid #f87171;
    border-radius: 8px;
    font-size: 14px;
    line-height: 1.6;
}

/* ===== О БРЕНДЕ ===== */
.about-page { max-width: 1040px; margin: 0 auto; padding: 64px 48px 110px; }

.about-hero {
    display: flex;
    gap: 56px;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 72px;
}

.about-portrait {
    width: 260px;
    height: 260px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
}

.about-portrait img { width: 100%; height: 100%; object-fit: cover; }

.about-text h1 { font-family: 'Yeseva One', serif; font-weight: 400; font-size: 36px; margin-bottom: 18px; }
.about-text p { font-size: 16px; line-height: 1.75; color: var(--text-muted); }

.about-cards {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 28px;
    margin-bottom: 56px;
}

.about-card {
    background: var(--bg2);
    border-radius: 18px;
    padding: 26px;
    border: 1px solid var(--border);
}

.about-card__icon { font-size: 22px; margin-bottom: 12px; }
.about-card__title { font-family: 'Yeseva One', serif; font-weight: 400; font-size: 16px; margin-bottom: 10px; }
.about-card__text { font-size: 14px; color: var(--text-muted); line-height: 1.6; }

/* ===== КОНТАКТЫ ===== */
.contacts-page { max-width: 1000px; margin: 0 auto; padding: 64px 48px 110px; }
.contacts-page h1 { font-family: 'Yeseva One', serif; font-weight: 400; font-size: 36px; margin-bottom: 48px; text-align: center; }

.contacts-socials {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    margin-bottom: 56px;
}

.social-card {
    display: block;
    background: var(--bg2);
    border-radius: 16px;
    padding: 22px;
    border: 1px solid var(--border);
    text-align: center;
    font-weight: 700;
    color: var(--text);
    transition: border-color 0.2s;
}

.social-card:hover { border-color: var(--accent); color: var(--accent); }

.contacts-bottom { display: flex; gap: 56px; flex-wrap: wrap; }
.contacts-bottom h2 { font-family: 'Yeseva One', serif; font-weight: 400; font-size: 22px; margin-bottom: 18px; }

.contacts-form { flex: 1 1 300px; }
.contacts-form input,
.contacts-form textarea {
    display: block;
    width: 100%;
    padding: 14px 16px;
    margin-bottom: 14px;
    background: var(--bg2);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 12px;
    color: var(--text);
    font-family: 'Manrope', sans-serif;
    font-size: 14px;
}

.contacts-info { flex: 1 1 260px; }
.contacts-info ul { list-style: none; display: flex; flex-direction: column; gap: 14px; font-size: 14px; color: var(--text-muted); line-height: 1.6; }

/* ===== АДМИНКА ===== */
.admin { max-width: 1200px; margin: 0 auto; padding: 40px 48px 80px; }
.admin h1 { font-family: 'Yeseva One', serif; font-weight: 400; font-size: 32px; margin-bottom: 24px; }
.admin h2 { font-family: 'Yeseva One', serif; font-weight: 400; font-size: 22px; margin-bottom: 16px; }

.admin-actions { display: flex; gap: 12px; margin-bottom: 24px; flex-wrap: wrap; }

/* Навигация по разделам. Отделена от .admin-actions намеренно: там действия
   над текущей страницей («добавить товар»), здесь переходы между разделами —
   раньше они стояли вперемешку в одном ряду. */
.admin-nav {
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
    margin: 0 0 28px; padding-bottom: 12px;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
}
.admin-nav__spacer { flex: 1 1 auto; }
.admin-nav__item {
    /* 24px по высоте — минимальная цель нажатия по WCAG 2.5.8; админку
       открывают и с телефона, стоя у почтомата. */
    display: inline-block; padding: 8px 14px; min-height: 24px;
    font-size: 14px; color: var(--text-muted); text-decoration: none;
    border-radius: 6px; white-space: nowrap;
}
.admin-nav__item:hover { color: var(--text); background: rgba(255, 255, 255, .05); }
.admin-nav__item--active { color: var(--text); background: rgba(255, 255, 255, .1); font-weight: 600; }
.admin-nav__item--muted { font-size: 13px; opacity: .75; }

@media (max-width: 700px) {
    .admin { padding: 24px 16px 60px; }
    .admin-nav__spacer { display: none; }
}

/* Поиск и групповые операции в списках товаров */
.admin-search { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 16px; }
.admin-search input[type="search"] {
    /* 16px — иначе iOS увеличивает страницу при фокусе, и админка на телефоне
       прыгает. То же правило, что у полей формы заказа. */
    font-size: 16px;
    padding: 9px 12px;
    min-width: 240px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg2);
    color: var(--text);
}
.admin-search__reset { font-size: 14px; color: var(--text-muted); }
.admin-search__found { font-size: 14px; color: var(--text-muted); }

/* «Требуют действия» на входе в админку. Оранжевый, а не красный: это не
   поломка, а работа, которую ещё не сделали. */
.attention-tiles { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 20px; }
.attention-tile {
    display: flex; align-items: baseline; gap: 10px;
    padding: 12px 18px; min-height: 24px;
    background: rgba(245,158,11,0.12);
    border: 1px solid rgba(245,158,11,0.35);
    border-radius: 12px;
    text-decoration: none;
}
.attention-tile:hover { background: rgba(245,158,11,0.2); }
.attention-tile__value { font-size: 22px; font-weight: 800; color: #fbbf24; }
.attention-tile__label { font-size: 14px; color: var(--text); }

/* Отбор заказов. Поля в строку и переносом: на широком экране это одна полоса
   над таблицей, на ноутбуке — две, и ни на каком экране не появляется
   горизонтальная прокрутка. */
.admin-filters {
    display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px;
    margin-bottom: 12px;
}
.admin-filters input[type="search"] {
    /* 16px — иначе iOS увеличивает страницу при фокусе. */
    font-size: 16px; padding: 9px 12px; min-width: 240px;
    border: 1px solid var(--border); border-radius: 8px;
    background: var(--bg2); color: var(--text);
    align-self: flex-end;
}
.admin-filters__field { display: flex; flex-direction: column; gap: 4px; }
.admin-filters__field span { font-size: 12px; color: var(--text-muted); }
.admin-filters__field select {
    font-size: 15px; padding: 9px 10px;
    border: 1px solid var(--border); border-radius: 8px;
    background: var(--bg2); color: var(--text);
}
.admin-filters__applied { margin: 0 0 12px; font-size: 14px; color: var(--text-muted); }
.admin-filters__export { margin: 0 0 16px; font-size: 14px; }
.admin-filters__export a { color: var(--text-muted); }
.admin-filters__empty { padding: 28px 12px; text-align: center; color: var(--text-muted); }

/* Панель групповых операций. Появляется, только когда что-то отмечено: пустая
   панель над таблицей предлагает действие, которое некуда применить. */
.bulk-actions {
    display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
    margin-bottom: 16px; padding: 14px 16px;
    background: var(--bg2); border: 1px solid var(--border); border-radius: 12px;
}
.bulk-actions select, .bulk-actions input {
    font-size: 15px; padding: 8px 10px;
    border: 1px solid var(--border); border-radius: 8px;
    background: var(--bg); color: var(--text);
}

/* Горизонтальные полосы: «по товарам» и разрезы. Столбцами их не нарисовать —
   подписи длинные, и под вертикальными столбцами читаются только боком.
   grid, а не flex: три колонки выравниваются между строками, и полосы начинаются
   от одной вертикали независимо от длины названия. */
.bars { display: flex; flex-direction: column; gap: 6px; margin-bottom: 20px; }
.bars__row {
    display: grid;
    grid-template-columns: minmax(120px, 220px) 1fr auto;
    align-items: center;
    gap: 12px;
    font-size: 14px;
}
.bars__label {
    color: var(--text-muted);
    /* Название в одну строку с многоточием: перенос сдвигал бы соседние полосы
       по вертикали и ряд переставал читаться как ряд. Полное имя — в title. */
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bars__track {
    height: 18px;
    background: var(--bg2);
    border-radius: 4px;
    overflow: hidden;
}
.bars__fill {
    display: block;
    height: 100%;
    background: linear-gradient(90deg, #7c93e0, #a58ce0);
    border-radius: 4px;
    /* Нулевая выручка иначе даёт полосу нулевой ширины, неотличимую от
       отсутствия строки. */
    min-width: 2px;
}
.bars__value { white-space: nowrap; font-variant-numeric: tabular-nums; }
.bars--compact .bars__row { grid-template-columns: minmax(90px, 150px) 1fr auto; font-size: 13px; }

/* Кнопка выгрузки рядом с заголовком отчёта. Мельче заголовка намеренно: это
   действие при отчёте, а не второй заголовок. */
.report-download {
    margin-left: 12px;
    font-family: 'Manrope', sans-serif;
    font-size: 13px;
    font-weight: 400;
    color: var(--text-muted);
    white-space: nowrap;
}
.report-download:hover { color: var(--accent); }

/* Сворачиваемый отчёт. Заголовок остаётся заголовком — h2 внутри summary, — и
   меняется у него только отступ: свои у h2 сдвинули бы стрелку относительно
   текста. */
.report { margin-top: 36px; }
.report__head {
    display: flex; align-items: baseline; gap: 10px;
    cursor: pointer;
    /* Свой указатель вместо системного треугольника: тот рисуется по-разному в
       трёх движках и не поддаётся выравниванию по базовой линии заголовка. */
    list-style: none;
}
.report__head::-webkit-details-marker { display: none; }
.report__head::before {
    content: "▸";
    color: var(--text-muted);
    transition: transform 0.15s;
}
.report[open] > .report__head::before { transform: rotate(90deg); }
.report__head h2 { margin: 0; }
/* Фокус виден: блок открывают и с клавиатуры, а системная обводка на summary
   без этого пропадает под собственным фоном страницы. */
.report__head:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

/* ===== ОТЧЁТЫ ПО ПРОДАЖАМ ===== */

.sales-periods { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 16px; }
.sales-periods__item {
    padding: 8px 16px; min-height: 24px; border-radius: 6px;
    font-size: 14px; color: var(--text-muted); text-decoration: none;
    border: 1px solid var(--border);
}
.sales-periods__item:hover { color: var(--text); }
.sales-periods__item--active { color: var(--text); background: rgba(255, 255, 255, .1); font-weight: 600; }

/* Оговорки о том, как считалось. Не мелким шрифтом в углу: расхождение отчёта
   со списком заказов — первый вопрос, который к нему возникает. */
.sales-note {
    color: var(--text-muted); font-size: 14px; line-height: 1.6;
    max-width: 760px; margin: 0 0 20px;
}

.sales-tiles {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
}
/* На главной админки плитки — одна ссылка в отчёты, поэтому вёрстка на span:
   вложить div в <a> можно, но блочные элементы внутри строчной ссылки ведут
   себя непредсказуемо, а display у них задан здесь явно. */
.sales-tiles--compact { text-decoration: none; margin-bottom: 24px; }
.sales-tiles--compact:hover .sales-tile { border-color: rgba(255, 255, 255, .2); }

.sales-tile {
    display: block;
    background: var(--bg2); border: 1px solid var(--border);
    border-radius: 16px; padding: 20px 24px;
}
.sales-tile__label { display: block; color: var(--text-muted); font-size: 13px; text-transform: uppercase; letter-spacing: .04em; }
.sales-tile__value { display: block; font-family: 'Yeseva One', serif; font-size: 30px; margin: 6px 0 4px; color: var(--text); }
.sales-tile__hint { display: block; color: var(--text-muted); font-size: 13px; }
.sales-up { color: #4ade80; }
.sales-down { color: #f87171; }

/* Диаграмма столбиками. Без библиотеки графиков: внешние скрипты блокирует CSP,
   а высота столбца — единственное, что нужно взять из данных. */
.sales-chart {
    display: flex; align-items: flex-end; gap: 3px;
    height: 180px; margin-bottom: 20px; padding-top: 8px;
    overflow-x: auto;
}
.sales-chart__col {
    flex: 1 1 0; min-width: 14px;
    display: flex; flex-direction: column; justify-content: flex-end;
    height: 100%;
}
.sales-chart__bar {
    background: linear-gradient(180deg, #7a7a9a, #4a4f6a);
    border-radius: 3px 3px 0 0;
    /* Нулевой день обязан остаться видимой полоской, иначе «нет продаж» и
       «нет данных» на графике выглядят одинаково. */
    min-height: 2px;
}
.sales-chart__tick {
    font-size: 10px; color: var(--text-muted); text-align: center;
    margin-top: 4px; white-space: nowrap; overflow: hidden;
}

.sales-dimensions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.sales-dimensions__title { font-size: 16px; margin: 0 0 10px; color: var(--text); }

@media (max-width: 900px) {
    .sales-tiles, .sales-dimensions { grid-template-columns: 1fr; }
    .sales-chart__tick { display: none; }
}

/* Ручка перетаскивания строки. Без видимой ручки никто не догадается, что
   строку можно тащить, — а курсор grab появляется только при наведении. */
.drag-handle {
    cursor: grab;
    color: var(--text-muted);
    user-select: none;
    width: 24px;
    text-align: center;
}
.drag-handle:active { cursor: grabbing; }

/* ===== СТАТУСЫ ЗАКАЗОВ ===== */
.status-badge { padding: 3px 8px; border-radius: 12px; font-size: 0.8rem; font-weight: bold; }
.status-new { background: #2a2510; color: #f0c040; }
.status-confirmed { background: #0d1f35; color: #60a5fa; }
.status-shipped { background: #0d2010; color: #4ade80; }
.status-delivered { background: #0d2020; color: #34d399; }
.status-cancelled { background: #2a0d0d; color: #f87171; }
.order-row.status-cancelled td { opacity: 0.6; }

/* ===== DROP ZONE ===== */
#drop-zone {
    border: 2px dashed rgba(255,255,255,0.2);
    border-radius: 12px;
    padding: 30px;
    text-align: center;
    cursor: pointer;
    color: var(--text-muted);
    transition: border-color 0.2s, background 0.2s;
}

#drop-zone:hover, #drop-zone.dragover {
    border-color: var(--accent);
    background: rgba(146,178,244,0.05);
    color: var(--text);
}

/* ===== ПРОГРЕСС ЗАГРУЗКИ ФОТО =====
   Десяток фотографий с телефона — это десятки мегабайт: страница молчала всё
   время отправки, и оператор успевал решить, что кнопка не сработала, и нажать
   ещё раз. */
#upload-progress { margin-top: 15px; }

.upload-bar {
    height: 8px;
    border-radius: 4px;
    background: rgba(255,255,255,0.08);
    overflow: hidden;
}

.upload-bar-fill {
    display: block;
    width: 0;
    height: 100%;
    border-radius: 4px;
    background: var(--accent);
    transition: width 0.15s linear;
}

/* Байты ушли, но сервер ещё сжимает картинки и пишет миниатюры. Полоса,
   замершая на сотне процентов, читается как зависшая, поэтому на это время
   она пульсирует: ждать есть чего, но проценты тут уже ни при чём. */
.upload-bar.processing .upload-bar-fill {
    width: 100%;
    animation: upload-pulse 1.2s ease-in-out infinite;
}

@keyframes upload-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

.upload-status { margin: 8px 0 0; font-size: 13px; color: var(--text-muted); }
.upload-status.error { color: #f87171; }

/* ===== АДАПТИВ ===== */
@media (max-width: 768px) {
    .container, header, footer { padding: 16px; }
    .hero { padding: 48px 16px; }
    .hero h1 { font-size: 36px; }
    .products-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
    .categories-grid { grid-template-columns: repeat(2, 1fr); }
    /* Отзывы в один столбец: текст в половину ширины телефона нечитаем. */
    .about-cards, .related-grid, .contacts-socials { grid-template-columns: 1fr; }
    .product-detail { padding: 24px 16px; }
    .section { padding: 48px 16px; }
    nav { gap: 16px; }

    /* ===== Корзина на телефоне =====
       Мобильных правил у этой страницы не было вовсе: она держала десктопные
       поля по 48 px, и на 375 px под содержимое оставалось 279. Таблица из пяти
       колонок в них не влезала, страница ехала вбок на 59 px, а крестик удаления
       товара начинался на отметке 404 — то есть целиком за экраном, и убрать
       товар с телефона было нельзя.

       Нижнее поле щедрое: под страницей висят кнопка корзины в углу и баннер
       cookie. */
    .cart-page { padding: 32px 16px 90px; }
    .cart-page h1 { font-size: 28px; }

    /* Таблица превращается в список карточек. Разметка при этом остаётся
       таблицей: её собирает renderCart, и на `#cart-items tr` завязаны
       браузерные сценарии — переделка в <div> сломала бы и то, и другое ради
       того же результата. */
    .cart-table thead { display: none; }

    /* Флекс с переносом, а не сетка: в сетке каждая ячейка — свой элемент, и
       цена, количество и сумма встали бы друг под другом, растянув карточку
       товара до 125 px. Здесь они переносятся одной строкой под названием.
       Правое поле — место под крестик, он снят с потока. */
    .cart-table tbody tr {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 0 14px;
        position: relative;
        padding: 14px 34px 14px 0;
        border-bottom: 1px solid var(--border);
    }

    .cart-table tbody td {
        padding: 0;
        border: none;
        font-size: 14px;
        color: var(--text-muted);
    }

    /* Название — на всю ширину карточки, остальное строкой под ним. */
    .cart-table tbody td:nth-child(1) {
        flex: 0 0 100%;
        font-size: 15px;
        color: var(--text);
        font-weight: 700;
        margin-bottom: 8px;
    }

    .cart-table tbody td:nth-child(4) { color: var(--text); font-weight: 700; }

    /* Крестик — в правый верхний угол карточки, где его и ищут, вместо пятой
       колонки за краем экрана. */
    .cart-table tbody td:nth-child(5) {
        position: absolute;
        top: 12px;
        right: 0;
    }

    /* Итоги — подпись слева, значение справа. colspan в сетке не действует,
       поэтому раскладываем ячейки явно. */
    .cart-table tfoot tr {
        display: grid;
        grid-template-columns: 1fr auto;
        gap: 8px;
        padding: 10px 0;
    }

    .cart-table tfoot td {
        padding: 0;
        border: none;
        font-size: 15px;
    }

    /* Пустая ячейка-заглушка пятой колонки заняла бы место в сетке и утащила
       сумму на вторую строку. */
    .cart-table tfoot td:empty { display: none; }

    /* Кнопке «Применить» нечем сжиматься — у неё white-space: nowrap, — и без
       переноса она выталкивала строку за край экрана. */
    .promo-block > div { flex-wrap: wrap; }
    #promo-input { min-width: 160px; }
}

/* Успешный заказ */
.success-icon {
    font-size: 64px;
    color: var(--accent);
    margin-bottom: 24px;
    animation: twinkle 2s ease-in-out infinite;
}

/* Карточка товара — мобильный */
.product-card__footer {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
}

.btn-add-cart:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    font-size: 11px;
    padding: 5px 10px;
}

/* Описание товара — переносы строк */
.product-detail__desc {
    white-space: pre-line;
}

/* Плашки товаров */
.badges {
    position: absolute;
    top: 10px;
    left: 10px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    z-index: 2;
}

.badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 12px;
    font-size: 11px;
    font-weight: 800;
    font-family: 'Manrope', sans-serif;
    letter-spacing: 0.5px;
}

.badge-hit {
    background: linear-gradient(135deg, #FF4589, #FF316B);
    color: #fff;
}

.badge-new {
    background: linear-gradient(135deg, #7c93e0, #a58ce0);
    color: #12141d;
}

.badge-back {
    background: linear-gradient(135deg, #34d399, #059669);
    color: #12141d;
}

/* Плашки на карточке товара */
.product-detail__badges {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 14px;
}

/* Хлебные крошки */
.breadcrumbs {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--text-muted);
    margin-bottom: 24px;
    flex-wrap: wrap;
}

.breadcrumbs a { color: var(--text-muted); transition: color 0.2s; }
.breadcrumbs a:hover { color: var(--accent); }
.breadcrumbs span { color: #4a4f6a; }

/* Поиск */
.search-form { margin-bottom: 28px; }

.search-input-wrap {
    display: flex;
    align-items: center;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: 24px;
    overflow: hidden;
    padding: 0 16px;
    gap: 8px;
}

.search-input-wrap input {
    flex: 1;
    background: transparent;
    border: none;
    padding: 12px 0;
    color: var(--text);
    font-family: 'Manrope', sans-serif;
    /* 16px, чтобы iOS не зумил страницу при фокусе. */
    font-size: 16px;
    outline: none;
}

/* Здесь стоял голый outline: none без замены — с клавиатуры фокус на поле
   поиска был не виден вообще. Подсвечиваем всю обёртку: само поле прозрачное и
   без рамки, обводка на нём выглядела бы обрезанной. */
.search-input-wrap:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(146, 178, 244, 0.25);
}

.search-input-wrap button {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 16px;
    padding: 4px;
}

.search-clear {
    color: var(--text-muted);
    font-size: 14px;
    text-decoration: none;
}

.search-clear:hover { color: var(--text); }

/* Пагинация */
.pagination {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 8px;
    margin-top: 48px;
    flex-wrap: wrap;
}

.page-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    height: 40px;
    padding: 0 12px;
    border-radius: 20px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-muted);
    font-size: 14px;
    font-family: 'Manrope', sans-serif;
    text-decoration: none;
    transition: all 0.2s;
}

/* Остаток в карточке каталога. Те же цвета, что у наличия на странице
   товара: одна и та же информация не должна выглядеть по-разному. */
.product-card__stock {
    font-size: 12px;
    color: var(--text-muted);
}

/* «В корзине: N» — акцентным цветом, в отличие от строки наличия рядом.
   Приглушённой она сливалась бы с остатком в одну серую кашу, а говорят эти две
   строки о разном: сколько есть у магазина и сколько уже взял покупатель. */
.product-card__in-cart,
.product-detail__in-cart {
    font-size: 12px;
    color: var(--accent);
    font-weight: 700;
}

.product-detail__in-cart {
    font-size: 14px;
    white-space: nowrap;
}

/* Атрибут hidden против правил с display — та же оговорка, что у кнопки в углу:
   без этого пустая строка занимала бы место в карточке. */
.product-card__in-cart[hidden],
.product-detail__in-cart[hidden] { display: none; }

/* Строка наличия на странице товара стоит в одном ряду со счётчиком
   количества и кнопкой (product-detail__actions — флекс с align-items:center),
   поэтому без нижнего отступа: он поднял бы её над соседями. */
.product-detail__stock {
    font-size: 14px;
    color: var(--text-muted);
    /* Фраза короткая и осмысленна только целиком: «✦ В наличии:» на одной
       строке и «3 шт.» на другой читается как обрывок. */
    white-space: nowrap;
}

/* Выделяется только малый остаток — в каталоге число всегда обычным цветом. */
.product-detail__stock strong {
    color: var(--accent-stock);
}

.page-btn:hover { border-color: var(--accent); color: var(--accent); }
.page-btn.active { background: var(--grad); color: var(--bg); border-color: transparent; font-weight: 800; }
.page-dots { color: var(--text-muted); padding: 0 4px; }

/* Кнопка корзины в углу экрана — только на мобильном (правило ниже, в
   медиазапросе). На десктопе корзина видна в шапке всегда, и вторая кнопка там
   лишняя. */
/* Кнопка корзины в углу экрана — на всех устройствах.
   Появилась под мобильную задачу: там ссылки шапки спрятаны под бургер. Но и на
   большом экране шапка уезжает вверх при прокрутке — у неё стоит sticky, который
   не работает из-за overflow-x: hidden у body (см. правило body выше), — и
   значок корзины теряется на длинном каталоге ровно так же.

   Тот же вид, что у значка в шапке, только крупнее: покупатель должен узнать в
   ней ту же кнопку, а не принять за новую сущность. z-index ниже мобильного
   меню (45) — открытый бургер обязан её накрывать. */
.cart-fab {
    display: flex;
    position: fixed;
    right: 24px;
    bottom: 24px;
    z-index: 30;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--grad);
    color: var(--bg) !important;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.45);
    transition: transform 0.2s, box-shadow 0.2s;
}

/* Значок количества у этой кнопки крупнее: 18 px хватало в шапке, где на него
   смотрят вплотную, а в углу экрана он читается хуже. */
.cart-fab .cart-count {
    top: -2px;
    right: -2px;
    min-width: 22px;
    height: 22px;
    font-size: 12px;
    border: 2px solid var(--bg);
    background: var(--bg2);
    color: var(--text);
}

/* Отклик на мышь — только там, где есть настоящий указатель: на тачскрине
   :hover залипает после касания, и кнопка осталась бы увеличенной до
   следующего касания в другом месте. Та же причина, по которой сюда уехали
   наведения карточек. */
@media (hover: hover) and (pointer: fine) {
    .cart-fab:hover {
        transform: scale(1.06);
        box-shadow: 0 10px 28px rgba(0,0,0,0.5);
    }
}

/* Атрибут hidden сам по себе тут бессилен: правило с display перебивает
   стиль браузера, и скрытая кнопка продолжала бы висеть в углу. */
.cart-fab[hidden] { display: none !important; }

/* Бургер */
.burger {
    display: none;
    flex-direction: column;
    gap: 5px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 4px;
    z-index: 50;
}

.burger span {
    display: block;
    width: 24px;
    height: 2px;
    background: var(--text);
    border-radius: 2px;
    transition: all 0.3s;
}

.burger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger.open span:nth-child(2) { opacity: 0; }
.burger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 768px) {
    .burger { display: flex; }

    /* Заголовки документов мельче: 36px рассчитаны на широкую колонку, а на
       телефоне «Конфиденциальности» одним словом занимает больше её ширины. */
    .doc-title { font-size: 26px; }

    /* Тот же вид, что у значка корзины в шапке, только крупнее: покупатель
       должен узнать в ней ту же кнопку, а не принять за новую сущность.
       z-index ниже меню (45) — открытый бургер обязан её накрывать. */
    /* Ближе к углу, чем на большом экране: на телефоне край близко, и отступ в
       24 px съедает заметную долю ширины. */
    .cart-fab {
        right: 16px;
        bottom: 16px;
    }

    /* Шапка на мобильном — без backdrop-filter, и это не косметика.
       Элемент с backdrop-filter становится содержащим блоком для потомков с
       position: fixed, а меню лежит внутри шапки. Из-за этого оно растягивалось
       не по экрану, а по полоске шапки: «Главная» и «Каталог» уезжали выше
       верхнего края и пропадали, значки корзины и избранного вываливались на
       текст страницы, а тёмной подложки не было вовсе.
       Фон делаем непрозрачным: без размытия под шапкой просвечивал бы текст. */
    header {
        backdrop-filter: none;
        background: var(--bg);
    }

    #main-nav {
        display: none;
        flex-direction: column;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: rgba(18,20,29,0.98);
        backdrop-filter: blur(10px);
        z-index: 45;
        align-items: center;
        justify-content: center;
        gap: 32px;
        padding: 80px 48px;
        /* Экран в альбомной ориентации ниже, чем список из шести пунктов:
           без прокрутки нижние оказались бы недосягаемы. */
        overflow-y: auto;
    }

    #main-nav.open { display: flex; }

    #main-nav a {
        font-size: 22px;
        color: var(--text);
    }

    #main-nav .cart-btn {
        width: 52px;
        height: 52px;
        font-size: 22px;
    }

    /* Значок растёт вместе с кнопкой: в открытом меню она 52px, и тележка в
       20px терялась бы в середине круга. */
    #main-nav .cart-btn .icon-cart { width: 24px; height: 24px; }

    /* Категории на мобильном */
    .catalog-filters {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 8px;
        justify-items: stretch;
    }

    .filter-chip {
        text-align: center;
        width: 100%;
    }

    /* Фильтры + сортировка на мобильном — в колонку, во всю ширину */
    .catalog-controls {
        flex-direction: column;
        align-items: stretch;
    }

    .sort-form { width: 100%; }
    .sort-select { flex: 1; min-width: 0; }

    /* Карточка товара — шире текст */
    .product-detail {
        flex-direction: column;
        padding: 24px 16px;
    }

    .product-detail__info {
        min-width: unset;
        width: 100%;
    }

    .product-detail__desc {
        font-size: 15px;
        line-height: 1.8;
    }
}

/* Сброс глобальных стилей внутри виджета СДЭК */
#cdek-map input,
#cdek-map select,
#cdek-map button,
#cdek-map textarea {
    all: revert;
}

#cdek-map * {
    font-family: inherit;
    box-sizing: content-box;
}