/* ==========================================================================
   СЛОВНОВЧЕРА — design system
   Single stylesheet by design (Task 6 brief): grows across later tasks.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fonts (self-hosted, one @font-face per file/weight — see Task 6 note:
   some binaries carry internal name-table strings like "Manrope Medium" /
   "Unbounded SemiBold" rather than base-family-plus-weight, so we do not
   rely on that metadata; each block declares its own explicit font-weight
   under a shared font-family name).
   -------------------------------------------------------------------------- */

/* Onest (SIL OFL) — self-hosted woff2, one @font-face per weight. Used site-wide for both body
   and headings; heading rules just reach for the heavier weights (600–800). */
@font-face {
    font-family: 'Onest';
    src: url('/fonts/onest/onest-300-9d2ba87a66d7e48de78833eb714e6fe1.woff2') format('woff2');
    font-weight: 300;
    font-style: normal;
    font-display: optional;
}

@font-face {
    font-family: 'Onest';
    src: url('/fonts/onest/onest-400-f997ac56420f17c37861250396ddaaf8.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: optional;
}

@font-face {
    font-family: 'Onest';
    src: url('/fonts/onest/onest-500-2fd2a2585428daf72e39dc568958d85f.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: optional;
}

@font-face {
    font-family: 'Onest';
    src: url('/fonts/onest/onest-600-8c03bc070abb3b74caf3ad55f7e6a51a.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: optional;
}

@font-face {
    font-family: 'Onest';
    src: url('/fonts/onest/onest-700-339b667d09243379bb13113022500ab0.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: optional;
}

@font-face {
    font-family: 'Onest';
    src: url('/fonts/onest/onest-800-e0c4c784468c5f6b302e5ce9bc283b9f.woff2') format('woff2');
    font-weight: 800;
    font-style: normal;
    font-display: optional;
}

/* Metrics-matched fallback for Onest. Onest's own metrics (from the woff2): 1000 em, ascent 970,
   descent 305, x-height 527. Rendered in Arial while Onest is still loading, but with the SAME line
   box and character width — so when Onest swaps in there is NO reflow/jump, and (unlike swap alone)
   the text is visible immediately (no invisible flash). Used via the font stacks below. */
@font-face {
    font-family: 'Onest-fallback';
    src: local('Arial');
    /* size-adjust измерен ЭМПИРИЧЕСКИ в браузере (ширина одинакового текста в Onest vs Arial):
       Onest шире Arial всего на 3% → 103%. (Ранее стояло 131.2% по xAvgCharWidth — неверно, из-за чего
       кнопки/текст «скакали» при подмене шрифта.) ascent/descent — из реальных метрик Onest (970/305
       при upm 1000). При этих значениях запасной Arial занимает то же место, что Onest, и при подмене
       нет ни горизонтального, ни вертикального сдвига. */
    size-adjust: 103%;
    ascent-override: 97%;
    descent-override: 30.5%;
    line-gap-override: 0%;
}

/* --------------------------------------------------------------------------
   Brand tokens
   -------------------------------------------------------------------------- */

:root {
    /* Brand hex colors — exact values from Global Constraints, do not adjust. */
    --color-payne-gray: #62727F;
    --color-pastel-blue: #A8BAC6;
    --color-beige: #E5E3C5;
    --color-camel: #B19870;
    --color-old-burgundy: #442D2A;
    --color-eerie-black: #1E1E1E;
    --color-gainsboro: #D4DBE1;
    --color-alabaster: #F2F3EC;
    --color-white: #FFFFFF;

    /* Semantic aliases built on the tokens above — keep component CSS below
       readable without hard-coding hex values a second time.

       Retheme (revamp item 3): the storefront reads as brand blue + butter now, not
       burgundy/camel. --color-accent is the pastel blue, --color-accent-soft is the butter/beige
       tint for soft section backgrounds and badges, and --color-accent-dark stays a DEEP tone
       (payne-gray, not pale blue) specifically so primary buttons/prices keep white-text-legible
       contrast - pale blue with white text would be unreadable. --color-danger is unchanged
       (old-burgundy) and reserved for genuine error/destructive states (form errors, "danger"
       links), which are a different semantic than the brand accent. */
    --color-text: var(--color-eerie-black);
    --color-text-muted: var(--color-payne-gray);
    /* Тёплая бумага вместо чистого белого. Белый на экране холодный и «удешевляет» —
       владелица сформулировала это как «белый старит сайт», и она права: у брендов,
       на которые она ориентируется, страница всегда чуть тёплая (у Organic Zoo #F5F2EB).
       Значение подобрано между их бумагой и нашим прежним белым: заметно теплее белого,
       но светлее беж-зон (--color-beige #E5E3C5), чтобы зоны по-прежнему читались.

       ОТТЕНОК ВАЖНЕЕ ТЕПЛА, А КРАСНЫЙ ПЕРЕВЕС ВАЖНЕЕ ОТТЕНКА. Бумагу правили трижды, и
       владелица трижды повторила: «фон розовый». Первые две попытки чинили температуру и
       оттенок — 45°, потом 53° — но розовое никуда не делось, потому что причина была в
       другом. У тона #F6F5EE красного было на единицу больше зелёного, а разница с синим
       всего 8: слишком слабо, чтобы читаться жёлтым, и ровно столько, чтобы читаться
       подкрашенным серым с красным уклоном. Это и есть «грязно-розовый». Рядом насыщенная
       жёлтая шапка добивала эффект: на её фоне слабый тон уходит в противоположную сторону.

       Лечение не в подкрутке, а в двух правилах для всех светлых тонов сразу:
       R РОВНО РАВЕН G — красного перевеса нет как величины, оттенок ровно 60°, чистый жёлтый;
       разница с синим не меньше 11 — тон читается как ЦВЕТ, а не как испачканный серый.

       ПОТОМ ЖЕЛТИЗНУ СНЯЛИ НА 40%: с правилом R = G она стала не нужна. Насыщенность была
       защитой от розового — тон должен был звучать достаточно громко, чтобы читаться жёлтым,
       а не подкрашенным серым. Но громкость лечила следствие; причиной был красный перевес,
       и его больше нет. Без него тон можно опускать в тихий, почти нейтральный — розовым он
       не станет, потому что становиться нечем. Владелица попросила меньше жёлтого, и это
       ровно та правка, которую новая система позволяет сделать безопасно. */
    --color-bg: #F8F8EF;
    /* Самое светлое в системе: карточки, поля ввода, приподнятые панели. Не чистый белый —
       он единственным нейтральным пятном в кадре сбивает калибровку глаза, и тогда честно
       тёплая бумага рядом с ним снова читается розовой. --color-white остаётся чистым и
       живёт только там, где белый — это ТЕКСТ на тёмном. */
    --color-surface: #FDFDF7;
    /* Ступень между бумагой и панелью: подсветки при наведении, чередующиеся полосы. */
    --color-bg-soft: #F2F2E9;
    --color-bg-tint-blue: #EDF2F4;
    --color-border: var(--color-gainsboro);
    --color-accent: var(--color-pastel-blue);
    --color-accent-soft: var(--color-beige);
    --color-accent-dark: var(--color-payne-gray);
    --color-danger: var(--color-old-burgundy);
    /* Терракотовый красный, уже использованный в предупреждениях корзины и на карточке товара.
       Вынесен в переменную, потому что тем же цветом красится маркер сноски про Meta. */
    --color-footnote: #B24A2E;

    --font-heading: 'Onest', 'Onest-fallback', sans-serif;
    --font-body: 'Onest', 'Onest-fallback', sans-serif;

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4.5rem;

    --container-max: 1200px;
    --radius-sm: 6px;
    --radius-md: 12px;
    --header-height: 88px;
}

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body,
h1, h2, h3, h4, p, ul, ol, figure {
    margin: 0;
}

ul, ol {
    padding: 0;
    list-style: none;
}

img {
    max-width: 100%;
    display: block;
}

a {
    color: inherit;
    text-decoration: none;
}

button {
    font: inherit;
    color: inherit;
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
}

/* select/textarea are in here with input for a reason: native form controls do NOT inherit type
   from their parent, they fall back to the browser's own UI font (Arial on Chrome/macOS), which
   is how the product page's variant <select> and the admin textareas ended up off-brand while
   every other element on the page was Onest. */
input,
select,
textarea {
    font: inherit;
    color: inherit;
}

/* Пол по фону для полей ввода. Браузер рисует незаданный <input> ЧИСТО БЕЛЫМ, и на тёплой
   бумаге это выдаёт ровно те холодные пятна, из-за которых сайт и выглядел разнобойно: поле
   промокода в шторке корзины и счётчик количества на странице корзины так и остались
   #FFFFFF, пока все остальные поля давно жили на тёплом тоне.

   Список исключений завёрнут в :where() СПЕЦИАЛЬНО. Обычный :not() наследует вес своего
   аргумента, и девять атрибутных селекторов подряд дали бы правилу вес выше любого
   одиночного класса — оно перебило бы строку поиска и все прочие поля со своим цветом
   (проверено: строка поиска действительно посветлела). У :where() вес нулевой, поэтому
   правило весит ровно как один тег и работает как пол, а не как диктат: любое поле со
   своим классом продолжает жить по-своему. Кнопки и переключатели исключены: у них свой вид. */
input:where(:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], [type="submit"], [type="button"], [type="reset"], [type="image"], [type="file"])),
select,
textarea {
    background-color: var(--color-surface);
}

svg {
    display: block;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* --------------------------------------------------------------------------
   Base typography
   -------------------------------------------------------------------------- */

body {
    font-family: var(--font-body);
    font-weight: 400;
    font-size: 1rem;
    line-height: 1.6;
    color: var(--color-text);
    background: var(--color-bg);
}

h1, h2, h3,
.btn {
    font-family: var(--font-heading);
    font-weight: 700;
    line-height: 1.25;
    color: var(--color-text);
}

h1 {
    font-size: clamp(1.35rem, 1.1rem + 1vw, 1.9rem);
}

h2 {
    font-size: clamp(1.15rem, 1rem + 0.6vw, 1.5rem);
    margin-bottom: var(--space-4);
}

h3 {
    font-size: 1.1rem;
    font-weight: 600;
    margin-bottom: var(--space-2);
}

p {
    color: var(--color-text);
}

.container {
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--space-4);
}

section + section {
    margin-top: var(--space-8);
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-6);
    border-radius: var(--radius-sm);
    font-size: 0.95rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.btn--primary {
    background: var(--color-accent-dark);
    color: var(--color-white);
    border: 1px solid var(--color-accent-dark);
}

.btn--primary:hover {
    background: var(--color-eerie-black);
    border-color: var(--color-eerie-black);
}

.btn--secondary {
    background: transparent;
    color: var(--color-accent-dark);
    border: 1px solid var(--color-accent-dark);
}

.btn--secondary:hover {
    background: var(--color-accent-dark);
    color: var(--color-white);
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn--primary:disabled:hover {
    background: var(--color-accent-dark);
    border-color: var(--color-accent-dark);
}

/* Looks inactive but stays clickable (so the click can nudge the shopper to pick a colour). */
.btn.is-blocked {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn--primary.is-blocked:hover {
    background: var(--color-accent-dark);
    border-color: var(--color-accent-dark);
}

/* --------------------------------------------------------------------------
   Wordmark (shared by header, footer, hero)
   -------------------------------------------------------------------------- */

.wordmark {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
    text-align: center;
}

/* logo.svg is viewBox 0 0 2000 1000 (2:1) with fill="currentColor" - as a plain <img> (not
   inlined) its currentColor resolves to the SVG's own default (black), which reads fine on the
   light header/footer. Width-driven sizing keeps the 2:1 aspect ratio via `height: auto`. */
.wordmark__img {
    width: 190px;
    height: auto;
    display: block;
}

.wordmark--footer {
    flex-direction: row;
    align-items: center;
    gap: var(--space-4);
}

.wordmark--footer .wordmark__img {
    width: 150px;
}

/* --------------------------------------------------------------------------
   Marquee (running line) — the very first element in the body, above the header, on every page
   (see layout/base.html). Pure CSS: the track holds several copies of the same text already
   duplicated in the markup, translated left by exactly 50% of its own width, so the loop is
   seamless (at the halfway point the second half of copies lines up pixel-for-pixel with where
   the first half started).
   -------------------------------------------------------------------------- */

.marquee {
    overflow: hidden;
    background: var(--color-old-burgundy);
    color: var(--color-alabaster);
}

.marquee__track {
    display: flex;
    width: max-content;
    animation: marquee-scroll 100s linear infinite;
}

.marquee__item {
    flex: 0 0 auto;
    padding: var(--space-2) var(--space-6);
    font-family: var(--font-heading);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    white-space: nowrap;
    position: relative;
}

/* Small blue/butter accent dot between repeats, alternating so the strip doesn't read as flatly
   monochrome. */
.marquee__item::after {
    content: '';
    position: absolute;
    right: 0;
    top: 50%;
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--color-pastel-blue);
    transform: translateY(-50%);
}

.marquee__item:nth-child(even)::after {
    background: var(--color-beige);
}

@keyframes marquee-scroll {
    from {
        transform: translateX(0);
    }
    to {
        transform: translateX(-50%);
    }
}

@media (prefers-reduced-motion: reduce) {
    .marquee__track {
        animation-play-state: paused;
    }
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

.site-header {
    position: sticky;
    top: 0;
    z-index: 40;
    /* Soft brand tint (retheme follow-up) instead of plain white; logo/icons stay dark so they
       remain legible on top of it. */
    background: var(--color-beige);
    border-bottom: 1px solid var(--color-border);
    transition: background-color 0.25s ease, border-color 0.25s ease;
}

/* Home page: the header is overlaid transparently on top of the hero photo and turns into the solid
   coloured bar once you scroll (.is-scrolled), leokid-style. The .has-hero-overlay class is set on
   <html> by an inline head script BEFORE first paint (so there's no beige flash on load); main.js
   only toggles .is-scrolled on scroll. */
.has-hero-overlay .site-header {
    background: transparent;
    border-bottom-color: transparent;
}

.has-hero-overlay .site-header.is-scrolled {
    background: var(--color-beige);
    border-bottom-color: var(--color-border);
}

/* Pull the hero up under the transparent header from the very first paint (no JS-induced jump). */
.has-hero-overlay .hero {
    margin-top: calc(-1 * var(--header-height) - 1px);
}

/* Home page only (.has-hero-overlay is set on <html> just for the home hero): drop the footer's
   usual top margin so the footer sits flush under the hero photo instead of leaving a white band.
   Other pages keep the normal breathing room above the footer. */
.has-hero-overlay .site-footer {
    margin-top: 0;
}

.site-header__bar {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    min-height: var(--header-height);
    /* Deliberately NOT .container: this bar must span the full viewport width so the hamburger
       sits near the left edge and the utility icons near the right edge even on wide screens (a
       centered, max-width .container pulled both far in from the edges). It carries its own
       horizontal padding instead - small on the left (just enough breathing room for the
       hamburger's focus ring/tap target), larger on the right to match the utility icon cluster's
       usual .container-derived spacing. The logo stays centered via absolute positioning against
       this padding-box's full width, so it remains centered on the viewport either way. */
    padding-left: var(--space-3);
    padding-right: var(--space-5);
}

.hamburger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    color: var(--color-text);
}

.site-header .wordmark {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

/* Responsive header logo: ~140px on narrow phones, up to 220px from the tablet breakpoint (see
   the 768px query below) - stays comfortably inside --header-height at every size. */
.site-header .wordmark__img {
    width: 140px;
}

@media (min-width: 420px) {
    .site-header .wordmark__img {
        width: 180px;
    }
}

/* Mobile header: a slimmer bar (60px). The logo stays CENTRED (the base .wordmark absolute-centre
   rule), the hamburger sits left and the search / favourites / cart icons on the right. The logo SVG
   was cropped to its letters, so at 128px wide its box is only ~15px tall and fits the thin bar
   without stretching it (which used to leave a white gap under the header on the home hero). Placed
   after the 420px rule above so it wins for phones in the 420-768px range. */
@media (max-width: 768px) {
    :root {
        --header-height: 60px;
    }

    .site-header .wordmark__img {
        width: 128px;
    }

    /* Tighter icon cluster (so the bigger centred logo has room and never overlaps the search icon).
       The icons sit close to the right edge (small right padding) at the owner's request. The
       `.site-header` prefix raises specificity above the base .header-utility rules that appear later
       in this file (equal specificity would otherwise let those win by source order). */
    .site-header__bar {
        padding-right: var(--space-4);
    }

    .site-header .header-utility {
        gap: var(--space-1);
    }

    .site-header .header-utility__icon {
        width: 28px;
        height: 28px;
    }
}

.header-utility {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    justify-self: end;
}

.header-utility__pill {
    display: none;
    align-items: center;
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

.header-utility__icon {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    color: var(--color-text);
}

.header-utility__cart {
    color: var(--color-text);
}

.header-utility__badge {
    position: absolute;
    top: 0;
    right: 0;
    min-width: 16px;
    height: 16px;
    padding: 0 3px;
    border-radius: 999px;
    /* Blue accent badge (retheme item 3) - pastel blue is light enough that dark text (not
       white) is what stays legible on it. */
    background: var(--color-accent);
    color: var(--color-eerie-black);
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}

/* Hidden when the count is 0 (no "0" bubble poking above the icons - keeps the utility row clean). */
.header-utility__badge--hidden {
    display: none;
}

/* Highlights the search icon itself while the bar below is open (aria-expanded="true", set by
   static/js/search.js) - a plain color change, no layout shift. */
#search-toggle[aria-expanded="true"] {
    color: var(--color-accent-dark);
}

/* --------------------------------------------------------------------------
   Header search bar (fragments/header.html, static/js/search.js) - a slide-down bar just under
   the header's own row, toggled open/closed by #search-toggle. It lives inside .site-header
   (itself `position: sticky`), so it scrolls/sticks together with the rest of the header rather
   than floating independently, and never overlaps the marquee above or the mobile nav panel
   (`z-index: 50`, well above this bar's own stacking context).

   It hangs *below* the header out of flow (absolute, top: 100%) rather than growing it: the home
   hero is pulled up by exactly `-1 * --header-height`, so a bar that added its own height to the
   header would push the whole page down by that much the moment search was opened, tearing a
   strip open under the hero.

   This is the inner-page look (an opaque strip with a pill input). Over the home hero the bar
   sheds all of it and becomes a bare line on the photo - see the .has-hero-overlay rules below.
   -------------------------------------------------------------------------- */

.site-search-bar {
    position: absolute; /* out of flow: never changes .site-header's height */
    top: 100%;
    left: 0;
    right: 0;
    z-index: 45;
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-border);
    padding: var(--space-4) var(--space-5);
    animation: search-bar-slide-down 0.18s ease-out;
}

.site-search-bar[hidden] {
    display: none;
}

.site-search-bar__form {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    max-width: 560px;
    margin: 0 auto;
}

.site-search-bar__input {
    flex: 1;
    min-width: 0;
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    background: var(--color-bg-soft);
    font-size: 0.95rem;
}

.site-search-bar__input:focus {
    outline: none;
    border-color: var(--color-accent-dark);
    background: var(--color-surface);
}

/* Chrome draws its own clear-✕ inside `type="search"` fields, in its own blue - it lands right
   next to our own submit icon and reads as a second, broken-looking control. */
.site-search-bar__input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}

.site-search-bar__submit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: 999px;
    background: var(--color-accent-dark);
    color: var(--color-white);
}

.site-search-bar__submit:hover {
    background: var(--color-eerie-black);
}

@keyframes search-bar-slide-down {
    from {
        opacity: 0;
        transform: translateY(-8px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .site-search-bar {
        animation: none;
    }
}

/* --------------------------------------------------------------------------
   Home page, header still floating transparently over the hero (.has-hero-overlay, not scrolled):
   search stops being a widget and becomes typography on the photo. The opaque strip is gone (it
   cut a hard band straight across the hero), and so is the pill - what is left is large, light
   text on a hairline rule, sitting high on the sky where the photo is calm.

   Readability without any fill behind it comes from three things together: the type is large, it
   carries a soft dark text-shadow (the same trick .hero__lede already uses over this photo), and
   the rule under it is near-white. Once the header goes solid on scroll, everything above takes
   over again and the bar is a normal opaque panel.
   -------------------------------------------------------------------------- */
.has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar {
    background: transparent;
    border-bottom-color: transparent;
    padding-top: var(--space-6);
    padding-bottom: var(--space-6);
}

.has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__form {
    max-width: 620px;
}

.has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__input {
    padding: var(--space-2) 2px var(--space-3);
    border: none;
    border-bottom: 1px solid rgba(255, 255, 255, 0.75);
    border-radius: 0;
    background: transparent;
    color: var(--color-white);
    font-size: clamp(1.15rem, 2.4vw, 1.6rem);
    font-weight: 300;
    letter-spacing: 0.02em;
    text-shadow: 0 1px 12px rgba(30, 30, 30, 0.45);
}

.has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__input::placeholder {
    color: rgba(255, 255, 255, 0.8);
}

.has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__input:focus {
    border-bottom-color: var(--color-white);
    background: transparent;
}

.has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__submit {
    width: 32px;
    height: 32px;
    background: transparent;
    color: var(--color-white);
    filter: drop-shadow(0 1px 8px rgba(30, 30, 30, 0.5));
}

.has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__submit:hover {
    background: transparent;
    opacity: 0.75;
}

/* Mobile: the transparent "line over the photo" search collides illegibly with the hero's own
   headline on the short mobile hero (both land in the same band). So on phones the home-page search
   reverts to the normal OPAQUE bar - a solid panel with a pill input - regardless of the hero
   overlay, so it reads cleanly and never overlaps the hero text. */
@media (max-width: 768px) {
    .has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar {
        background: var(--color-bg);
        border-bottom: 1px solid var(--color-border);
        padding: var(--space-4) var(--space-5);
    }

    .has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__input {
        padding: var(--space-2) var(--space-4);
        border: 1px solid var(--color-border);
        border-radius: 999px;
        background: var(--color-bg-soft);
        color: var(--color-text);
        font-size: 0.95rem;
        font-weight: 400;
        letter-spacing: 0;
        text-shadow: none;
    }

    .has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__input::placeholder {
        color: var(--color-text-muted);
    }

    .has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__input:focus {
        border-color: var(--color-accent-dark);
        background: var(--color-surface);
    }

    .has-hero-overlay .site-header:not(.is-scrolled) .site-search-bar__submit {
        width: 40px;
        height: 40px;
        background: var(--color-accent-dark);
        color: var(--color-white);
        filter: none;
    }
}

/* Live suggestions dropdown (static/js/search.js -> GET /search/suggest). Positioned relative to
   .site-search-bar (not the narrower .site-search-bar__form) so `left/right: 0` + this same
   max-width/margin-auto pair centers it exactly under the input, matching the form above it.
   It stays a solid white card in every state - product rows need their normal contrast, and over
   the hero it is the one piece of the search that must not be transparent.
   z-index 45 sits above the sticky header (40) but below the mobile nav panel (50) - the two
   never open at once, so no real conflict, but this keeps the stacking order sensible regardless. */
.site-search-suggestions {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    max-width: 560px;
    margin: 0 auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-top: none;
    border-radius: 0 0 var(--radius-md) var(--radius-md);
    box-shadow: 0 8px 24px rgba(30, 30, 30, 0.12);
    max-height: 360px;
    overflow-y: auto;
    z-index: 45;
}

/* Over the hero the dropdown has no strip to hang off, so it detaches into a floating card:
   rounded on all four corners, lifted off the input, and shadowed hard enough to read as a card
   over a photo rather than a pale rectangle lying on it. */
.has-hero-overlay .site-header:not(.is-scrolled) .site-search-suggestions {
    top: calc(100% - var(--space-5));
    max-width: 620px;
    border: none;
    border-radius: var(--radius-md);
    box-shadow: 0 18px 44px rgba(30, 30, 30, 0.3);
}

.site-search-suggestions[hidden] {
    display: none;
}

.site-search-suggestions__item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-4);
    color: var(--color-text);
}

.site-search-suggestions__item:not(:last-child) {
    border-bottom: 1px solid var(--color-border);
}

.site-search-suggestions__item:hover,
.site-search-suggestions__item:focus-visible {
    background: var(--color-bg-soft);
}

.site-search-suggestions__thumb {
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    object-fit: cover;
    border-radius: var(--radius-sm);
    background: var(--color-bg-soft);
}

.site-search-suggestions__info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.site-search-suggestions__name {
    font-size: 0.9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.site-search-suggestions__price {
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.site-search-suggestions__empty {
    padding: var(--space-4);
    color: var(--color-text-muted);
    font-size: 0.9rem;
    text-align: center;
}

/* --------------------------------------------------------------------------
   Mobile nav (slide-in panel, toggled by js/main.js)
   -------------------------------------------------------------------------- */

.mobile-nav {
    position: fixed;
    inset: 0;
    z-index: 50;
    visibility: hidden;
    pointer-events: none;
}

.mobile-nav.is-open {
    visibility: visible;
    pointer-events: auto;
}

.mobile-nav__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(30, 30, 30, 0.45);
    opacity: 0;
    transition: opacity 0.2s ease;
}

.mobile-nav.is-open .mobile-nav__backdrop {
    opacity: 1;
}

.mobile-nav__panel {
    position: relative;
    z-index: 1;
    width: min(320px, 85vw);
    height: 100%;
    /* Тот же материал, что у шторки корзины: обе выезжают поверх затемнённой страницы, значит
       обе должны быть приподнятой поверхностью, а не просто куском той же бумаги. Раньше меню
       стояло на тоне страницы и без тени — оно читалось как продолжение фона, поехавшее вбок,
       а корзина рядом как настоящая панель. Тень зеркальная: меню приходит слева, корзина
       справа, поэтому смещение по X с обратным знаком. */
    background: var(--color-surface);
    box-shadow: 12px 0 40px rgba(30, 30, 30, 0.18);
    padding: var(--space-6) var(--space-5);
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.mobile-nav.is-open .mobile-nav__panel {
    transform: translateX(0);
}

.mobile-nav__close {
    align-self: flex-end;
    width: 32px;
    height: 32px;
}

.mobile-nav__list li + li {
    margin-top: var(--space-4);
}

.mobile-nav__list a {
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 1.05rem;
}

/* Accordion (revamp item 10): a category with children (e.g. "Дети 1–7 лет") renders its own
   link plus a separate chevron toggle; the sublist is collapsed (max-height: 0) by default and
   expands when static/js/main.js toggles .is-expanded on the parent <li>. max-height (rather than
   height: auto, which can't be transitioned) is set generously above any realistic sublist's
   real height so the slide animation never clips content. */
.mobile-nav__parent-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}

.mobile-nav__accordion-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    color: var(--color-text-muted);
    transition: transform 0.2s ease;
}

.mobile-nav__item--accordion.is-expanded .mobile-nav__accordion-toggle {
    transform: rotate(180deg);
    color: var(--color-text);
}

.mobile-nav__sublist {
    margin-top: 0;
    max-height: 0;
    overflow: hidden;
    padding-left: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    transition: max-height 0.25s ease, margin-top 0.25s ease;
}

.mobile-nav__item--accordion.is-expanded .mobile-nav__sublist {
    margin-top: var(--space-3);
    max-height: 480px;
}

.mobile-nav__sublist a {
    font-family: var(--font-body);
    font-weight: 400;
    font-size: 0.9rem;
    color: var(--color-text-muted);
}

/* "Смотреть все" — the lead item of an expanded category submenu, a touch stronger than its
   sibling sub-category links. */
.mobile-nav__sublist-all {
    font-weight: 600;
    color: var(--color-text);
}

body.nav-open,
body.modal-open {
    overflow: hidden;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.site-footer {
    position: relative;
    isolation: isolate;
    margin-top: var(--space-8);
    /* Soft brand mesh gradient (сливочный Beige #E5E3C5 ↔ голубой Pastel Blue #A8BAC6), matching the
       branded bag. Only the two brand hexes over an alabaster base - no grey, so the blue stays true. */
    background-color: var(--color-alabaster);
    background-image:
        radial-gradient(95% 120% at 7% 16%, rgba(229, 227, 197, 0.98), rgba(229, 227, 197, 0) 55%),
        radial-gradient(90% 120% at 93% 84%, rgba(229, 227, 197, 0.85), rgba(229, 227, 197, 0) 52%),
        radial-gradient(115% 130% at 58% 46%, rgba(168, 186, 198, 0.95), rgba(168, 186, 198, 0) 60%),
        radial-gradient(70% 95% at 82% 22%, rgba(168, 186, 198, 0.72), rgba(168, 186, 198, 0) 55%);
    border-top: 1px solid var(--color-border);
    padding-top: var(--space-6);
}

.site-footer__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-6);
}

.site-footer__brand {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.site-footer__tagline {
    color: var(--color-text-muted);
    max-width: 21rem;
}

/* "Будьте на связи" + email form, sitting under the footer logo (moved here from the home page).
   Dropped a little lower under the logo, with the email field and button stacked at the same width
   so they line up. */
.site-footer__newsletter {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Тот же заголовок колонки, что «Покупателям» и «Контакты»: размер и вес НЕ переопределяем —
   берём глобальный h3 (1.1rem / 600), иначе «Будем на связи» выбивался (был 1.05rem / 400).
   Отступ снизу задаёт .newsletter-block, чтобы поле ввода встало на уровень «О нас». */
.site-footer__newsletter-title {
    margin-bottom: 0;
}

/* Страница подтверждения подписки: заголовок и кнопка по центру. .legal-page по умолчанию
   выравнивает текст по ширине (justify) — для одной короткой строки это ни к чему. */
.newsletter-confirmed {
    text-align: center;
}

.newsletter-confirmed h1 {
    margin-bottom: var(--space-6);
}

.newsletter-confirmed .legal-page__note {
    text-align: center;
    margin-inline: auto;
}

/* Селектор из ДВУХ классов намеренно: у .legal-page есть `p { text-align: justify }` (класс + тег),
   и оно перебивает как выравнивание секции, так и одиночный класс — кнопка прижималась влево.
   По той же причине здесь перечислены ВСЕ абзацы этой страницы: кнопка «Скопировать промокод»
   и строка «промокод скопирован» ловили ту же justify-выключку и уезжали к левому краю. */
.newsletter-confirmed .newsletter-confirmed__action {
    text-align: center;
    margin: var(--space-3) 0 0;
}

/* Отбивка перед «Смотреть каталог» больше: это следующий шаг, а не ещё одна кнопка в ряду. */
.newsletter-confirmed .newsletter-confirmed__action:last-of-type {
    margin-top: var(--space-5);
}

/* И такая же отбивка ПОСЛЕ кнопки: подпись «Введите код в корзине…» стояла к ней вплотную и
   читалась как часть кнопки. Это отдельная мысль — ей нужен воздух. */
.newsletter-confirmed .newsletter-confirmed__action + .legal-page__note {
    margin-top: var(--space-5);
}

/* Обёртка «заголовок + форма подписки». Повторяет раскладку родителя, потому что заголовок теперь
   живёт внутри фрагмента (чтобы исчезать вместе с формой после подписки) — иначе он остаётся
   единственным соседом формы без отступа между ними. */
.newsletter-block {
    display: flex;
    flex-direction: column;
    /* space-4, а не space-3: у соседней колонки между «Покупателям» и «О нас» набегает 15 px
       (12 px отступа заголовка + собственная строка ссылки), и с 12 px поле ввода вставало на
       3 px выше. С 16 px первая строка всех колонок сходится в одну линию. */
    gap: var(--space-4);
}

/* Сообщение после подписки — на месте заголовка и формы. Не «плашка», а спокойный текст в тон
   подвала: это финал действия, а не предупреждение. */
.newsletter-done {
    /* pre-line: перевод строки из самого текста сообщения работает, а лишние пробелы/переносы в
       разметке — нет. «Спасибо за подписку!» стоит отдельной строкой. */
    white-space: pre-line;
    /* Первая строка сообщения встаёт на уровень «О нас», а не на уровень заголовков колонок:
       заголовок «Будем на связи» исчез вместе с формой, и без этого отступа текст поднимался в
       строку заголовков. Считаем ровно ту высоту, которую занимал заголовок (1.1rem × line-height
       1.25) плюс отступ до первой строки. */
    margin-top: calc(1.1rem * 1.25 + var(--space-4));
    max-width: 340px;
    font-family: var(--font-heading);
    font-size: 1.05rem;
    line-height: 1.5;
    color: var(--color-text);
}

/* Roomy stacked form: a comfortably wide email field with the button below it, both full-width of
   the newsletter column - reads as a proper sign-up, not a cramped little box. */
/* flex-wrap: nowrap ОБЯЗАТЕЛЕН, и это не перестраховка. Базовый .newsletter-form объявлен с
   flex-wrap: wrap ради строчной раскладки на главной, а здесь направление меняется на column — и в
   колоночном flex перенос работает не так, как ожидаешь: элементы переносятся не на новую строку, а
   в НОВЫЙ СТОЛБЕЦ справа. Высота при этом ограничена: подвал — грид, его ячейки растягиваются на
   высоту строки, так что у формы есть определённая высота, в которую надо влезть.

   Пока в форме было два элемента (поле и кнопка), они в эту высоту помещались и перенос не
   срабатывал. Третий — блок согласий — не поместился, и форма разложилась в три столбца поверх
   колонок «Покупателям» и «Контакты»: поле слева, галочки на ссылках, кнопка в контактах.
   Колонка из полей формы не должна переноситься никогда, поэтому запрет прямой. */
.site-footer__newsletter .newsletter-form {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    max-width: 340px;
    gap: var(--space-3);
}

/* Mobile: let the email field + "Подписаться" button fill the full column width, so their side
   margins match the rest of the footer (the 340px cap left extra space on the right). */
@media (max-width: 768px) {
    .site-footer__newsletter .newsletter-form {
        max-width: none;
    }
}

.site-footer__newsletter .newsletter-form__label {
    flex: none;
    width: 100%;
}

.site-footer__newsletter .newsletter-form__input {
    padding-block: var(--space-4);
}

.site-footer__newsletter .newsletter-form__submit {
    width: 100%;
}

/* flex: none — по той же причине, что и у .newsletter-form__label выше. В строчной раскладке
   (главная) блоку согласий нужен flex-basis: 100%, чтобы занять целую строку. Здесь направление
   колоночное, и та же сотня процентов означает уже 100% ВЫСОТЫ контейнера — вместе с
   flex-shrink: 1 это отдало бы согласиям всю высоту формы и сплющило поле ввода с кнопкой.
   Ширину задаём отдельно: колонка подвала шире формы, и без ограничения строки согласий вылезали
   бы за правый край поля ввода. */
.site-footer__newsletter .newsletter-form__consents {
    flex: none;
    max-width: 340px;
}

@media (max-width: 768px) {
    .site-footer__newsletter .newsletter-form__consents {
        max-width: none;
    }
}

.site-footer__social {
    display: flex;
    gap: var(--space-3);
}

.site-footer__social-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1px solid var(--color-border);
    font-size: 0.7rem;
    font-weight: 700;
}

.site-footer__col h3 {
    margin-bottom: var(--space-3);
}

.site-footer__col ul li + li {
    margin-top: var(--space-2);
}

.site-footer__col a {
    /* Darker than the muted payne-gray so links stay readable over the footer's colour gradient. */
    color: #363c42;
}

.site-footer__col a:hover {
    color: var(--color-eerie-black);
}

/* Контакты: a collapsible item at the end of the Покупателям list. The toggle
   button matches the sibling footer links; clicking it expands the panel with
   the social channels + contact info. */
.site-footer__contacts-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--color-text-muted);
    font: inherit;
    cursor: pointer;
}

/* When Контакты is its own footer column, its toggle doubles as the column heading - match the
   sibling <h3> headings (font/size/weight/spacing). */
.site-footer__contacts .site-footer__contacts-toggle {
    margin-bottom: var(--space-3);
    font-family: var(--font-heading);
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--color-text);
}

.site-footer__contacts-toggle:hover {
    color: var(--color-payne-gray);
}

.site-footer__contacts-chevron {
    transition: transform 0.2s ease;
}

.site-footer__contacts-toggle[aria-expanded="true"] .site-footer__contacts-chevron {
    transform: rotate(180deg);
}

/* Раскрытие: max-height анимируется до РЕАЛЬНОЙ высоты контента (её ставит main.js через scrollHeight),
   а не до фиксированного значения — поэтому нет «перелёта» и мёртвой паузы. Пиксельная анимация max-
   height надёжно работает во всех браузерах (в отличие от grid-fr, который не анимируется в Safari).
   Короткий ease-out делает раскрытие снаппи, без ощущения «залипания».

   На телефоне панель остаётся в потоке: колонка там одна, раздвигать подвал вниз ей некуда
   мешать. На широких экранах она вынимается из потока — см. брейкпоинт 768px ниже. */
.site-footer__contacts-panel {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.2s ease-out;
}

/* No top margin: the intro starts right under the "Контакты" heading, level with "О нас" in the
   neighbouring column. Compact so the expanded panel fits the other columns' height and the footer
   doesn't grow when Контакты is opened. */
.site-footer__contacts-intro {
    margin-top: 0;
    max-width: none;
    /* Same dark graphite as the "Покупателям" links so it reads over the gradient. */
    color: #363c42;
    font-size: 1rem;
    /* 1.4, а не 1.5: разбивка на два предложения добавила абзацу пятую строку, и панель стала
       заканчиваться ниже соседней колонки. Строки чуть плотнее — и низ снова сходится. */
    line-height: 1.4;
    /* Выключка по формату: колонка узкая, и рваный правый край рядом с ровной колонкой ссылок
       выглядел неопрятно. Переносы намеренно выключены — слова рвутся целиком; расплата за это
       чуть более широкие межсловные пробелы в отдельных строках. */
    text-align: justify;
}

.site-footer__contact-email {
    display: inline-block;
    color: #363c42;
    margin-top: var(--space-2);
    margin-bottom: 0;
    font-size: 0.92rem;
}

.site-footer__contact-email:hover {
    color: var(--color-eerie-black);
}

.site-footer__contacts-panel .site-footer__social {
    margin-bottom: 0;
    color: var(--color-text-muted);
}

/* E-mail text + channel icons on one row (keeps the expanded panel short enough that opening it
   doesn't push the footer taller). */
.site-footer__contacts-foot {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-4);
    /* 4px вместо 8px — вместе со сноской ниже отыгрывает те 10 px, из-за которых последняя
       строка сноски висела ниже последней ссылки соседней колонки «Покупателям». */
    margin-top: 4px;
}

.site-footer__contacts-foot .site-footer__contact-email {
    margin: 0;
}

.site-footer__social-link:hover {
    color: var(--color-payne-gray);
    border-color: var(--color-payne-gray);
}

/* Маркер сноски, висящий в правом верхнем углу иконки Instagram (связывает её со сноской «*»
   внизу подвала). Раньше это была SVG-звезда в пять лучей — теперь ровно тот же типографский
   символ «*», что в сноске и в письмах; цвет и насыщенность приходят из .footnote-star.
   line-height: 1 обязателен: у строчного бокса иначе своя высота, и звёздочка уезжает вниз. */
.site-footer__social-link--ig {
    position: relative;
    overflow: visible;
}

.site-footer__social-star {
    position: absolute;
    top: -2px;
    right: -1px;
    font-size: 0.95rem;
    line-height: 1;
    pointer-events: none;
}

/* Маркер сноски про Meta. Красный, а не цвет текста: это единственная пометка на сайте,
   которую закон требует заметить, — сливаясь с абзацем, она свою работу не делает.
   Тон тот же, что у предупреждений в корзине (--color-footnote), чтобы не заводить
   в палитре второй красный. Звёздочка над иконкой Instagram в подвале
   (.site-footer__social-star) красится тем же цветом: это одна и та же сноска. */
.footnote-star {
    color: var(--color-footnote);
    font-weight: 600;
}

.site-footer__contacts ul li + li {
    margin-top: var(--space-2);
}

.site-footer__qr {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-4);
    color: var(--color-text-muted);
    font-size: 0.8rem;
}

.site-footer__qr img {
    width: 112px;
    height: 112px;
    background: var(--color-surface);
    padding: var(--space-2);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
}

.site-footer__bottom {
    /* Полоса была вчетверо выше, чем ей положено: четыре строки в столбик, каждая с отбивкой,
       да ещё щедрые поля сверху и снизу. Это служебный низ, а не раздел — он должен читаться
       как подпись под документом, поэтому три коротких элемента сведены в одну строку
       (см. .site-footer__requisites), а отступы ужаты почти вдвое. */
    /* Отбивка больше остальных отступов подвала: под колонками должно оставаться место для
       раскрытой панели «Контакты» — она вынута из потока и на эту строку не давит, но и
       налезать на реквизиты ей нельзя. */
    margin-top: var(--space-7);
    padding-block: var(--space-3);
    border-top: 1px solid var(--color-border);
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

/* Сноска про Meta живёт внутри раскрывающейся панели «Контакты», под строкой с почтой и
   иконками. Кегль ещё мельче остального в панели: это пометка при значке, а не текст, который
   читают. Нижнего отступа нет — она последняя в панели. */
.site-footer__disclaimer {
    /* Сноска прижата к строке с иконками намеренно: звёздочка, которую она объясняет, стоит
       прямо на иконке Instagram — чем ближе пояснение к своей звёздочке, тем оно понятнее.
       Заодно вторая (последняя) строка сноски встаёт ровно на уровень последней ссылки
       колонки «Покупателям», и низ подвала перестаёт быть рваным. */
    margin: 2px 0 0;
    font-size: 0.68rem;
    line-height: 1.4;
    color: var(--color-text-muted);
}

/* --- Фотографии брака в заявке на возврат -------------------------------------------------- */
/* Настоящий <input type=file> спрятан, а нажимается его подпись: браузерная кнопка «Выберите
   файл» выглядит чужой на любой странице и не переводится. */
.return-photos { display: flex; flex-direction: column; gap: var(--space-2); }
.return-photos[hidden] { display: none; }
.return-photos__button {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    align-self: flex-start;
    padding: 10px 18px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    font-size: 0.92rem;
    cursor: pointer;
}
.return-photos__button:hover { border-color: var(--color-payne-gray); }
/* Кнопку подсвечивает та же проверка, что и остальные поля формы: при браке фотография обязательна. */
.return-photos__button--invalid { border-color: var(--color-footnote); }
.return-photos__button input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}
/* Фокус с клавиатуры живёт на скрытом поле — рамку рисуем вокруг видимой подписи. */
.return-photos__button:focus-within {
    outline: 2px solid var(--color-payne-gray);
    outline-offset: 2px;
}
.return-photos__list {
    margin: 0;
    font-size: 0.85rem;
    color: var(--color-text-muted);
    word-break: break-word;
}
.return-photos__list[hidden] { display: none; }

/* Снимки в карточке заявки в админке. */
.admin-return-photos { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.admin-return-photos a { display: block; line-height: 0; }
.admin-return-photos img {
    width: 120px;
    height: 150px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
    background: var(--color-bg-soft);
}

/* Кнопка отзыва согласия на cookie. Выглядит как ссылка и стоит рядом с дисклеймером: это
   служебное действие, а не призыв — тому, кто её ищет, она нужна, остальным мешать не должна.
   Сбрасываем всё, что браузер рисует у <button> по умолчанию: фон, рамку, свои отступы и шрифт. */
.site-footer__cookie-link {
    display: inline-block;
    margin-bottom: 0;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: 0.72rem;
    /* Чёрным, в отличие от приглушённой строки реквизитов рядом: это единственное действие в
       нижней полосе, и найти его должно быть легче, чем прочитать номер ОГРНИП. */
    color: var(--color-eerie-black);
    text-decoration: underline;
    text-underline-offset: 0.2em;
    cursor: pointer;
}

.site-footer__cookie-link:hover {
    color: var(--color-accent-dark);
}

/* Реквизиты продавца под подвалом. Колонкой, а не строкой: почта — то, ради чего сюда смотрят
   чаще всего, и она должна стоять отдельно, а не теряться в перечислении номеров. */
/* Одна строка на двоих: реквизиты слева, «Настройки cookie» — прижаты к правому краю.
   Выключка по базовой линии, потому что кегли у них разные; перенос разрешён, поэтому на
   телефоне кнопка сама уйдёт под реквизиты. Точки-разделителя между ними больше нет: она
   нужна была, пока три элемента шли подряд одной строкой, а разнесённым по краям она бы
   висела посреди пустоты. */
.site-footer__requisites {
    display: flex;
    flex-flow: row wrap;
    align-items: baseline;
    justify-content: space-between;
    column-gap: var(--space-4);
    row-gap: var(--space-1);
}

/* Почта — тем же приглушённым цветом, что и вся строка реквизитов: она часть перечисления, а не
   отдельный призыв, и выделяться из него не должна. Что по ней кликают, показывает подчёркивание
   (с отступом, чтобы хвосты «р» и «у» не перечёркивались линией), а темнеет она только под курсором. */
.site-footer__requisites-email {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

.site-footer__requisites-email:hover {
    color: var(--color-text);
}

/* Строка с ИНН и ОГРНИП — служебная: нужна для доверия и по закону, но читать её подряд никто не
   станет. Поэтому мельче и приглушённее почты. Разделители — узкие шпации в разметке, а не
   отступы, чтобы при переносе на узком экране номера не разъезжались по разным строкам с висящей
   точкой. */
.site-footer__requisites-legal {
    margin-bottom: 0;
    font-size: 0.72rem;
    line-height: 1.6;
    color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Newsletter form (shared by footer + home page newsletter section)
   -------------------------------------------------------------------------- */

.newsletter-form {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    max-width: 420px;
}

.newsletter-form__label {
    flex: 1 1 220px;
}

.newsletter-form__input {
    width: 100%;
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
}

.newsletter-form__submit {
    flex: 0 0 auto;
}

/* Галочки согласий между полем и кнопкой. flex-basis: 100% обязателен: .newsletter-form —
   flex-контейнер с переносом, и без него блок встал бы В СТРОКУ с полем ввода, растолкав его и
   кнопку. Фрагмент подписки живёт и в подвале, и на главной, поэтому правило общее. */
.newsletter-form__consents {
    flex: 1 1 100%;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: var(--space-1);
}

/* align-items: flex-start, а не center: текст согласия в две строки переносится, и по центру
   квадратик уезжал бы на середину абзаца вместо первой строки. */
.newsletter-consent {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--color-text-muted);
    cursor: pointer;
}

/* flex: none — иначе flex-контейнер сжимает квадратик по ширине, когда текст длинный, и он из
   квадрата превращается в узкую полоску. margin-top подгоняет его к базовой линии первой строки. */
.newsletter-consent input[type="checkbox"] {
    flex: none;
    margin-top: 0.15em;
    cursor: pointer;
}

.newsletter-consent a {
    color: inherit;
    text-decoration: underline;
}

/* Подсветка при попытке отправить без согласия. Красным — только рамка квадратика: красить весь
   текст значило бы кричать на человека там, где достаточно показать, чего не хватает. */
.newsletter-consent.is-invalid input[type="checkbox"] {
    outline: 2px solid #E0393B;   /* тот же красный, что у .checkout-checkbox.is-invalid */
    outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Cards (collections grid, generic reuse for later tasks)
   -------------------------------------------------------------------------- */

.card,
.collection-card {
    display: block;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.collection-card:hover {
    box-shadow: 0 8px 24px rgba(30, 30, 30, 0.08);
    transform: translateY(-2px);
}

/* Deliberately NO lift or shadow on hover any more: a frameless card has no edge to lift, and a
   photo drifting 3px up out of a 2px seam just breaks the grid's alignment. The hover now happens
   inside the photo instead - the second shot fades in and the size/colour panel rises. */

.collection-card__media {
    aspect-ratio: 4 / 5;
    background: var(--color-bg-soft);
    overflow: hidden;
}

.collection-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.collection-card h3,
.collection-card p {
    padding-inline: var(--space-4);
}

.collection-card h3 {
    margin-top: var(--space-4);
    margin-bottom: var(--space-1);
}

.collection-card p {
    padding-bottom: var(--space-4);
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

/* --------------------------------------------------------------------------
   Home page: hero
   -------------------------------------------------------------------------- */

/* Landscape hero photo (1280x1024). The hero takes the photo's own aspect ratio so the whole frame
   shows full-bleed at a normal banner height, with no crop and no side bars (leokid-style banner). */
.hero {
    position: relative;
    isolation: isolate;
    aspect-ratio: 1280 / 1024;
    display: flex;
    align-items: center;
    overflow: hidden;
    color: var(--color-white);
    background: var(--color-alabaster);
}

.hero__image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    z-index: 1;
}

.hero::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    background: linear-gradient(180deg, rgba(30, 30, 30, 0) 45%, rgba(30, 30, 30, 0.6) 100%);
}

.hero__overlay {
    position: relative;
    z-index: 3;
    width: 100%;
    /* Bottom padding lifts the lede + CTA up off the very edge, sitting them over the sand above
       the child rather than crammed against the bottom. */
    padding: var(--space-5) var(--space-4);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4);
    text-align: center;
}

.hero__lede {
    max-width: 30.5rem;
    color: var(--color-white);
    text-shadow: 0 1px 14px rgba(30, 30, 30, 0.35);
}

/* Small brand-emblem watermark accent (emblem task, item 4, optional): a faint corner mark on
   the hero photo, the same idea as the little figure-8 mark tucked into the corner of the
   brand's own lifestyle photography. Inline SVG (not an <img>) so `stroke="currentColor"` picks
   up the `color` set here rather than defaulting to black - reused below on the About page photo
   with a different color/opacity for its lighter background. Purely decorative: aria-hidden. */
.brand-watermark {
    position: absolute;
    z-index: 1;
    width: 44px;
    height: 55px;
    pointer-events: none;
}

.brand-watermark--hero {
    right: var(--space-4);
    bottom: var(--space-4);
    color: var(--color-white);
    opacity: 0.35;
    filter: drop-shadow(0 1px 2px rgba(30, 30, 30, 0.35));
}

/* --------------------------------------------------------------------------
   Home page: brand story / USP
   -------------------------------------------------------------------------- */

.brand-story {
    max-width: 45rem;
}

.usp__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-6);
}

.usp__item p {
    color: var(--color-text-muted);
}

.collections__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
}

.newsletter-section {
    /* Butter section tint (retheme item 3), instead of the neutral alabaster used elsewhere. */
    position: relative;
    isolation: isolate;
    background: var(--color-accent-soft);
    border-radius: var(--radius-md);
    padding: var(--space-6);
}

/* --------------------------------------------------------------------------
   Cookie consent (Task 14): fixed bottom bar, shown once by static/js/cookie-consent.js.
   -------------------------------------------------------------------------- */

.cookie-consent[hidden] {
    display: none;
}

.cookie-consent {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 60;
    background: var(--color-eerie-black);
    box-shadow: 0 -4px 16px rgba(30, 30, 30, 0.18);
}

/* Плашка закреплена у нижнего края экрана, поэтому она перекрывает низ страницы, и доскроллить
   туда нельзя в принципе: даже в самом низу под плашкой оставался конец подвала — в том числе
   раскрытые «Контакты». Резервируем под неё место; реальную высоту проставляет
   static/js/cookie-consent.js, а после закрытия плашки она обнуляется.

   Запас живёт в ПОДВАЛЕ, а не на body: на body зарезервированная полоса заливалась фоном
   СТРАНИЦЫ, то есть под подвалом появлялась чужая по цвету полоса, которая ещё и меняла длину
   страницы, когда плашку закрывали. В подвале та же полоса залита его собственным градиентом и
   не читается как пустота. */
.site-footer {
    padding-bottom: var(--cookie-bar-space, 0px);
}

.cookie-consent__inner {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    padding-block: var(--space-5);
}

.cookie-consent__text {
    color: var(--color-white);
    font-size: 0.9rem;
    max-width: 42rem;
}

.cookie-consent__text a {
    color: var(--color-pastel-blue);
    text-decoration: underline;
}

.cookie-consent__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

/* --------------------------------------------------------------------------
   Catalog (Task 7): filter sidebar, sort/toolbar, product grid, pagination.
   Product-card visuals (.card, .product-card__media aspect-ratio) deliberately mirror
   .collection-card above rather than inventing a second card style.
   -------------------------------------------------------------------------- */

.catalog__header {
    margin-bottom: var(--space-3); /* вкладки/«Найдено» ближе к «Каталогу» — уже расстояние */
}

/* Лёгкий заголовок (вес 400) — спокойнее и современнее, чем базовый жирный 700. То же и у «Избранного». */
.catalog__header h1 {
    font-weight: 400;
    letter-spacing: -0.01em;
}

.catalog__description {
    color: var(--color-text-muted);
    max-width: 40rem;
}

/* Sub-category tab strip (e.g. "Все"/Футболки/Толстовки/... under "Дети 1-8 лет"): mirrors the
   .pagination__link is-active treatment above rather than inventing a third "active state" style. */
.subcategory-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
    margin-bottom: var(--space-6);
}

/* Plain text tabs (no pill/border boxes): inactive tabs are muted, the active one is dark with an
   underline. The transparent bottom border reserves the underline's space so switching tabs never
   nudges the row. */
.subcategory-tabs__link {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) 0;
    border-bottom: 2px solid transparent;
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--color-text-muted);
    background: none;
    transition: color 0.15s ease, border-color 0.15s ease;
}

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

.subcategory-tabs__link.is-active {
    color: var(--color-eerie-black);
    border-bottom-color: var(--color-eerie-black);
}

/* The catalogue spans the full viewport width (edge to edge, like loobmbrand.ru/newitems) rather
   than sitting inside the 1200px .container - only a small responsive gutter keeps the outer
   cards off the very edge. The heading, breadcrumbs and tabs share the same left gutter so they
   line up with the first product column. */
.catalog {
    padding-inline: clamp(var(--space-4), 2.5vw, var(--space-7));
    padding-block: var(--space-6) var(--space-5);
}

/* No big white void between the catalogue grid and the footer - let the footer sit right under the
   products (its own border + padding provide the separation). */
.site-main:has(.catalog) ~ .site-footer,
.site-main:has(.catalog) + .site-footer {
    margin-top: 0;
}

.catalog__layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-6);
    align-items: start;
}

.catalog__filters {
    background: var(--color-bg-soft);
    border-radius: var(--radius-md);
    padding: var(--space-5);
}

.filter-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.filter-form__group {
    border: none;
    padding: 0;
    margin: 0;
}

.filter-form__group legend {
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 0.95rem;
    margin-bottom: var(--space-3);
    padding: 0;
}

.filter-form__checkbox {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.9rem;
}

.filter-form__checkbox + .filter-form__checkbox {
    margin-top: var(--space-2);
}

.filter-form__group--swatches {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.filter-form__swatch {
    position: relative;
    display: inline-flex;
}

.filter-form__swatch input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.filter-form__swatch-dot {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 2px solid var(--color-border);
    display: inline-block;
}

.filter-form__swatch input:checked + .filter-form__swatch-dot {
    border-color: var(--color-accent-dark);
    box-shadow: 0 0 0 2px var(--color-white), 0 0 0 3px var(--color-accent-dark);
}

.filter-form__price-range {
    display: flex;
    gap: var(--space-2);
}

.filter-form__price-range input {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
}

.filter-form__submit {
    width: 100%;
}

.catalog__toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
    flex-wrap: wrap;
}

.catalog__count {
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

.catalog__empty {
    color: var(--color-text-muted);
    padding: var(--space-7) 0;
    text-align: center;
}

/* The photos sit almost flush - a 2px seam between cards, a slightly taller one between rows so a
   name/price band never reads as belonging to the photo underneath it. The cards themselves carry
   no frame (see .product-card below), so the gutter is the ONLY thing separating one shot from the
   next, and keeping it hairline-thin is what makes the grid read as one continuous wall of
   photography rather than a tray of boxed thumbnails. */
.product-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);   /* phones: two per row */
    gap: var(--space-5) 2px;
}

@media (min-width: 640px) {
    .product-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (min-width: 1024px) {
    .product-grid {
        grid-template-columns: repeat(4, 1fr);
    }
}

/* Equal-height polaroid frames across a catalogue row: the grid stretches each cell, and this
   makes the wrapped card fill its cell so a one-line name and a three-line name still produce
   frames of the same height (the extra goes to white frame below the caption). Scoped to the
   catalogue grid, whose children are wrapper <div>s - the favorites grid appends bare
   .product-card articles straight into .product-grid, so a blanket rule would flex those cards. */
.catalog__results .product-grid > * {
    display: flex;
}

.catalog__results .product-grid > * > .product-card {
    width: 100%;
}

/* No frame at all: the photographs ARE the grid. The old polaroid matte (white fill + border +
   padding) put a visible box around every shot and forced a gutter wide enough to justify it; with
   the frame gone the cards sit almost flush (see the 2px gutters above) and the page reads as one
   continuous wall of photography, the way current fashion grids do. */
.product-card {
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0;
    box-shadow: none;
    transition: transform 0.2s ease;
}

.product-card__media {
    position: relative;
    aspect-ratio: 4 / 5;
    background: var(--color-bg-soft);
    overflow: hidden;
    border-radius: 0;
}

.product-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Hover image-swap (like the reference shop): the primary photo stays in flow; the secondary
   is stacked on top of it and fades in when the card is hovered, with a gentle zoom on both.
   Falls back gracefully - a card with only one image simply has no secondary layer. */
.product-card__img--primary {
    transition: opacity 0.5s ease, transform 0.6s ease;
}

.product-card__img--secondary {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 0.5s ease, transform 0.6s ease;
}

.product-card:hover .product-card__img--secondary {
    opacity: 1;
}

.product-card:hover .product-card__img--primary,
.product-card:hover .product-card__img--secondary {
    transform: scale(1.04);
}

@media (hover: none) {
    /* No hover on touch devices - never hide the primary behind an invisible layer. */
    .product-card__img--secondary {
        display: none;
    }
}

/* --------------------------------------------------------------------------
   Favorites heart (revamp item 9) — overlaid top-right on the product-card image, and reused
   (bigger, inline with the heading) on the product detail page. Purely a client-side toggle
   (static/js/favorites.js); the filled/active state uses the blue accent per the retheme.
   -------------------------------------------------------------------------- */

.favorite-heart {
    position: absolute;
    top: var(--space-2);
    right: var(--space-2);
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.85);
    color: var(--color-eerie-black);
    transition: background-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}

.favorite-heart:hover {
    transform: scale(1.08);
}

.favorite-heart.is-active {
    color: var(--color-pastel-blue);
}

.favorite-heart.is-active svg path {
    fill: var(--color-pastel-blue);
}

.favorite-heart--detail {
    position: static;
    width: 40px;
    height: 40px;
    background: var(--color-bg-soft);
    flex: 0 0 auto;
}

/* Favorites heart overlaid on the product photo (top-right), above the image + zoom hint. */
.product-gallery__main .favorite-heart {
    z-index: 2;
}

/* Hover panel inside the photo (fragments/product-card.html): sizes on the left, colour dots on the
   right, rising from the bottom edge. Frosted rather than solid so the photo still shows through -
   the panel is an annotation on the picture, not a drawer covering it.

   translateY(101%), not 100%: a fractional layout height can leave a hairline of the panel visible
   at exactly 100%, and that sliver reads as a rendering bug along the bottom of every card. */
.product-card__quick {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: rgba(255, 255, 255, 0.92);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    transform: translateY(101%);
    transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.3, 1);
}

.product-card:hover .product-card__quick,
.product-card:focus-within .product-card__quick {
    transform: translateY(0);
}

/* No hover on a phone, and pinning this permanently over the bottom of every photo would cover the
   very thing people scroll a catalogue to look at. The product page carries all of it anyway. */
@media (max-width: 900px), (hover: none) {
    .product-card__quick {
        display: none;
    }
}

.product-card__sizes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

.product-card__size {
    font-size: 0.78rem;
    letter-spacing: 0.01em;
    color: var(--color-text);
    white-space: nowrap;
}

.product-card__size--out {
    color: var(--color-text-muted);
    opacity: 0.55;
    text-decoration: line-through;
}

/* Deliberately tiny (10px) and unringed: at this size the dots are a hint that the product comes in
   several colourways, not a control - the real, tappable swatches live on the product page. A dark
   border would turn each one into a bullseye and shout louder than the photo behind it, so they get
   only a hairline, and only to keep near-white colourways from vanishing into the panel. */
.product-card__dots {
    display: flex;
    flex-shrink: 0;
    gap: 5px;
}

.product-card__dot {
    width: 10px;
    height: 10px;
    border-radius: 999px;
    border: 1px solid rgba(30, 30, 30, 0.12);
}

/* Caption: name on the left, price on the right, one quiet line under the photo. A fixed two-line
   box for the name is what keeps every price in a row on the same baseline - with the frames gone,
   a long name (the longsleeve) would otherwise push its price a line below its neighbours', and the
   misalignment is glaring across a flush grid. */
/* The horizontal padding is what stops one card's price from running straight into the next card's
   name: with a 2px seam between photos, captions set flush to the card edge read as a single
   sentence across the row ("1 690 ₽ Махровые полосатые шорты"). The photos stay flush; only the
   text is inset. */
.product-card__body {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-2) var(--space-4);
    text-align: left;
}

.product-card__name {
    font-family: var(--font-body);
    font-weight: 400;
    font-size: 0.9rem;
    line-height: 1.35;
    letter-spacing: 0;
    color: var(--color-text);
    margin-bottom: 0;
}

.product-card__price {
    color: var(--color-text);
    font-weight: 400;
    font-size: 0.9rem;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-7);
}

.pagination__link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 36px;
    padding-inline: var(--space-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
}

.pagination__link.is-active {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: var(--color-eerie-black);
}

/* --------------------------------------------------------------------------
   Product detail page (Task 8): image gallery, variant selector chips, quantity stepper.
   Reuses .btn / .product-grid (related products row uses the exact same fragment/grid as the
   catalog page) rather than inventing new primitives for those.
   -------------------------------------------------------------------------- */

.product-detail__layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-7);
    margin-bottom: var(--space-8);
}

.product-gallery__main {
    position: relative;
    aspect-ratio: 4 / 5;
    background: var(--color-bg-soft);
    border-radius: 0;
    overflow: hidden;
}

.product-gallery__main img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Zoom affordance — only once gallery.js has wired the click-to-open-fullscreen behaviour. */
.product-gallery__main.is-zoomable {
    cursor: zoom-in;
}

.product-gallery__zoom-hint {
    position: absolute;
    right: var(--space-3);
    bottom: var(--space-3);
    display: none;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.9);
    color: var(--color-eerie-black);
    box-shadow: 0 4px 14px rgba(30, 30, 30, 0.18);
    opacity: 0;
    transition: opacity 0.2s ease, transform 0.2s ease;
    pointer-events: none;
}

.product-gallery__main.is-zoomable .product-gallery__zoom-hint {
    display: inline-flex;
    opacity: 0.85;                 /* always visible once zoom is enabled, so it's an obvious cue */
}

.product-gallery__main.is-zoomable:hover .product-gallery__zoom-hint,
.product-gallery__main.is-zoomable:focus-visible .product-gallery__zoom-hint {
    opacity: 1;
    transform: scale(1.08);
}

/* --------------------------------------------------------------------------
   Full-screen image lightbox (gallery.js) — dark backdrop, large centred image, left/right nav.
   -------------------------------------------------------------------------- */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: clamp(var(--space-3), 4vw, var(--space-6));
    background: rgba(20, 20, 20, 0.92);
}

.lightbox[hidden] {
    display: none;
}

.lightbox__stage {
    margin: 0;
    flex: 1 1 auto;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
}

.lightbox__image {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: var(--radius-sm);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

.lightbox__nav,
.lightbox__close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-white);
    background: rgba(255, 255, 255, 0.12);
    border-radius: 50%;
    transition: background-color 0.15s ease;
}

.lightbox__nav:hover,
.lightbox__close:hover {
    background: rgba(255, 255, 255, 0.26);
}

.lightbox__nav {
    width: clamp(44px, 6vw, 60px);
    height: clamp(44px, 6vw, 60px);
    font-size: 2rem;
    line-height: 1;
}

.lightbox__close {
    position: absolute;
    top: var(--space-4);
    right: var(--space-4);
    width: 44px;
    height: 44px;
    font-size: 1.6rem;
    line-height: 1;
}

.lightbox__counter {
    position: absolute;
    bottom: var(--space-4);
    left: 50%;
    transform: translateX(-50%);
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.9rem;
    letter-spacing: 0.05em;
}

/* On phones the on-screen arrows overlap the image edges rather than eating layout width. */
@media (max-width: 599px) {
    .lightbox__nav {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
    }
    .lightbox__nav--prev { left: var(--space-2); }
    .lightbox__nav--next { right: var(--space-2); }
}

.product-gallery__thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

.product-gallery__thumb {
    width: 64px;
    height: 80px;
    padding: 0;
    border: 2px solid transparent;
    border-radius: 0;
    background: var(--color-bg-soft);
    overflow: hidden;
    cursor: pointer;
}

.product-gallery__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.product-gallery__thumb.is-active {
    border-color: var(--color-accent-dark);
}

.product-info__heading {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
}

.product-info__heading h1 {
    font-size: 1.35rem;
    margin-bottom: var(--space-1);
}

/* Thin rule between the name/price block and the spec (Состав/Цвет/Размер) block. */
.product-info__divider {
    height: 1px;
    border: 0;
    background: var(--color-border);
    margin-block: var(--space-3);
}

.product-info__sku {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    margin-top: var(--space-1);
    margin-bottom: 0;
}

.product-info__price {
    font-family: var(--font-heading);
    font-size: 1.3rem;
    font-weight: 600;
    color: var(--color-text);
    margin-top: var(--space-3);
    margin-bottom: 0;
}

.product-info__meta {
    font-size: 0.9rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-1);
}

.product-info__meta span {
    color: var(--color-text);
}

/* Size table (revamp item 7): a small reference chart, size range -> age, always showing the
   storefront's whole four-range grid. */

/* Wider modal so all four size columns are visible at once (the default 480px panel cut the last
   "116–122" column off). */
#size-guide-modal .modal__panel {
    width: min(780px, 100%);
}

.product-size-table__scroll {
    margin-top: var(--space-5);
    overflow-x: auto;
}

.product-size-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
}

.product-size-table th,
.product-size-table td {
    padding: var(--space-3) var(--space-2);
    border: 1px solid var(--color-border);
    text-align: center;
    white-space: nowrap;
}

.product-size-table thead th {
    background: var(--color-bg-soft);
    font-family: var(--font-heading);
    font-weight: 600;
}

.product-size-table tbody th {
    text-align: left;
    color: var(--color-text-muted);
    font-weight: 600;
}

.product-size-table__note {
    margin-top: var(--space-3);
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

/* Характеристики (revamp item 8): a plain definition list, term/value pairs stacked on mobile. */
.product-specs {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.product-specs__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--color-border);
}

/* The last row (Уход, whose own care-list already reads as a clean stopping point) must not carry
   the divider used BETWEEN rows - without this, every row (including the last) got a
   border-bottom, so a stray horizontal line rendered right after the care-instruction list,
   inside the accordion's own bottom padding. */
.product-specs__row:last-child {
    padding-bottom: 0;
    border-bottom: none;
}

.product-specs__row dt {
    flex: 0 0 140px;
    font-weight: 600;
    color: var(--color-text-muted);
}

.product-specs__row dd {
    flex: 1 1 200px;
    margin: 0;
}

/* Уход (product-detail item 3): the "Материал/уход" row's replacement - an intro line plus a
   small icon + text row per care instruction, instead of a plain bullet list. */
.product-specs__row--care dd {
    flex-basis: 100%;
}

.care-list__intro {
    margin: 0 0 var(--space-3);
    color: var(--color-text-muted);
}

.care-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    list-style: none;
    padding-left: 0;
    margin: 0;
}

.care-list__item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.care-list__icon {
    flex: 0 0 auto;
    color: var(--color-accent-dark);
}

/* Доставка и оплата / Возврат (revamp item 8). */
.product-shipping-info ul {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.product-shipping-info li {
    position: relative;
    padding-left: var(--space-4);
    color: var(--color-text-muted);
}

.product-shipping-info li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.6em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--color-pastel-blue);
}


/* Colour options as photo thumbnails (Ziggy-Zaza style, fragments product/detail.html): a row of
   small garment photos, one per colourway product, the selected one ringed. Each is a link to that
   colour's own product page. */
.product-colorways__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-2);
}

.product-colorway {
    display: block;
    width: 58px;
    height: 72px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    box-shadow: 0 0 0 1px var(--color-border);
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

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

.product-colorway:not(.product-colorway--active):hover {
    transform: translateY(-1px);
    box-shadow: 0 0 0 1px var(--color-text-muted);
}

/* The current colour: a dark ring set off from the photo by a gap of page background, and not a
   link (it's the page you're on). */
.product-colorway--active {
    box-shadow: 0 0 0 2px var(--color-eerie-black);
    cursor: default;
}

.product-colorway:focus-visible {
    outline: 2px solid var(--color-accent-dark);
    outline-offset: 2px;
}

/* The vertical rhythm here is deliberately tight (space-4 gaps, not space-5) so the info column of
   the longsleeve - the one product with an extra "Цвет швов" selector - still fits inside the main
   photo's height. That is what lets its `margin-top: auto`-pinned "О модели"/"Детали" accordions
   end level with the bottom of the first photo instead of overflowing past it. Shorter products
   (no seam-colour row) simply gain a little more auto-margin above the accordions; their alignment
   is unaffected. */
.add-to-cart-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    max-width: 360px;
    margin-top: var(--space-4);
}

/* Soft, rounded add-to-cart button in the brand's muted tone - sentence case, pill shape, gentle
   weight (the old solid-black UPPERCASE spec button read as harsh against the pastel palette). */
.add-to-cart-form__submit {
    background: transparent;
    border: 1px solid var(--color-eerie-black);
    color: var(--color-eerie-black);
    padding-block: var(--space-4);
    border-radius: 0;
    text-transform: none;
    letter-spacing: 0.02em;
    font-weight: 500;
    font-size: 0.95rem;
}

.add-to-cart-form__submit:hover {
    background: var(--color-eerie-black);
    border-color: var(--color-eerie-black);
    color: var(--color-white);
}

/* Colour: informational only (revamp follow-up) - a round swatch + label, never a selector
   (see js/variant-selector.js's header comment). */
.product-color-static {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
}

/* "Цвет" label, same quiet soft style as the "Размер" label above it. */
.product-color-static__title {
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 0.85rem;
    text-transform: none;
    letter-spacing: 0;
    color: var(--color-text-muted);
}

/* Colour: a round swatch + name inline, no bordered box (the boxed paint-chip read as clunky). */
.product-color-static__chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0;
    border: none;
    background: transparent;
    font-size: 0.95rem;
}

/* Round now, but deliberately still the 40px it always was: the info column's total height is what
   lines its bottom edge up with the bottom of the gallery next to it, and shrinking this swatch to
   match the 26px seam dots below pulled that edge 14px short. It is also the one colour here that
   is a crop of the real product photo rather than a flat fill, so it earns being the larger mark -
   at 26px a print or a melange just turns to mush. */
.product-color-static__swatch {
    width: 40px;
    height: 40px;
    border-radius: 999px;
    border: 1px solid rgba(30, 30, 30, 0.12);
    flex: 0 0 auto;
    background-size: cover;
    background-position: center;
}

.product-color-static__name {
    font-weight: 500;
}

/* Size guide: opens #size-guide-modal (static/js/modal.js) instead of an inline table. */
.size-guide-trigger {
    align-self: flex-start;
    font-size: 0.85rem;
    text-decoration: underline;
    color: var(--color-text-muted);
}

.size-guide-trigger:hover {
    color: var(--color-text);
}

.variant-selector__group {
    margin-bottom: var(--space-3);
}

.variant-selector__group[hidden] {
    display: none;
}

.variant-selector__label {
    display: block;
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 0.85rem;
    text-transform: none;
    letter-spacing: 0;
    color: var(--color-text-muted);
    margin-bottom: var(--space-2);
}

.variant-selector__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
}

/* Sizes as a clean row of text (no boxes): the chosen one is underlined, loobmbrand-style. */
.variant-chip {
    padding: var(--space-1) 0;
    /* Фиксированная минимальная ширина: иначе чип подгоняется под ширину текста, а цифры у Onest и
       запасного шрифта разной ширины — при подмене шрифта чипы «скакали». Теперь ширина не зависит
       от шрифта (размеры вида «116–122» помещаются), поэтому подмена ничего не двигает. */
    min-width: 4.25rem;
    border: none;
    border-radius: 0;
    background: transparent;
    font-size: 0.95rem;
    font-weight: 500;
    text-align: center;
    color: var(--color-text-muted);
    border-bottom: 1.5px solid transparent;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.variant-chip:not(.is-active):not(.is-disabled):hover {
    color: var(--color-text);
    border-bottom-color: var(--color-border);
}

.variant-chip.is-active {
    color: var(--color-text);
    border-bottom-color: var(--color-eerie-black);
    font-weight: 600;
}

.variant-chip:disabled,
.variant-chip.is-disabled {
    opacity: 0.4;
    text-decoration: line-through;
    cursor: not-allowed;
}

/* Seam-colour selector (longsleeve). The dropdown itself carries the styling, so the wrapping
   group is just a plain block that lets the dropdown span the full column width. */
.variant-selector__group--color {
    padding: 0;
    border: none;
    background: transparent;
}

.variant-selector__chips--swatches {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
}

/* The colour NAME, printed in the label itself ("Цвет швов — коричневый", js/variant-selector.js).
   The swatch alone can only show a shopper what a colour looks like, never what it is called - and
   the name is what they need when they come back to reorder or ask about it. It follows the cursor
   across the row (hover preview) and settles on the selected colour. */
.variant-selector__value {
    font-weight: 400;
    color: var(--color-text);
}

.variant-selector__value::before {
    content: ' — ';
    color: var(--color-text-muted);
}

/* Colour choice as round swatches: a filled circle per colourway, sized to be tapped, with the
   selected one carrying a thin dark ring set off from the dot by a gap of page background. The ring
   (rather than a heavy border or a fill change) is what keeps the colour itself undistorted - a
   border eats into a small dot and shifts how the colour reads. Unavailable colourways are struck
   through with a diagonal bar, the same "shown but not offered" language as the sizes. */
.color-swatch {
    position: relative;
    display: inline-flex;
    width: 28px;
    height: 28px;
    padding: 0;
    border-radius: 999px;
    background: transparent;
    border: none;
    box-shadow: 0 0 0 1.5px transparent;
    cursor: pointer;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

/* The dot is inset inside the button so the ring on .is-active lands in that gap instead of on the
   colour. The hairline border only exists to keep near-white colourways (молочный, айвори) from
   dissolving into the page. */
.color-swatch__dot {
    width: 18px;
    height: 18px;
    margin: auto;
    border-radius: 999px;
    border: 1px solid rgba(30, 30, 30, 0.12);
}

.color-swatch:not(.is-active):not(.is-disabled):hover {
    box-shadow: 0 0 0 1.5px var(--color-border);
    transform: translateY(-1px);
}

.color-swatch:focus-visible {
    outline: 2px solid var(--color-accent-dark);
    outline-offset: 2px;
}

.color-swatch.is-active {
    box-shadow: 0 0 0 1.5px var(--color-eerie-black);
}

.color-swatch.is-disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Diagonal strike across an unavailable colourway - opacity alone reads as "loading", not as
   "sold out". */
.color-swatch.is-disabled::after {
    content: '';
    position: absolute;
    inset: 4px;
    background: linear-gradient(to top right,
                                transparent calc(50% - 1px),
                                var(--color-text) calc(50% - 1px),
                                var(--color-text) calc(50% + 1px),
                                transparent calc(50% + 1px));
    border-radius: 999px;
}

/* When the shopper clicks the blocked add-to-cart button, the colour selector "signals itself":
   a quick shake plus an emphasised outline. */
@keyframes attention-shake {
    0%, 100% { transform: translateX(0); }
    20%, 60% { transform: translateX(-5px); }
    40%, 80% { transform: translateX(5px); }
}

.needs-attention {
    animation: attention-shake 0.4s ease;
}

@media (prefers-reduced-motion: reduce) {
    .needs-attention {
        animation: none;
    }
}

.variant-selector__native {
    display: block;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.variant-selector__native select {
    display: block;
    width: 100%;
    margin-top: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
}

.quantity-stepper {
    display: inline-flex;
    align-items: center;
    width: fit-content;
    border: 1px solid var(--color-border);
    border-radius: 0;
    overflow: hidden;
}

.quantity-stepper__btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    font-size: 1.1rem;
    color: var(--color-text-muted);
    transition: color 0.15s ease, background 0.15s ease;
}

.quantity-stepper__btn:hover {
    color: var(--color-text);
    background: var(--color-bg-soft);
}

.quantity-stepper input {
    width: 48px;
    height: 40px;
    border: none;
    border-left: 1px solid var(--color-border);
    border-right: 1px solid var(--color-border);
    text-align: center;
}

/* Hide the native number-input spinner (up/down) arrows on every quantity stepper (PDP + cart
   lines) - only the −/+ buttons and the typed value should be visible. Scoped to
   .quantity-stepper input so other, unrelated number inputs elsewhere are unaffected. */
.quantity-stepper input[type=number]::-webkit-inner-spin-button,
.quantity-stepper input[type=number]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.quantity-stepper input[type=number] {
    -moz-appearance: textfield;
    appearance: textfield;
}

.add-to-cart-form__stock-hint {
    min-height: 1.2em;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

/* "Уже в корзине" control on the product page: a live +/- stepper for the selected size's cart
   line, shown in place of the "Добавить в корзину" button once that size is in the cart. */
.pdp-in-cart {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-4);
}

/* These carry their own `display`, so the plain [hidden] attribute (UA display:none) would lose to
   it - re-assert display:none when hidden, at higher specificity, so variant-selector.js can toggle
   between the add button/stepper and the in-cart stepper by setting `hidden`. */
.pdp-in-cart[hidden],
.add-to-cart-form__submit[hidden],
.quantity-stepper[hidden] {
    display: none;
}

.pdp-in-cart__label {
    font-weight: 600;
}

.pdp-in-cart__stepper .quantity-stepper__btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.pdp-in-cart__qty {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 48px;
    height: 36px;
    padding-inline: var(--space-2);
    border-left: 1px solid var(--color-border);
    border-right: 1px solid var(--color-border);
    font-weight: 600;
}

.pdp-in-cart__link {
    color: var(--color-text-muted);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.pdp-in-cart__link:hover {
    color: var(--color-text);
}

.product-tabs {
    display: flex;
    flex-direction: column;
    max-width: 45rem;
    margin-top: var(--space-6);
    border-top: 1px solid var(--color-border);
}

/* --------------------------------------------------------------------------
   Accordions (Описание / Характеристики / Доставка и возврат on the product
   page) - collapsed by default, no JS height-measuring: `.accordion__panel`
   animates via a `max-height` 0->large transition rather than the `grid-
   template-rows: 0fr->1fr` trick, which still leaks a line of the collapsed
   panel's content: a stretched CSS Grid item's used height is computed as
   (available track space − its own padding), clamped at 0 rather than going
   negative, so `.accordion__panel-inner`'s padding-bottom alone renders as a
   visible sliver even at a genuine `0fr` track and `overflow: hidden`.
   `max-height` on `.accordion__panel` itself has no such gotcha: it caps the
   panel's own generated box (padding included) directly, so `overflow:
   hidden` clips everything - content and padding - at true zero height.
   -------------------------------------------------------------------------- */

.accordion {
    border-bottom: 1px solid var(--color-border);
}

/* Overrides the global `section + section { margin-top: var(--space-8) }` rule (see near the top
   of this file) specifically for the PDP accordions - Описание/Характеристики/Доставка и возврат
   are each their own <section class="accordion">, so without this override they'd inherit that
   generic big inter-section gap and no longer read as one tight, FAQ-style stacked list separated
   only by .accordion's own border-bottom. */
.product-tabs .accordion + .accordion {
    margin-top: 0;
}

.accordion__header-h {
    margin: 0;
    font-size: inherit;
}

.accordion__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: var(--space-4) 0;
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 1.1rem;
    text-align: left;
}

.accordion__chevron {
    flex: 0 0 auto;
    color: var(--color-text-muted);
    transition: transform 0.2s ease;
}

.accordion.is-open .accordion__chevron {
    transform: rotate(180deg);
}

.accordion__panel {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s ease;
}

.accordion.is-open .accordion__panel {
    /* Comfortably above the tallest panel's real content (Характеристики' six-row <dl> plus
       margins) so the transition never visibly clips an open panel; overflow stays hidden on
       the way there but the panel's actual (auto) content height is what's ultimately shown. */
    max-height: 700px;
}

.accordion__panel-inner {
    overflow: hidden;
}

.accordion__panel-inner > *:first-child {
    margin-top: 0;
}

.accordion__panel-inner p {
    color: var(--color-text-muted);
    white-space: pre-line;
}

.accordion__panel-inner {
    padding-bottom: var(--space-4);
}

.accordion__panel-inner h3 {
    margin-top: var(--space-5);
}

/* --------------------------------------------------------------------------
   Modal (size guide, static/js/modal.js) - a centered overlay, closed by
   default (`hidden`); the backdrop and the × button both carry
   `data-modal-close`.
   -------------------------------------------------------------------------- */

.modal {
    position: fixed;
    inset: 0;
    /* Высота — по ВИДИМОЙ части экрана. На телефоне (iOS Safari) `inset: 0` растягивает
       фиксированный слой на полный «большой» экран, включая область под панелью браузера, поэтому
       окно, отцентрированное по такому слою, визуально уезжало ВНИЗ. `dvh` учитывает панель, и
       окно встаёт ровно по центру видимой области. Браузеры без поддержки dvh просто игнорируют
       строку и ведут себя как раньше. */
    height: 100dvh;
    z-index: 60;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}

.modal[hidden] {
    display: none;
}

.modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(30, 30, 30, 0.5);
}

.modal__panel {
    position: relative;
    z-index: 1;
    width: min(480px, 100%);
    max-height: 85vh;
    overflow-y: auto;
    background: var(--color-surface);
    border-radius: var(--radius-md);
    padding: var(--space-6);
}

.modal__panel h2 {
    margin-bottom: var(--space-4);
    padding-right: var(--space-6);
}

.modal__close {
    position: absolute;
    top: var(--space-3);
    right: var(--space-3);
    width: 32px;
    height: 32px;
    font-size: 1.4rem;
    line-height: 1;
    color: var(--color-text-muted);
}

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

/* --------------------------------------------------------------------------
   "Товар добавлен в корзину" modal (product/detail.html, static/js/cart.js). Reuses
   .modal/.modal__backdrop/.modal__panel/.modal__close for the overlay shell, same as the
   size-guide and welcome modals.
   -------------------------------------------------------------------------- */

.cart-added-modal__product {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}

.cart-added-modal__image {
    width: 88px;
    height: 88px;
    flex-shrink: 0;
    object-fit: cover;
    border-radius: var(--radius-sm);
    background: var(--color-bg-tint-blue);
}

.cart-added-modal__name {
    margin: 0 0 var(--space-1);
    font-weight: 600;
}

.cart-added-modal__qty {
    margin: 0 0 var(--space-1);
    color: var(--color-text-muted);
}

.cart-added-modal__price {
    margin: 0;
    font-weight: 700;
}

.cart-added-modal__actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.cart-added-modal__actions .btn {
    width: 100%;
}

/* --------------------------------------------------------------------------
   Favorites-page size picker (templates/favorites.html, static/js/favorites.js). Reuses
   .modal/.modal__backdrop/.modal__panel/.modal__close for the overlay shell, and .variant-chip
   (product/detail.html's own size chips) for each size pill, so a disabled/out-of-stock size
   looks and behaves identically in both places.
   -------------------------------------------------------------------------- */

.size-picker-modal__product-name {
    margin: 0 0 var(--space-4);
    font-weight: 600;
}

.size-picker-modal__sizes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.size-picker-modal__message {
    margin: 0;
    color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Welcome promo modal (fragments/welcome-modal.html, static/js/welcome.js) -
   shown once per browser on first visit. Reuses .modal/.modal__backdrop/
   .modal__panel/.modal__close for the overlay shell; everything below is its
   own branded content, a soft blue-to-butter gradient card rather than the
   plain white size-guide modal panel.
   -------------------------------------------------------------------------- */

/* Editorial split card: photo (left) + gift offer (right). */
.welcome-modal__panel {
    position: relative;
    isolation: isolate;
    width: min(760px, 100%);
    padding: 0;
    overflow: hidden;
    border: none;
    border-radius: var(--radius-md);
    text-align: left;
    display: grid;
    grid-template-columns: 0.9fr 1.1fr;
    background: var(--color-surface);
}

/* Left: warm lifestyle photo with the slogan over its darkened bottom. */
.welcome-modal__media {
    position: relative;
    min-height: 430px;
    background-size: cover;
    background-position: center;
}

.welcome-modal__media::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(30, 30, 30, 0) 50%, rgba(30, 30, 30, 0.55) 100%);
}

.welcome-modal__slogan {
    position: absolute;
    left: var(--space-4);
    bottom: var(--space-4);
    z-index: 1;
    color: var(--color-white);
    font-family: var(--font-heading);
    font-size: 0.92rem;
    line-height: 1.35;
    text-shadow: 0 1px 12px rgba(30, 30, 30, 0.45);
}

/* Right: soft brand gradient (сливочный Beige ↔ голубой Pastel Blue), like the bag. */
.welcome-modal__body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-6);
    background-color: var(--color-alabaster);
    background-image:
        radial-gradient(95% 80% at 8% 6%, rgba(229, 227, 197, 0.92), rgba(229, 227, 197, 0) 60%),
        radial-gradient(95% 95% at 96% 100%, rgba(168, 186, 198, 0.8), rgba(168, 186, 198, 0) 62%);
}

/* Эмблема — на самом фото, в правом нижнем углу, напротив слогана. Мельче прежнего (было 44px
   в текстовой части), белая с мягкой тенью — как слоган, чтобы читалась на любом кадре. */
.welcome-modal__media .brand-emblem {
    position: absolute;
    right: var(--space-4);
    bottom: var(--space-4);
    z-index: 1;
    width: 30px;
    color: var(--color-white);
    opacity: 0.92;
    filter: drop-shadow(0 1px 8px rgba(30, 30, 30, 0.45));
}

.welcome-modal__eyebrow {
    margin: 0;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    font-size: 0.7rem;
    color: var(--color-text-muted);
}

.welcome-modal__title {
    margin: 0;
    font-size: 1.6rem;
    line-height: 1.12;
    color: var(--color-eerie-black);
}

.welcome-modal__text {
    margin: 0;
    font-size: 0.92rem;
    line-height: 1.5;
    color: var(--color-text);
}

.welcome-modal__text strong {
    font-weight: 700;
    color: var(--color-eerie-black);
}

.welcome-modal__promo {
    width: 100%;
    margin-top: var(--space-1);
}

.welcome-modal__code {
    display: block;
    width: 100%;
    padding: var(--space-3);
    border: 1px dashed var(--color-camel);
    background: var(--color-surface);
    text-align: center;
    font-family: var(--font-heading);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: 0.1em;
    color: var(--color-eerie-black);
}

.welcome-modal__copy {
    width: 100%;
    padding: var(--space-3) var(--space-5);
    background: var(--color-eerie-black);
    color: var(--color-white);
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
    transition: background 0.15s ease;
}

.welcome-modal__copy:hover {
    background: #000;
}

.welcome-modal__copied {
    margin: 0;
    font-size: 0.85rem;
    color: var(--color-accent-dark);
}

@media (max-width: 640px) {
    .welcome-modal__panel {
        grid-template-columns: 1fr;
        width: min(400px, 100%);
    }

    .welcome-modal__media {
        min-height: 170px;
    }

    .welcome-modal__body {
        padding: var(--space-5);
    }
}

/* --------------------------------------------------------------------------
   Breadcrumbs + "Вернуться назад" (fragments/breadcrumbs.html, product/detail.html).
   -------------------------------------------------------------------------- */

/* "← Вернуться назад" link, kept on the info pages (Доставка / Контакты / Возврат / Соглашение /
   О нас) at the top-left. Its styling was dropped when the link was removed from the catalog/product
   pages; restored here so it sits neatly at the top instead of falling to the default inline flow. */
.product-detail__back {
    display: inline-block;
    margin-bottom: var(--space-4);
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

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

.breadcrumbs {
    margin-top: var(--space-4);
    margin-bottom: var(--space-5);
}

/* leokid-style: small uppercase crumbs sitting at the very top of the product page. */
.breadcrumbs__list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    list-style: none;
    padding: 0;
    margin: 0;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.breadcrumbs__item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.breadcrumbs__item:not(:last-child)::after {
    content: '/';
    color: var(--color-border);
}

.breadcrumbs__link {
    color: var(--color-text-muted);
}

.breadcrumbs__link:hover {
    color: var(--color-accent-dark);
}

.breadcrumbs__current {
    color: var(--color-text);
}

.related-products {
    margin-top: var(--space-8);
}

.related-products h2 {
    margin-bottom: var(--space-5);
}

/* --------------------------------------------------------------------------
   Cart page (Task 9). Reuses .btn / .quantity-stepper from the product detail page rather than
   redefining the stepper a second time.
   -------------------------------------------------------------------------- */

.cart-page__title {
    margin-top: var(--space-5); /* чуть опускаем от шапки, чтобы не липло к верхней границе */
    margin-bottom: var(--space-6);
}

.cart-flash {
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-5);
}

.cart-flash--success {
    background: var(--color-beige);
    color: var(--color-eerie-black);
}

.cart-flash--error {
    background: var(--color-danger);
    color: var(--color-white);
}

.cart-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-4);
    padding: var(--space-8) 0;
    color: var(--color-text-muted);
}

/* Empty-state copy (cart + favorites): a tidy centred column that stays within the width of
   the "Смотреть каталог" button below it rather than sprawling wider than the CTA. */
.empty-state__text {
    max-width: 20rem;
    margin: 0 auto;
    line-height: 1.5;
}

/* --------------------------------------------------------------------------
   Brand emblem accents (fragments/brand.html) + faint pattern watermark.
   -------------------------------------------------------------------------- */

.brand-emblem {
    display: block;
    width: 40px;
    height: auto;
}

/* Empty states (cart + favorites): centred column, copy then the catalog button. The emblem that
   used to sit above the copy was dropped at the owner's request. */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-4);
    padding: var(--space-8) 0;
    color: var(--color-text-muted);
}

/* Эмблема выводится ровно в двух местах — на главной и в окне с промокодом, оба раза в ПРАВОМ
   нижнем углу. Правило для страниц ошибок (404/500) удалено: разметки под него давно нет,
   в шаблонах эмблема там не выводится. */

/* Brand emblem (horizontal, mono white) overlaid on the hero photo, bottom-right corner. */
.hero__emblem {
    position: absolute;
    right: clamp(var(--space-6), 7vw, var(--space-8));
    bottom: var(--space-5);
    z-index: 3;
    pointer-events: none;
}

.hero__emblem .brand-emblem {
    width: 52px;
    color: var(--color-white);
}

/* Smaller hero emblem on mobile (it read as oversized on a phone). */
@media (max-width: 768px) {
    .hero__emblem .brand-emblem {
        width: 26px;
    }
}

.cart-page__layout {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.cart-lines {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

/* Each line is a single self-contained flex row (photo + body), never a multi-area grid - the
   old 4-area grid ("media info/form/total/remove") is what used to visually collapse when
   content overflowed. min-width: 0 on the body lets long product names/SKUs wrap or truncate
   instead of pushing the row wider than its container; the remove button is absolutely
   positioned but only relative to *this* row (position: relative below), so it can never bleed
   past it into the footer. */
.cart-line {
    position: relative;
    display: flex;
    gap: var(--space-4);
    padding: var(--space-5) 0;
    border-bottom: 1px solid var(--color-border);
}

.cart-line__media {
    flex: 0 0 96px;
    width: 96px;
    aspect-ratio: 4 / 5;
    background: var(--color-bg-soft);
    overflow: hidden;
    border-radius: var(--radius-sm);
}

.cart-line__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.cart-line__body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding-right: var(--space-7);
}

.cart-line__name {
    display: block;
    font-family: var(--font-heading);
    font-weight: 600;
}

.cart-line__unit-price,
.cart-line__variant,
.cart-line__sku {
    color: var(--color-text-muted);
    font-size: 0.85rem;
}

.cart-line__footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: var(--space-2);
}

.cart-line__total {
    font-weight: 700;
    color: var(--color-accent-dark);
}

.cart-remove-form {
    position: absolute;
    top: var(--space-4);
    right: 0;
}

.cart-line__remove {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    color: var(--color-text-muted);
    font-size: 1rem;
    line-height: 1;
}

.cart-line__remove:hover {
    color: var(--color-danger);
    background: var(--color-bg-soft);
}

/* Панель «Ваш заказ» (и та же панель в корзине). Раньше красилась общим мягким фоном, и
   после перевода страницы на тёплую бумагу разница между ними осталась в пять единиц —
   владелица справедливо сказала, что панель «сливается практически». Общий токен трогать
   нельзя: им же залиты подложки фотографий товара и состояния наведения, там усиление тона
   выглядело бы грязью. Поэтому панель получает собственный, чуть более бежевый тон и
   волосяную рамку: разница с бумагой становится втрое заметнее, а тон остаётся из того же
   семейства (оттенок 52° против 53° у страницы). */
.cart-summary {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--space-5);
    /* Панель ТЕМНЕЕ страницы — ровно та же логика, что работала на белом фоне: там панель
       была на 13 пунктов темнее белого, здесь на 12 пунктов темнее бумаги. Светлее страницы
       пробовали — разницу в полтона глаз почти не ловит, и панель приходилось держать рамкой.

       РАЗДЕЛЯЕМ ГЛУБИНОЙ, А НЕ ЦВЕТОМ. Тон этой панели перебирали пять раз, и каждый провал
       был поучительным: беж совпадал с шапкой; светлее бумаги на полтона — не читалось;
       темнее и теплее — владелица назвала розовым; холодный серо-голубой — «ужасно», и это
       справедливо: замер её же скриншота показал панель на R−B −7 посреди страницы на +12.
       Два разных света в одном кадре, ровно то, от чего дешевеет любая вёрстка.

       Вывод: пока панель отличается ОТТЕНКОМ, она обязана либо спорить с шапкой, либо ломать
       температуру, либо уезжать в розовое на тёплой белой точке экрана. Поэтому она больше не
       отличается оттенком вовсе — она того же тёплого семейства, что и карточки товара, и
       поднята над листом тенью. Отделяет не цвет, а глубина: цвета, который мог бы уехать в
       розовое, в панели просто нет.

       Тень тёплая (коричнево-серая, не чёрная) — чёрная на кремовом даёт грязный ореол. */
    /* ФИРМЕННАЯ МЕШЕВАЯ ЗАЛИВКА — та же, что в подвале, теми же двумя цветами марки:
       сливочный беж #E5E3C5 и голубой #A8BAC6, четырьмя мягкими пятнами по углам.

       Отличие одно — плотность. В подвале пятна стоят на 0.72–0.98, там нет мелкого текста
       и это можно. Здесь мелкого текста много (артикул, «80–86 · голубой», условие
       бесплатной доставки), а контраст меряется по САМОЙ ТЁМНОЙ точке заливки, не по
       средней. Плотность подобрана замером реальных пикселей панели: при этих значениях
       самая тёмная точка держит норму 4.5 для приглушённого текста.

       Прямого перехода «беж → голубой» тут нет, и это важно. Линейный градиент между ними
       прошёл бы через точку, где красный и синий меняются местами, — грязная нейтральная
       середина, из-за которой началась вся история с розовым. Мешевая раскладка ставит
       цвета в РАЗНЫЕ углы и гасит каждый в прозрачность, поэтому середина остаётся светлой
       основой, а не смесью двух противоположных температур. */
    background-color: var(--color-surface);
    background-image:
        radial-gradient(90% 110% at 6% 8%, rgba(229, 227, 197, 0.55), rgba(229, 227, 197, 0) 58%),
        radial-gradient(85% 110% at 94% 92%, rgba(229, 227, 197, 0.45), rgba(229, 227, 197, 0) 55%),
        radial-gradient(110% 120% at 62% 40%, rgba(168, 186, 198, 0.30), rgba(168, 186, 198, 0) 62%),
        radial-gradient(70% 90% at 88% 14%, rgba(168, 186, 198, 0.22), rgba(168, 186, 198, 0) 58%);
    border: 1px solid #EAE9DE;
    border-radius: var(--radius-md);
    box-shadow: 0 1px 2px rgba(92, 88, 62, 0.05), 0 14px 32px -18px rgba(92, 88, 62, 0.28);
    /* Поля внутри панели НИЧЕМ не отличаются от полей на остальном сайте — иначе получается
       ровно то, что владелица поймала: я топила поле промокода на полтона, чтобы оно читалось
       на светлой панели, и завела единственное серое поле на весь магазин. ФИО, телефон,
       почта светлые, а промокод серый — он и бросался в глаза, хотя задача была обратная.
       Теперь его держит рамка, как и все прочие поля. Переопределена только подсветка «−/+»:
       на панели она должна быть чуть заметнее, чем была бы на бумаге. */
    --color-bg-soft: #EDEDE2;
    /* Мелкий текст темнее обычного — это и есть плата за видимый градиент. На общем #62727F
       низ панели пришлось бы держать на #F6F6EC, где перепада не видно; на #556370 низ
       уходит до #E7E7DE и градиент читается, а контраст даже растёт: 4.96 против 4.56. */
    --color-text-muted: #556370;
}

.cart-summary__promo {
    width: 100%;
    padding-bottom: var(--space-4);
    border-bottom: 1px solid var(--color-border);
}

.cart-promo-form__label {
    display: block;
    margin-bottom: var(--space-2);
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.cart-promo-form__row {
    display: flex;
}

.cart-promo-form__input {
    flex: 1 1 auto;
    min-width: 0;
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-border);
    border-right: none;
    border-radius: var(--radius-sm) 0 0 var(--radius-sm);
    background: var(--color-surface);
}

.cart-promo-form__submit {
    flex: 0 0 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-eerie-black);
    color: var(--color-white);
    font-size: 1.3rem;
    line-height: 1;
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    transition: background-color 0.15s ease;
}

.cart-promo-form__submit:hover {
    background: var(--color-accent-dark);
}

/* Applied-promo state (cart-summary__promo swaps the input form for this once a code is
   accepted) - a soft blue pill echoing the header badge accent, plus a plain-text "remove" link
   styled as a button so it never looks like a second primary action next to "Оформить заказ". */
.cart-promo-applied {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-tint-blue);
    border-radius: var(--radius-sm);
}

.cart-promo-applied__text {
    font-size: 0.9rem;
}

.cart-promo-applied__remove {
    font-size: 0.8rem;
    text-decoration: underline;
    color: var(--color-text-muted);
    white-space: nowrap;
}

.cart-promo-applied__remove:hover {
    color: var(--color-danger);
}

.cart-summary__subtotal {
    font-family: var(--font-heading);
    font-size: 1.2rem;
    font-weight: 600;
}

.cart-summary__checkout {
    width: 100%;
    margin-top: var(--space-2);
}

.cart-summary__continue {
    align-self: center;
    font-size: 0.9rem;
    color: var(--color-text-muted);
    text-decoration: underline;
}

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

/* --------------------------------------------------------------------------
   Checkout (Task 10): contact/address/delivery/payment form + order summary
   sidebar, and the post-order confirmation page. Reuses .cart-summary/
   .cart-flash for the sidebar/flash-message look rather than redefining them.
   -------------------------------------------------------------------------- */

.checkout-page__title {
    /* Тот же лёгкий заголовок, что на «Избранном» и в «Каталоге» (там font-weight 400 + лёгкая
       отрицательная разрядка) — жирное начертание по умолчанию выбивалось из остальных страниц. */
    font-weight: 400;
    letter-spacing: -0.01em;
    margin-top: var(--space-5); /* чуть опускаем от шапки (веб и моб), чтобы не липло к верхней границе */
    margin-bottom: var(--space-7); /* «Контактные данные» ниже — больше воздуха под заголовком */
}

.checkout-page__layout {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    align-items: start;
}

.checkout-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.checkout-form__section {
    border: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.checkout-form__section legend {
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 1.05rem;
    margin-bottom: var(--space-2);
    padding: 0;
}

.checkout-form__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.checkout-form__row .field {
    flex: 1 1 140px;
}

.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Подписи полей стояли на том же приглушённом тоне, что и пояснения под ними, и сливались с
   ними в одну серую массу — владелица заметила это на форме возврата, но касается всех форм
   сайта. Теперь у подписи свой вес: она темнее пояснения (контраст 6.83 против 4.65) и чуть
   плотнее начертанием. Пояснения намеренно остаются прежними — иначе исчезнет сама разница
   между «что заполнить» и «как заполнить». */
.field__label {
    font-size: 0.9rem;
    font-weight: 500;
    color: #4A5866;
}

.field__input {
    width: 100%;
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    font-family: var(--font-body);
}

.field__input:focus {
    outline: 2px solid var(--color-accent-dark);
    outline-offset: 1px;
}

.field__error {
    color: var(--color-danger);
    font-size: 0.85rem;
}

/* City prefix autocomplete (custom, replaces the native datalist which matched substrings). */
.city-autocomplete {
    position: relative;
}

.city-autocomplete__list {
    position: absolute;
    top: calc(100% + 2px);
    left: 0;
    right: 0;
    z-index: 25;
    margin: 0;
    padding: var(--space-1);
    list-style: none;
    max-height: 260px;
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    box-shadow: 0 14px 34px rgba(30, 30, 30, 0.14);
}

.city-autocomplete__list[hidden] {
    display: none;
}

.city-autocomplete__item {
    display: block;
    width: 100%;
    padding: var(--space-2) var(--space-3);
    text-align: left;
    background: transparent;
    border-radius: var(--radius-sm);
    font-size: 0.95rem;
    color: var(--color-text);
    cursor: pointer;
}

.city-autocomplete__item:hover {
    background: var(--color-bg-soft);
}

/* Client-side "required field is empty" highlight on submit (checkout.js) - a clear red. */
.field__input--invalid {
    border-color: #E0393B;
    box-shadow: 0 0 0 1px #E0393B;
    background: #FDF3F3;
}

.field__input--invalid:focus {
    outline-color: #E0393B;
}

.checkout-radio-group.is-invalid,
.checkout-checkbox.is-invalid,
.checkout-pickup.is-invalid {
    outline: 2px solid #E0393B;
    outline-offset: 4px;
    border-radius: var(--radius-sm);
}

.checkout-radio-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Способ доставки как кликабельная карточка-кнопка (вместо радио-кружка): вся плашка выделяется. */
.checkout-radio {
    display: block;
    position: relative;
    padding: var(--space-3) var(--space-4);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md, 12px);
    background: var(--color-surface);
    cursor: pointer;
    font-size: 0.95rem;
    transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
}

/* Спрятать нативный кружок — выбор показываем самой карточкой. */
.checkout-radio input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    margin: 0;
}

.checkout-radio:hover {
    border-color: var(--color-accent-dark, #b06a4f);
}

/* Выбранная карточка. :has() поддерживается всеми актуальными браузерами; если нет —
   карточка всё равно кликается (label), просто без подсветки. */
.checkout-radio:has(input[type="radio"]:checked) {
    border-color: var(--color-accent-dark, #b06a4f);
    background: var(--color-bg-muted, #f7f4f0);
    box-shadow: inset 0 0 0 1px var(--color-accent-dark, #b06a4f);
}

/* Галочка в углу выбранной карточки. */
.checkout-radio:has(input[type="radio"]:checked)::after {
    content: "✓";
    position: absolute;
    top: var(--space-3);
    right: var(--space-4);
    color: var(--color-accent-dark, #b06a4f);
    font-weight: 700;
}

.checkout-radio:has(input[type="radio"]:focus-visible) {
    outline: 2px solid var(--color-accent-dark, #b06a4f);
    outline-offset: 2px;
}

.checkout-radio__demo-note {
    display: block;
    font-style: normal;
    color: var(--color-text-muted);
    font-size: 0.8rem;
}

/* Small grey caption under the "Яндекс Доставка" option (what its ПВЗ network covers). */
.checkout-radio__hint {
    display: block;
    color: var(--color-text-muted);
    font-size: 0.8rem;
    margin-top: 2px;
}

/* Courier address block (shown only for "СДЭК — курьер до двери"). */
.checkout-courier {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* A class-selector `display:flex` outranks the bare `[hidden]` UA rule, so without these the
   pickup/courier blocks would stay visible even when checkout.js sets their `hidden` attribute
   (they're mutually exclusive per the chosen delivery option). Attribute+class wins it back. */
.checkout-pickup[hidden],
.checkout-courier[hidden] {
    display: none;
}

.checkout-courier__row {
    display: grid;
    grid-template-columns: 2fr 1fr 1.4fr;
    gap: var(--space-3);
}

/* Адрес курьера в две строки:
   1) улица (шире) + дом + корпус/строение + подъезд;
   2) кв./офис + домофон + этаж + индекс (одинаковые). */
.checkout-courier__line {
    display: grid;
    gap: var(--space-3);
}

.checkout-courier__line--1 {
    grid-template-columns: 2fr 1fr 1.3fr 1fr;
}

.checkout-courier__line--2 {
    grid-template-columns: 1fr 1fr 1fr 1fr;
}

@media (max-width: 767px) {
    .checkout-courier__row {
        grid-template-columns: 1fr;
    }
    /* На телефоне — по 2 ячейки в ряд, чтобы всё поместилось. */
    .checkout-courier__line--1,
    .checkout-courier__line--2 {
        grid-template-columns: 1fr 1fr;
    }
}

/* Wider modal + sized container for the СДЭК pickup-point map widget (its docs require an explicit
   height, else the map collapses to 0). */
.modal__panel--wide {
    max-width: 760px;
    width: min(92vw, 760px);
}

.checkout-pickup-map {
    position: relative;
    width: 100%;
    height: 48vh;
    min-height: 320px;
    margin-top: var(--space-3);
    margin-bottom: var(--space-3);
    border-radius: var(--radius-md, 12px);
    overflow: hidden;
    background: var(--color-bg-muted, #f2efe9);
}

/* Balloon «Выбрать этот пункт» button (ymaps renders balloon HTML inside the map container). */
.checkout-pickup-map__pick {
    /* Во всю ширину карточки: это главное действие в балуне, и на телефоне узкая кнопка рядом с
       текстом читалась как ссылка, а не как «нажми сюда». */
    display: block;
    width: 100%;
    margin: 8px 0 4px;
    padding: 9px 12px;
    border: none;
    border-radius: var(--radius-sm, 8px);
    background: var(--color-accent-dark, #b06a4f);
    color: #fff;
    font-family: var(--font-body);
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
}

/* Loading overlay with a delivery truck driving across while points load. */
.checkout-pickup-map__loader {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-4);
    background: var(--color-bg-muted, #f2efe9);
}

.checkout-pickup-map__loader[hidden] {
    display: none;
}

.checkout-pickup-map__loader-text {
    font-size: 0.9rem;
    color: var(--color-text-muted);
}

/* The truck: a full-colour SVG box van (injected by checkout.js, liveried per carrier) that
   drives left→right across the overlay on a loop. */
.delivery-truck {
    width: 130px;
    height: 78px;
    filter: drop-shadow(0 3px 4px rgba(0, 0, 0, 0.12));
    animation: truck-drive 1.7s ease-in-out infinite;
}

.delivery-truck svg { display: block; width: 100%; height: 100%; }

@keyframes truck-drive {
    0%   { transform: translateX(-46px); }
    50%  { transform: translateX(46px); }
    100% { transform: translateX(-46px); }
}

@media (prefers-reduced-motion: reduce) {
    .delivery-truck { animation: none; }
}

/* Pickup-point balloon (ymaps renders this HTML inside the map container). */
.pickup-balloon__addr {
    font-weight: 600;
    margin-bottom: 6px;
}

.pickup-balloon__row {
    font-size: 0.85rem;
    margin-top: 3px;
}

.pickup-balloon__row--ok { color: #1a7f37; }
.pickup-balloon__row--muted { color: var(--color-text-muted); }

/* Комментарий пункта («как пройти») бывает на целый абзац — обрезаем до трёх строк, иначе карточка
   перестаёт помещаться на экран телефона и выглядит сломанной. */
.pickup-balloon__row--clamp {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.pickup-balloon__op { font-weight: 600; }
.pickup-balloon__tel {
    color: var(--color-accent-dark, #b06a4f);
    text-decoration: underline;
    white-space: nowrap;
}

/* "Сначала укажите город" hint + the delivery radios locked until a city is entered. */
.checkout-city-required {
    font-size: 0.9rem;
    color: #B24A2E;
    margin-bottom: var(--space-2);
}

.checkout-radio-group--locked {
    opacity: 0.5;
    pointer-events: none;
}

/* Live delivery cost + total in the checkout order summary. */
.checkout-summary__total-row span {
    white-space: nowrap;
}

/* Значение доставки может быть длинным сообщением («Не удалось рассчитать стоимость…») —
   разрешаем перенос и прижимаем вправо, чтобы текст не вылезал за край сводки. Короткая цена
   («238 ₽») всё равно останется одной строкой. */
#summary-delivery {
    text-align: right;
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
}

.checkout-summary__total-row {
    display: flex;
    justify-content: space-between;
    gap: var(--space-4);
    margin-top: var(--space-2);
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-border);
    font-family: var(--font-heading);
    font-size: 1.1rem;
    font-weight: 600;
}

.checkout-summary__delivery {
    display: flex;
    justify-content: space-between;
    gap: var(--space-4);
}

/* Small helper text under an admin field (e.g. weight hint). */
/* --------------------------------------------------------------------------
   Приветственное окно: форма подписки за промокод
   -------------------------------------------------------------------------- */

/* Выключка по формату в окне: колонка узкая, и рваный правый край рядом с ровными полем ввода
   и кнопкой выглядел неопрятно. Переносы намеренно выключены — слова рвутся целиком; расплата
   за это чуть более широкие межсловные пробелы в отдельных строках. Ровно то же решение, что
   у вступления в колонке «Контакты» подвала. */
.welcome-modal__text {
    text-align: justify;
}

.welcome-modal__form {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-top: var(--space-4);
}

/* display: flex перебивает атрибут hidden — без этого правила форма оставалась на экране рядом
   с сообщением «спасибо за подписку», и человек не понимал, отправилось у него или нет. */
.welcome-modal__form[hidden] {
    display: none;
}

.welcome-modal__label {
    display: block;
}

.welcome-modal__input {
    width: 100%;
}

/* Галочки мельче основного текста: это условие, а не содержание предложения. Разводим их
   между собой, чтобы на телефоне не слипались в одну строку под палец. */
.welcome-modal__consents {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.welcome-modal__consent {
    font-size: 0.78rem;
    line-height: 1.45;
}

.welcome-modal__submit {
    width: 100%;
}

.welcome-modal__error {
    margin: 0;
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--color-footnote);
}

/* Сообщение об успехе занимает место формы — размер тот же, чтобы окно не прыгало. */
.welcome-modal__done {
    margin: var(--space-4) 0 0;
    font-size: 0.95rem;
    line-height: 1.6;
    color: var(--color-text);
    white-space: pre-line;
}

/* Промокод на странице подтверждения подписки: его копируют глазами и руками, поэтому крупно,
   вразрядку и в рамке-купоне — как в письме. */
/* Скретч-карта с промокодом. Код лежит текстом под холстом: холст только закрашивает его сверху,
   поэтому читалки экрана и поиск по странице видят код всегда. */
.scratch {
    position: relative;
    display: inline-block;
    margin: var(--space-4) 0 var(--space-3);
    border-radius: var(--radius-md);
    /* Скругление обрезает и холст: без этого покрытие торчало бы прямоугольником из-под рамки. */
    overflow: hidden;
}

.scratch .newsletter-confirmed__code {
    margin: 0;
    /* Место справа под значок копирования — иначе он лёг бы на последние буквы кода. */
    padding-right: var(--space-8);
}

/* Значок копирования в правом нижнем углу рамки с кодом. Прозрачный, без собственной рамки:
   он подсказка, а не вторая кнопка рядом с «Смотреть каталог». */
.scratch__copy {
    position: absolute;
    right: 8px;
    bottom: 6px;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 6px;
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--color-text-muted);
    cursor: pointer;
    line-height: 0;
}
.scratch__copy:hover { color: var(--color-payne-gray); background: var(--color-bg-soft); }
.scratch__copy:focus-visible { outline: 2px solid var(--color-payne-gray); outline-offset: 2px; }

.scratch__cover {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* grab/grabbing: курсор объясняет, что покрытие можно тереть, без единого слова подписи. */
    cursor: grab;
    /* Без этого страница на телефоне прокручивается вместо стирания. */
    touch-action: none;
    transition: opacity 0.35s ease;
}

.scratch__cover:active {
    cursor: grabbing;
}

/* Стёрли достаточно — остаток снимаем плавно, чтобы не оставлять лохмотья. */
.scratch--revealed .scratch__cover {
    opacity: 0;
    pointer-events: none;
}

.newsletter-confirmed__hint {
    font-size: 0.88rem;
    color: var(--color-text-muted);
}

@media (prefers-reduced-motion: reduce) {
    .scratch__cover {
        transition: none;
    }
}

.newsletter-confirmed__copied {
    margin: var(--space-2) 0 0;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.newsletter-confirmed__code {
    display: inline-block;
    margin: var(--space-4) 0 var(--space-3);
    padding: var(--space-3) var(--space-5);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius-md);
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    color: var(--color-text);
}

/* Пояснение под вещью, которую можно вернуть, но не обменять/* Пояснение под вещью, которую можно вернуть, но не обменять (бельё, чулочно-носочные). */
/*
  Красная часть строки «заказ найден»: сообщение о том, что срок прошёл. Цвет не общий
  --color-danger: он у нас глубокий бордовый, на светлом фоне читается как обычный тёмный текст
  и не тревожит. Здесь нужен именно сигнал, поэтому взят кирпичный #B24A2E — тот же, которым
  светится «Промокод не найден» и метка брака в админке.
*/
.return-status__alert {
    color: #B24A2E;
    font-weight: 500;
}

/* Выбор из нескольких заказов на одни и те же контакты. */
.return-choices { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }
.return-choices[hidden] { display: none; }
.return-choice {
    flex: 1 1 14rem;
    /* Номер и дата по центру карточки: в ней всего две короткие строки, и прижатые к левому краю
       они выглядели остатком текста, а не кнопкой выбора. */
    text-align: center;
    padding: var(--space-3);
    font: inherit;
    font-size: 0.9rem;
    line-height: 1.45;
    color: var(--color-text);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
}
.return-choice:hover { border-color: var(--color-accent-dark); background: var(--color-bg-soft); }
.return-choice strong { font-weight: 600; }

.return-item__note {
    margin: var(--space-1) 0 0;
    font-size: 0.82rem;
    line-height: 1.5;
    color: var(--color-text-muted);
}

/* Режим брака на заявке: выбор «вернуть деньги / обменять» скрыт — решение принимается после
   осмотра, и спрашивать о нём заранее значит обещать, что выбор учтён. Скрываем целиком, а не
   гасим: погашенный, но видимый выбор человек всё равно пытается нажать. */
.return-items--defect .return-item__choice {
    display: none;
}


/* Подсказка под полем промокода в корзине: объясняет, почему «первый заказ» проверяется позже. */
.cart-promo-form__hint {
    margin: var(--space-2) 0 0;
    font-size: 0.78rem;
    line-height: 1.5;
    color: var(--color-text-muted);
}

.field__hint {
    display: block;
    margin-top: 4px;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}
/* Собственный `display` перебивает браузерное правило для атрибута hidden, и подсказка,
   спрятанная скриптом, оставалась на экране. Так на заявке возврата абзац про брак («пришлите
   фотографии в ответ на письмо») висел под любой причиной — даже под «Не подошёл размер».
   Правило нужно каждому классу, который задаёт свой display и при этом прячется атрибутом. */
.field__hint[hidden] { display: none; }

/* Срок доставки — под выбором пункта/способа. */
.checkout-delivery-term {
    margin-top: var(--space-2);
    font-size: 0.9rem;
    font-weight: 500;
}

.checkout-delivery-term[hidden] { display: none; }

/* Ввод промокода в блоке заказа на странице оформления. */
.checkout-promo {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
}

.checkout-promo__entry {
    display: flex;
    gap: var(--space-2);
}

.checkout-promo__entry .field__input { flex: 1 1 auto; min-width: 0; }

/* Подпись над полем купона (как у Lumnits). */
.checkout-promo__label {
    display: block;
    font-size: 0.85rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-2);
}

/* «Осталось добрать до бесплатной доставки» под итогами. */
.checkout-summary__freeship {
    margin-top: var(--space-1);
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--color-text-muted);
}

.checkout-summary__freeship strong {
    color: var(--color-accent-dark, #b06a4f);
    white-space: nowrap;
}

/* Срок доставки в сводке «Ваш заказ» — мелкой строкой справа под ценой доставки. */
.checkout-summary__term {
    margin-top: -4px;
    text-align: right;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.checkout-summary__term[hidden] { display: none; }

/* Кирпичная подсказка «заполните поле» под городом (клиентская валидация). */
.checkout-city-error {
    color: #B24A2E;
    font-size: 0.85rem;
    margin-top: 2px;
}

.checkout-city-error[hidden] { display: none; }

/* Телефон с выбором кода страны (флаг + код слева, номер справа). */
.phone-input {
    position: relative;
    display: flex;
    align-items: stretch;
}
.phone-input__country {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 0 10px;
    border: 1px solid var(--color-border);
    border-right: none;
    background: var(--color-bg-soft);
    cursor: pointer;
    white-space: nowrap;
}
.phone-input__number {
    flex: 1;
    min-width: 0;
}
.phone-input__flag { font-size: 1.15rem; line-height: 1; }
.phone-input__code { font-size: 0.9rem; }
.phone-input__caret { font-size: 0.65rem; color: var(--color-text-muted); }
.phone-input__list {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 40;
    margin: 4px 0 0;
    padding: 4px;
    list-style: none;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    box-shadow: 0 8px 24px rgba(30, 30, 30, 0.14);
    max-height: 264px;
    overflow-y: auto;
    min-width: 240px;
    max-width: 88vw;
}
.phone-input__list[hidden] { display: none; }
/* Список стран живёт и на «Покупателям» (заявка на возврат), где у .legal-page__section ul стоит
   `list-style: disc` — а это селектор класса С ТЕГОМ, он весомее одного класса, и у каждой страны
   появлялась точка-маркер. Два класса перебивают его обратно. */
.phone-input .phone-input__list { list-style: none; padding-left: 4px; }
.phone-input__item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    text-align: left;
    cursor: pointer;
    font-size: 0.9rem;
    background: none;
    border: none;
}
.phone-input__item:hover { background: var(--color-bg-soft); }
.phone-input__cname { flex: 1; }
.phone-input__ccode { color: var(--color-text-muted); }

/* Раскупленные позиции: подсветка строки корзины/сводки, кирпичный бейдж «Нет в наличии» и
   ссылка «выбрать другой размер». Товар мог раскупиться, пока лежал в корзине — наличие берётся
   свежим при каждой загрузке, тут мы его показываем. */
.cart-line--unavailable,
.checkout-summary__line--unavailable {
    opacity: 0.85;
}
.cart-line__stock-badge,
.checkout-summary__stock-badge {
    display: inline-block;
    color: #B24A2E;
    font-weight: 600;
    font-size: 0.85rem;
    margin: 4px 0 2px;
}
.cart-line__pick-size,
.checkout-summary__pick-size {
    display: inline-block;
    color: #B24A2E;
    font-size: 0.85rem;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.cart-line__pick-size:hover,
.checkout-summary__pick-size:hover { text-decoration: none; }
.cart-summary__stock-note {
    color: #B24A2E;
    font-size: 0.85rem;
    margin-top: 8px;
    line-height: 1.4;
}
.cart-summary__stock-note a { color: #B24A2E; text-decoration: underline; }
.cart-summary__checkout[disabled],
.checkout-summary__submit[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
}

/* «Промокод применён» — аккуратная зелёная плашка с галочкой, а не голый текст со ссылкой.
   Переносится и сжимается, чтобы длинный код не вылезал за рамку узкой сводки. */
.checkout-promo__applied {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    font-size: 0.85rem;
    padding: var(--space-3);
    background: #F1F7F1;
    border: 1px solid #CFE6CF;
    border-radius: var(--radius-md, 12px);
    color: #1a7f37;
}

.checkout-promo__applied strong { color: inherit; word-break: break-word; }

.checkout-promo__applied-text {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 8px;
    flex: 1 1 auto;
    min-width: 0;
}

.checkout-promo__check {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    border-radius: 50%;
    background: #1a7f37;
    color: #fff;
    font-size: 0.7rem;
    line-height: 1;
}

.checkout-promo__remove {
    background: none;
    border: none;
    color: var(--color-text-muted);
    text-decoration: underline;
    cursor: pointer;
    font-size: 0.8rem;
    padding: 0;
    margin-left: auto;
    white-space: nowrap;
}

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

.checkout-promo__msg {
    font-size: 0.85rem;
    margin-bottom: var(--space-2);
}

.checkout-promo__msg--ok { color: #1a7f37; }
.checkout-promo__msg--err { color: #b42318; }

.checkout-pickup-modal__search {
    margin-bottom: var(--space-3);
}

.checkout-confirmation__payment {
    margin-top: var(--space-2);
    font-weight: 600;
}

.checkout-confirmation__payment--paid {
    color: #1a7f37;
}

.checkout-confirmation__payment--failed {
    color: #b42318;
    font-weight: 500;
}

.checkout-confirmation__payment--pending {
    color: #8a6d00;
    font-weight: 500;
}

.checkout-confirmation__pay-again {
    display: inline-block;
    margin-top: var(--space-3);
}

/* СБП payment page (checkout/sbp.html): a searchable bank list (tap → bank app) + a QR for desktop. */
.checkout-sbp {
    padding-block: var(--space-7);
    max-width: 620px;
}

.checkout-sbp__lead {
    margin-bottom: var(--space-2);
}

.checkout-sbp__status {
    margin-bottom: var(--space-5);
    font-weight: 600;
    color: var(--color-accent-dark);
}

.checkout-sbp__banks-label {
    margin-bottom: var(--space-3);
}

.checkout-sbp__search {
    margin-bottom: var(--space-3);
}

.checkout-sbp__banks {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 58vh;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: 12px;
}

.checkout-sbp__bank + .checkout-sbp__bank {
    border-top: 1px solid var(--color-border);
}

.checkout-sbp__bank-link {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    color: var(--color-text);
    text-decoration: none;
}

.checkout-sbp__bank-link:hover {
    background: var(--color-bg-soft);
}

.checkout-sbp__bank-logo {
    width: 32px;
    height: 32px;
    flex: 0 0 auto;
    object-fit: contain;
    border-radius: 6px;
}

.checkout-sbp__qr-block {
    margin-top: var(--space-5);
}

.checkout-sbp__qr-block summary {
    cursor: pointer;
    font-weight: 600;
    color: var(--color-accent-dark);
}

.checkout-sbp__qr {
    width: 240px;
    margin-top: var(--space-3);
}

.checkout-sbp__qr svg {
    display: block;
    width: 100%;
    height: auto;
}

/* Payment-method page (checkout/pay-methods.html): СБП big at top, card small at the bottom. */
.checkout-pay {
    padding-block: var(--space-7);
    max-width: 560px;
}

.checkout-pay__lead {
    margin-bottom: var(--space-5);
}

.checkout-pay__methods {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.checkout-pay__method {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: var(--space-4) var(--space-5);
    border: 1px solid var(--color-border);
    border-radius: 14px;
    text-decoration: none;
    color: var(--color-text);
    transition: border-color 0.15s ease, background 0.15s ease;
}

.checkout-pay__method:hover {
    border-color: var(--color-accent-dark);
}

.checkout-pay__method-title {
    font-weight: 600;
    font-size: 1.1rem;
}

.checkout-pay__method-note {
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

.checkout-pay__method--sbp {
    padding: var(--space-5);
    background: var(--color-accent-dark);
    border-color: var(--color-accent-dark);
    color: var(--color-white);
}

.checkout-pay__method--sbp .checkout-pay__method-title {
    font-size: 1.45rem;
}

.checkout-pay__method--sbp .checkout-pay__method-note {
    color: rgba(255, 255, 255, 0.85);
}

.checkout-pay__method--card {
    opacity: 0.85;
}

.checkout-pickup-map[hidden] {
    display: none;
}

/* --------------------------------------------------------------------------
   "Адрес и способ доставки" pickup/courier sub-sections + the mock
   pickup-point picker (checkout/checkout.html, static/js/checkout.js).
   -------------------------------------------------------------------------- */

.checkout-pickup {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
}

/* Выбранный пункт в рамке-чипе с крестиком «сбросить» справа. */
.checkout-pickup__chosen-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    align-self: stretch;
    padding: var(--space-2) var(--space-3);
    background: var(--color-bg-muted, #f7f4f0);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md, 12px);
}

.checkout-pickup__chosen-row[hidden] { display: none; }

.checkout-pickup__chosen {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    font-size: 0.9rem;
    color: var(--color-text);
}

.checkout-pickup__clear {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--color-text-muted);
    font-size: 1.35rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.checkout-pickup__clear:hover {
    background: rgba(0, 0, 0, 0.07);
    color: var(--color-text);
}

/* Ссылка «Выбрать/Изменить пункт выдачи» — не большая кнопка, а скромная ссылка: карта
   и так открывается сразу при выборе ПВЗ, эта ссылка нужна лишь чтобы переоткрыть её. */
.checkout-pickup__reopen {
    align-self: flex-start;
    background: none;
    border: none;
    padding: 0;
    color: var(--color-accent-dark, #b06a4f);
    font-family: var(--font-body);
    font-size: 0.9rem;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.checkout-pickup__reopen:hover {
    opacity: 0.8;
}

.checkout-pickup__reopen:disabled {
    color: var(--color-text-muted);
    text-decoration: none;
    cursor: default;
}

.checkout-courier-fields {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.checkout-pickup-modal__note {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-4);
}

.checkout-pickup-modal__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.checkout-pickup-modal__point {
    display: flex;
    flex-direction: column;
    gap: 3px;
    width: 100%;
    text-align: left;
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    font-family: var(--font-body);
    font-size: 0.9rem;
    cursor: pointer;
}

.checkout-pickup-modal__point:hover,
.checkout-pickup-modal__point:focus-visible {
    border-color: var(--color-accent-dark);
    background: var(--color-bg-muted, #f7f4f0);
}

.checkout-pickup-modal__point-addr {
    font-weight: 600;
    color: var(--color-text);
}

.checkout-pickup-modal__point-op {
    font-size: 0.8rem;
    color: var(--color-accent-dark, #b06a4f);
}

.checkout-pickup-modal__point-row {
    font-size: 0.82rem;
    color: var(--color-text-muted);
}

.checkout-pickup-modal__point-row--ok {
    color: #1a7f37;
}

/* --- Мобильная версия выбора ПВЗ ------------------------------------------------------------
   Раньше на телефоне карта занимала пол-экрана, а карточки пунктов уходили далеко вниз, и всю
   модалку приходилось листать. Теперь модалка — почти на весь экран: сверху компактная карта и
   поиск, а СПИСОК пунктов прокручивается сам по себе (как у loomknits), с полной инфой в каждой
   карточке (адрес, часы, примерочная, срок) — не нужно ловить балун на карте. */
@media (max-width: 600px) {
    /* ТОЛЬКО «шторка» выбора ПВЗ (.modal--sheet на #pickup-point-modal). Раньше это правило
       висело на всех .modal сразу, и на телефоне ко дну прижимались ВСЕ окна — в том числе
       приветственное с промокодом, которое должно стоять по центру. */
    .modal--sheet {
        padding: var(--space-2);
        align-items: flex-end; /* модалка-«шторка» снизу — удобнее большим пальцем */
    }

    .modal__panel--wide {
        width: 100%;
        max-width: 100%;
        max-height: 94vh;
        max-height: 94dvh;
        padding: var(--space-4);
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }

    .modal__panel--wide h2 {
        margin-bottom: var(--space-2);
        font-size: 1.1rem;
    }

    .checkout-pickup-map {
        flex: 0 0 auto;
        height: 30vh;
        min-height: 160px;
        margin-top: var(--space-2);
        margin-bottom: var(--space-2);
    }

    .checkout-pickup-modal__search {
        flex: 0 0 auto;
    }

    /* Единственная прокручиваемая часть — список пунктов. */
    .checkout-pickup-modal__list {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }

    /* На телефоне «Контактные данные» тоже с воздухом под заголовком «Оформление заказа». */
    .checkout-page__title {
        margin-bottom: var(--space-6);
    }
}

/* Согласия checkboxes (acceptedTerms/marketingConsent) below the order comment. */
.checkout-checkbox {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    font-size: 0.9rem;
}

.checkout-checkbox input[type="checkbox"] {
    margin-top: 0.2em;
    flex: none;
}

.checkout-checkbox a {
    text-decoration: underline;
}

.checkout-summary__title {
    font-family: var(--font-heading);
    font-size: 1.1rem;
    font-weight: 600;
}

.checkout-summary__lines {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    width: 100%;
}

/* Строка товара: иконка слева, текст начинается с ВЕРХА иконки (как в корзине loomknits),
   ниже — степпер количества и цена; крестик «убрать» справа сверху. */
.checkout-summary__line {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    font-size: 0.9rem;
}

.checkout-summary__thumb {
    width: 84px;
    height: 108px;
    flex: 0 0 auto;
    object-fit: cover;
    border-radius: 8px;
}

.checkout-summary__line-sku {
    font-size: 0.72rem;
    color: var(--color-text-muted);
}

.checkout-summary__line-main {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    flex: 1 1 auto;
    min-width: 0;
}

.checkout-summary__line-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.checkout-summary__line-name {
    min-width: 0;
    line-height: 1.25;
}

.checkout-summary__line-variant {
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.checkout-summary__line-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}

.checkout-summary__qty {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    overflow: hidden;
}

.checkout-summary__qty-btn {
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    color: var(--color-text);
    font-size: 0.95rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.checkout-summary__qty-btn:hover { background: var(--color-bg-muted, #f7f4f0); }
.checkout-summary__qty-btn:disabled { color: var(--color-text-muted); cursor: default; }

.checkout-summary__qty-val {
    min-width: 22px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.checkout-summary__line-price {
    flex: 0 0 auto;
    white-space: nowrap;
    font-weight: 600;
}

.checkout-summary__line-remove {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    font-size: 0.9rem;
    line-height: 1;
    border-radius: 50%;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.checkout-summary__line-remove:hover { background: rgba(0, 0, 0, 0.06); color: var(--color-text); }

/* Сводка заказа на телефоне: иконка чуть меньше, элементы управления не вылезают за край. */
@media (max-width: 600px) {
    .checkout-summary__thumb {
        width: 56px;
        height: 70px;
    }
    .checkout-summary__line-controls {
        flex-wrap: wrap;
        row-gap: var(--space-1);
    }
    .checkout-summary__qty-btn {
        width: 32px;
        height: 32px;
    }
}

.checkout-summary__note {
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.checkout-summary__submit,
.checkout-summary__total {
    width: 100%;
}

.checkout-summary__total {
    font-size: 1.3rem;
}

/* Order-summary rows on the confirmation page: label left, amount right, amount never wraps so a
   large total always fits the box. */
.checkout-summary__totals {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.checkout-summary__row {
    display: flex;
    justify-content: space-between;
    gap: var(--space-4);
    width: 100%;
    margin: 0;
    font-family: var(--font-heading);
    font-size: 1.02rem;
    font-weight: 500;
}

.checkout-summary__row > span:last-child {
    white-space: nowrap;
}

.checkout-summary__row.checkout-summary__total {
    font-size: 1.3rem;
    font-weight: 700;
    border-top: 1px solid var(--color-border);
    padding-top: var(--space-3);
    margin-top: var(--space-1);
}

.checkout-summary__line > span:first-child {
    min-width: 0;
}

.checkout-summary__line > span:last-child {
    white-space: nowrap;
}

.checkout-confirmation__label {
    font-weight: 600;
    margin-top: var(--space-3);
}

.checkout-confirmation {
    position: relative;
    isolation: isolate;
    padding-block: var(--space-6);
}

.checkout-confirmation__title {
    margin-bottom: var(--space-3);
}

.checkout-confirmation__lede {
    font-size: 1.15rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-5);
    max-width: 35rem;
}

.checkout-confirmation__number,
.checkout-confirmation__next {
    margin-bottom: var(--space-4);
    max-width: 40rem;
}

/* Короткая страница «спасибо»: без блоков с деталями она получается совсем невысокой, поэтому
   даём ей воздух сверху/снизу, чтобы заголовок не липнул к шапке и к подвалу.

   ВЫКЛЮЧКА ПО ЦЕНТРУ — решение владелицы. Слева страница выглядела обрывком большой вёрстки:
   три коротких строки и две кнопки жались к левому краю, а справа зияла пустота во весь экран.
   Центр собирает их в одно сообщение — это единственное, ради чего страница существует. */
.checkout-confirmation--short {
    /* Только существующие ступени шкалы: --space-9 в ней нет, и одна такая переменная делает
       ВСЁ объявление невалидным — padding-block молча схлопывался в ноль, заголовок прижимался
       к шапке. */
    padding-block: var(--space-8);
    text-align: center;
}

/* max-width у строк остаётся (длинная строка нечитаема), но при выключке по центру его надо
   центрировать самим — иначе блок текста прижмётся влево внутри центрированной секции. */
.checkout-confirmation--short .checkout-confirmation__lede,
.checkout-confirmation--short .checkout-confirmation__number,
.checkout-confirmation--short .checkout-confirmation__next {
    margin-inline: auto;
    /* Строки делятся поровну, а не «как получится»: без этого вторая строка обрывалась одним
       словом («почту») под длинной первой — на центрированном тексте это особенно заметно. */
    text-wrap: balance;
}

.checkout-confirmation--short .checkout-confirmation__actions {
    justify-content: center;
}

.checkout-confirmation__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-6);
}

.checkout-confirmation__layout {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    margin-bottom: var(--space-6);
}

.checkout-confirmation__details {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.checkout-confirmation__details h2 {
    font-family: var(--font-heading);
    font-size: 1.05rem;
    font-weight: 600;
    margin-top: var(--space-4);
}

/* --------------------------------------------------------------------------
   Login / registration (Task 11). A single centered card, reusing .field/
   .field__input/.field__error/.btn from the checkout form rather than
   redefining input styling a third time.
   -------------------------------------------------------------------------- */

.auth-page {
    display: flex;
    justify-content: center;
    padding: var(--space-8) var(--space-4);
}

.auth-card {
    width: 100%;
    max-width: 420px;
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    padding: var(--space-6);
    background: var(--color-bg-soft);
    border-radius: var(--radius-md);
}

.auth-card__title {
    margin: 0;
}

.auth-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.auth-form__submit {
    margin-top: var(--space-2);
}

.auth-card__footer {
    margin: 0;
    font-size: 0.9rem;
    color: var(--color-text-muted);
    text-align: center;
}

/* --------------------------------------------------------------------------
   Account area (Task 12): dashboard, order history/detail, saved addresses.
   Reuses .card / .btn / .field / .field__input / .field__error / .cart-flash /
   .cart-summary / .checkout-confirmation__* from earlier tasks rather than
   redefining any of them a second time.
   -------------------------------------------------------------------------- */

.account-page {
    padding-block: var(--space-7);
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.account-page__back {
    font-size: 0.9rem;
}

.account-page__back a {
    color: var(--color-text-muted);
}

.account-page__title {
    margin-bottom: 0;
    /* Same calmer treatment as the catalogue title (.catalog__header h1): Unbounded at its regular
       weight, not the heavy bold 700 the global h1 uses, so it isn't so big/bold. */
    font-weight: 400;
    letter-spacing: -0.01em;
}

.account-page__email {
    color: var(--color-text-muted);
    margin-top: calc(-1 * var(--space-4));
}

.account-page__logout {
    align-self: flex-start;
}

.account-dashboard__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-5);
}

.account-dashboard__card {
    padding: var(--space-6) var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.account-dashboard__card h2 {
    font-family: var(--font-heading);
    font-size: 1.1rem;
    font-weight: 600;
}

.account-dashboard__card p {
    color: var(--color-text-muted);
}

.account-orders-empty {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--space-8) 0;
    color: var(--color-text-muted);
}

.account-order-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.account-order-list__item {
    padding: 0;
}

.account-order-list__link {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-5);
    color: var(--color-text);
}

.account-order-list__number {
    font-family: var(--font-heading);
    font-weight: 600;
}

.account-order-list__status {
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

.account-order-list__total {
    font-weight: 700;
    color: var(--color-accent-dark);
}

.address-list {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-5);
}

.address-card {
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    position: relative;
}

.address-card__label {
    font-family: var(--font-heading);
    font-weight: 600;
}

.address-card__badge {
    position: absolute;
    top: var(--space-4);
    right: var(--space-4);
    background: var(--color-beige);
    color: var(--color-eerie-black);
    font-size: 0.75rem;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
}

.address-card__phone,
.address-card__lines,
.address-card__comment {
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

.address-card__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-top: var(--space-2);
}

.address-card__inline-form {
    display: contents;
}

.address-card__action {
    font-size: 0.85rem;
    color: var(--color-accent-dark);
    text-decoration: underline;
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    font-family: var(--font-body);
}

.address-card__action--danger {
    color: var(--color-danger);
}

.account-form {
    margin-top: var(--space-2);
    padding: var(--space-6) var(--space-5);
    background: var(--color-bg-soft);
    border-radius: var(--radius-md);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.account-form__title {
    margin: 0;
}

.account-form__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.account-form__row .field {
    flex: 1 1 140px;
}

.account-form__actions {
    display: flex;
    align-items: center;
    gap: var(--space-4);
}

/* --------------------------------------------------------------------------
   Admin area (Task 13): dashboard, orders, products, categories. Reuses
   .card / .btn / .field / .field__input / .field__error / .account-form* /
   .checkout-form__section / .cart-summary__subtotal from earlier tasks rather
   than redefining input/card styling a third time - only table/nav/stat-grid
   layout is genuinely new here.
   -------------------------------------------------------------------------- */

.admin-shell {
    padding-block: var(--space-7);
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.admin-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    padding-bottom: var(--space-4);
    border-bottom: 1px solid var(--color-border);
}

.admin-nav__link {
    font-family: var(--font-heading);
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--color-text);
}

.admin-nav__link--back {
    margin-left: auto;
    font-weight: 400;
    color: var(--color-text-muted);
}

.admin-shell__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.admin-page__title {
    margin-bottom: 0;
}

.admin-page__header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
}

.admin-flash {
    background: var(--color-bg-soft);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    color: var(--color-accent-dark);
}

.admin-stats {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
}

.admin-stats__card {
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.admin-stats__card h2 {
    font-family: var(--font-heading);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

.admin-stats__value {
    font-size: 2rem;
    font-weight: 700;
    color: var(--color-accent-dark);
}

.admin-panel {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.admin-panel h2 {
    font-family: var(--font-heading);
    font-size: 1.05rem;
    font-weight: 600;
}

.admin-filter {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-4);
}

.admin-filter__field {
    min-width: 200px;
}

/* Подписчики рассылки (admin/newsletter-list.html): пояснение над списком и подзаголовки секций.
   Классы .admin-table/.admin-page__title переиспользуем как есть — свой вид таблицы не изобретаем. */
.admin-note {
    max-width: 46rem;
    margin-bottom: var(--space-4);
    color: var(--color-text-muted);
    font-size: 0.92rem;
    line-height: 1.6;
}

.admin-section__title {
    margin-top: var(--space-6);
    margin-bottom: var(--space-3);
    font-size: 1.05rem;
}

.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

/* ВСЁ В ТАБЛИЦАХ АДМИНКИ — ПО ЦЕНТРУ СТОЛБЦА, и заголовок, и данные под ним. Решение владелицы:
   разнобой «заголовок над одним краем, значение под другим» заставлял глаз каждый раз искать,
   к какому столбцу относится ячейка. */
.admin-table th,
.admin-table td {
    text-align: center;
    padding: var(--space-3);
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
}

/* Исключение — многострочные куски текста: состав заявки, контакты покупателя, заметки. Абзац
   по центру читается рвано, потому что у каждой строки свой левый край. Значения (числа, статусы,
   даты, суммы) остаются по центру, тексты — по левому. */
.admin-table td.admin-cell-text,
.admin-table th.admin-cell-text {
    text-align: left;
}

.admin-table th {
    color: var(--color-text-muted);
    font-weight: 600;
}

.admin-table--form input,
.admin-table--form select {
    min-width: 90px;
}

/*
  Столбец действий — НЕ flex. display:flex на <td> вынимает ячейку из табличной раскладки: она
  перестаёт тянуться по высоте строки, и весь столбец уезжает относительно остальных — линии
  под «Редактировать» не совпадают с линиями строк. Ровно это было видно в списке товаров.
  Ссылка и кнопка выстраиваются строчными элементами, а по центру их ставит общее правило
  выравнивания таблицы.
*/
.admin-table td.admin-table__actions { white-space: nowrap; }
.admin-table td.admin-table__actions > * { display: inline-block; vertical-align: middle; margin: 0; }
.admin-table td.admin-table__actions > * + * { margin-left: var(--space-3); }

.admin-link-btn {
    font-size: 0.85rem;
    color: var(--color-accent-dark);
    text-decoration: underline;
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    font-family: var(--font-body);
}

.admin-link-btn--danger {
    color: var(--color-danger);
}

.admin-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.admin-form__hint {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    max-width: 39.5rem;
}

/* Variant colour field: a native colour picker (the visible swatch) next to the hex text input,
   kept in sync by static/js/admin-product-form.js. Clicking the swatch opens the OS colour picker. */
.color-field {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.color-field__picker {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: none;
    cursor: pointer;
}

/* Trim the browser's default swatch chrome so the control reads as a clean colour chip. */
.color-field__picker::-webkit-color-swatch-wrapper {
    padding: 2px;
}

.color-field__picker::-webkit-color-swatch {
    border: none;
    border-radius: 3px;
}

.color-field__hex {
    min-width: 0;
}

/* ---- Admin product-form image slots (drag-and-drop upload, static/js/admin-product-form.js) ---- */
.image-slots {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: var(--space-4);
}

.image-slot {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
}

/* Dropzone: a dashed frame that shows the preview (or a hint when empty), highlighted while a file
   is dragged over it. It's a <label> wrapping the hidden file input, so a click opens the picker. */
.image-slot__drop {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 4 / 5;
    border: 1.5px dashed var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-bg-soft);
    cursor: pointer;
    overflow: hidden;
    text-align: center;
}

.image-slot__drop.is-dragover {
    border-color: var(--color-accent-dark);
    background: var(--color-bg-tint-blue);
}

.image-slot__drop:focus-visible {
    outline: 2px solid var(--color-accent-dark);
    outline-offset: 2px;
}

.image-slot__preview {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.image-slot__preview.is-empty {
    display: none;
}

.image-slot__hint {
    padding: var(--space-3);
    color: var(--color-text-muted);
    font-size: 0.82rem;
    line-height: 1.4;
}

/* When a photo is present its preview covers the frame, so the hint underneath is hidden. */
.image-slot__preview:not(.is-empty) ~ .image-slot__hint {
    display: none;
}

.image-slot__uploading {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.82);
    font-size: 0.85rem;
    color: var(--color-text);
}

/* The flex display above would otherwise override the `hidden` attribute's display:none. */
.image-slot__uploading[hidden] {
    display: none;
}

.image-slot__fields {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.image-slot__meta {
    display: grid;
    grid-template-columns: 1fr 90px;
    gap: var(--space-2);
}

.image-slot__clear {
    align-self: flex-start;
    font-size: 0.8rem;
    color: var(--color-text-muted);
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}

.image-slot__clear:hover {
    color: var(--color-danger);
}

.admin-order-detail {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

.admin-status-form {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: center;
}

/* Wraps every <table class="admin-table"> so wide tables scroll horizontally instead of
   overflowing the viewport on narrow (~375px) screens, rather than shrinking columns unreadably. */
.table-responsive {
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    min-width: 0;
}

/* The admin form is a flex column; its fieldsets default to min-width:auto, so a wide variant/price
   table would stretch a fieldset past the viewport (horizontal page scroll on phones) instead of
   scrolling inside its .table-responsive wrapper. min-width:0 lets the fieldset shrink to the column
   width so the table scrolls within it. */
.admin-form .checkout-form__section {
    min-width: 0;
}

/* --------------------------------------------------------------------------
   About page (Task 14): editorial brand-story layout for /about. Reuses .usp__grid/.usp__item
   from the home page for the closing "what we believe" section rather than redefining it.
   -------------------------------------------------------------------------- */

/* Creative "family album" layout: a full-bleed photo hero with parallax, a scattered collage of
   tilted polaroid photos + overlapping text notes (chaotic on desktop, clean stack on mobile), a
   big tilted closing quote, and scroll-reveal animations (static/js/about.js). */
.about {
    /* No bottom padding: the page now ends on the full-bleed production-photo band, which sits flush
       against the footer (paired with `.about ~ .site-footer { margin-top: 0 }`). */
    padding-bottom: 0;
    /* rotated / offset collage pieces must never trigger horizontal scroll */
    overflow-x: clip;
}

/* Scroll reveal (site-wide, static/js/reveal.js): elements fade/rise in when they enter the
   viewport. Hidden ONLY when JS is active (html.js-reveal); with no JS everything is visible. */
.js-reveal .reveal {
    opacity: 0;
    transform: translateY(26px);
}

.reveal {
    transition: opacity 0.7s ease, transform 0.7s ease;
}

.reveal.is-visible {
    opacity: 1;
    transform: none;
}

@media (prefers-reduced-motion: reduce) {
    .js-reveal .reveal { opacity: 1; transform: none; }
    .reveal { transition: none; }
}

.about-eyebrow {
    font-family: var(--font-heading);
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    font-size: 0.75rem;
    color: var(--color-text-muted);
}

/* ---- Full-bleed hero ---- */
.about-hero {
    position: relative;
    min-height: min(62vh, 540px);     /* shorter hero so the story + photos sit higher up the page */
    display: flex;
    align-items: flex-end;            /* sit the intro in the lower part of the photo, off the face */
    justify-content: center;
    overflow: hidden;
    color: var(--color-white);
    text-align: center;
}

.about-hero__bg {
    position: absolute;
    inset: -10% 0;                 /* taller than the frame so the parallax shift has room */
    background-size: cover;
    background-position: center;
    will-change: transform;
}

.about-hero__scrim {
    position: absolute;
    inset: 0;
    /* Darken enough that the white intro text stays readable over a bright, sunlit photo, while
       keeping the moody atmosphere: a uniform wash + a soft centred pool behind the text. */
    background:
        radial-gradient(120% 80% at 50% 45%, rgba(30, 30, 30, 0.5) 0%, rgba(30, 30, 30, 0.28) 55%, rgba(30, 30, 30, 0.2) 100%),
        linear-gradient(180deg, rgba(30, 30, 30, 0.35) 0%, rgba(30, 30, 30, 0.3) 45%, rgba(30, 30, 30, 0.55) 100%);
}

.about-hero__back {
    position: absolute;
    top: var(--space-4);
    left: var(--space-4);
    z-index: 2;
    color: rgba(255, 255, 255, 0.9);
    font-size: 0.9rem;
    text-shadow: 0 1px 8px rgba(30, 30, 30, 0.45);
}

.about-hero__back:hover {
    color: var(--color-white);
}

.about-hero__content {
    position: relative;
    z-index: 1;
    max-width: 26.5rem;
    padding: var(--space-6);
    padding-bottom: clamp(var(--space-7), 9vh, var(--space-8));  /* lift clear of the scroll hint */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4);
}

.about-hero .about-eyebrow {
    color: rgba(255, 255, 255, 0.85);
}

.about-hero__lede {
    /* explicit white: the base `p { color }` rule otherwise overrides the inherited white */
    color: var(--color-white);
    /* body font, normal weight, modest size: the heavy display face read as too big and bold
       over the photo - this keeps the intro calm and easy to read. */
    font-family: var(--font-body);
    font-weight: 400;
    font-size: clamp(1.05rem, 0.9rem + 0.8vw, 1.45rem);
    line-height: 1.5;
    text-shadow: 0 1px 12px rgba(30, 30, 30, 0.4);
}

.about-hero__sub {
    font-size: 1rem;
    color: rgba(255, 255, 255, 0.92);
    text-shadow: 0 1px 8px rgba(30, 30, 30, 0.4);
}

.about-hero__scrollhint {
    position: absolute;
    left: 50%;
    bottom: var(--space-5);
    transform: translateX(-50%);
    z-index: 1;
    line-height: 0;                       /* a bouncing down-arrow (SVG), not the old "листайте" text */
    color: rgba(255, 255, 255, 0.85);
    animation: about-bob 2.4s ease-in-out infinite;
}

@keyframes about-bob {
    0%, 100% { transform: translate(-50%, 0); }
    50% { transform: translate(-50%, 7px); }
}

@media (prefers-reduced-motion: reduce) {
    .about-hero__scrollhint { animation: none; }
}

/* ---- "О нас" story ----
   One family photo filling the left column edge-to-edge (full-bleed - it runs to the very left edge
   with no white gap around it), the story in a comfortable reading column on the right. Mobile
   default: the photo on top, the story below. */
.about-story {
    background: var(--color-bg);
    padding: 0;
}

.about-story__grid {
    display: flex;
    flex-direction: column;
}

/* Mobile order: photo first, then the "О нас" label, then the story. */
.about-story__media {
    order: 1;
}

.about-story__eyebrow {
    order: 2;
}

.about-story__text {
    order: 3;
}

.about-story__media {
    margin: 0;
    line-height: 0;
    /* Тёплая подложка в зарезервированной рамке: пока фото грузится, видно ровный цвет, а не белую
       вспышку или «проявляющийся» блюр. Рамка уже зарезервирована (width/height + aspect-ratio),
       поэтому сдвига нет, фото просто появляется поверх подложки. */
    background-color: #e7dfd2;
}

.about-story__media img {
    display: block;
    width: 100%;
    height: auto;
    object-fit: cover;
    filter: saturate(0.96) contrast(0.98);
}

.about-story__text {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    /* Justified (по ширине) on all sizes at the owner's request. */
    text-align: justify;
    padding: var(--space-6) var(--space-4);
}

.about-story__eyebrow {
    display: block;
    margin-bottom: var(--space-1);
    text-align: left;
    /* Horizontal padding so the "О нас" label isn't flush against the screen edge on mobile, plus a
       top gap so it sits below the photo instead of right against it (desktop overrides both with its
       own grid placement). */
    padding-inline: var(--space-4);
    margin-top: var(--space-5);
}

.about-story__lede,
.about-story__text p {
    color: var(--color-text-muted);
    line-height: 1.7;
}

.about-story__lede {
    color: var(--color-text);
}

/* Desktop: two columns inside a centred max-width (so there's a white margin on the sides, as before).
   The photo column is stretched to the text column's height and its image is `object-fit: cover`, so
   the photo fills the whole column height - no white gap below it before "Как мы работаем". The text
   column is the wider of the two and its copy is justified. */
@media (min-width: 900px) {
    .about-story__grid {
        display: grid;
        grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
        /* Row 1 = the "О нас" label (auto height) over the text column; row 2 = photo + story. This
           is what drops the photo down so it starts on the first story line, with "О нас" sitting
           above it rather than beside its top corner. */
        grid-template-rows: auto 1fr;
        align-items: stretch;
        max-width: 1280px;
        margin-inline: auto;
    }

    /* Breathing room lives on the section (top only), so the columns themselves have NO vertical
       padding. That way row 2's height equals the story CONTENT exactly, and the photo - absolutely
       positioned to fill it - starts level with the first line and ends level with the last one,
       never overhanging it. */
    .about-story {
        /* Equal white space above ("О нас" ↔ header) and below (text ↔ "Как мы работаем"). */
        padding-top: clamp(var(--space-6), 4vw, var(--space-8));
        padding-bottom: clamp(var(--space-6), 4vw, var(--space-8));
    }

    .about-story__eyebrow {
        grid-column: 2;
        grid-row: 1;
        margin: 0 0 var(--space-4);
        padding-inline: clamp(var(--space-6), 5vw, var(--space-8));
    }

    /* Photo spans BOTH rows (the "О нас" label row + the story row), so its top starts level with
       "О нас" and its bottom ends level with the last line of the story. */
    .about-story__media {
        grid-column: 1;
        grid-row: 1 / 3;
        position: relative;
        height: 100%;
    }

    .about-story__media img {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
    }

    .about-story__text {
        grid-column: 2;
        grid-row: 2;
        justify-content: center;
        padding-block: 0;
        padding-inline: clamp(var(--space-6), 5vw, var(--space-8));
        /* Justify only on the wide desktop column, where it reads cleanly. */
        text-align: justify;
    }
}

/* Full-bleed warm band (edge to edge). Was a cool blue tint (--color-bg-tint-blue) with bold
   centred headings, which read cold and spec-sheet-dry next to the warm editorial "О нас" collage
   above it. Now it is a soft cream ground that continues the collage's warmth: an eyebrow, a lighter
   heading, and three airy columns separated only by hairline rules - the same quiet, unboxed
   editorial voice as the story, rather than a panel bolted on below it. */
/* Warm butter band (--color-beige, echoing the header/marquee) with the "Как мы работаем" copy:
   an eyebrow, a lighter heading, and three airy columns separated only by hairline rules. */
.about-values {
    /* No top margin: the white gap above this block is now the "О нас" section's own padding-bottom,
       kept equal to its padding-top so the spacing matches top and bottom. */
    margin-top: 0;
    text-align: center;
    background: var(--color-beige);
    /* Боковой отступ полосы: карточка внутри должна уходить вправо и влево, а не жаться к
       середине, но и не упираться в самые края экрана. Значение подобрано по просьбе владелицы
       в два захода — сначала карточку раздвинули до краёв, потом чуть сузили снаружи. */
    padding: var(--space-6) clamp(var(--space-3), 1.8vw, var(--space-5));
}

.about-values__eyebrow {
    display: block;
    margin-bottom: var(--space-2);
}

.about-values h2 {
    font-weight: 500;
    letter-spacing: -0.01em;
    margin-bottom: var(--space-7);
}

.about-values h2,
.about-values .usp__grid {
    max-width: 1640px;
    margin-inline: auto;
}

.about-values .usp__grid {
    gap: 0;
    /* Equal-width columns (owner's request). Kept as wide as the band allows (see the reduced
       section padding + wider max-width) so the longest paragraph still lands on four lines. */
    grid-template-columns: repeat(3, 1fr);
}

/* Горизонтальные отступы держит КОЛОНКА, а не карточка (см. padding карточки ниже: по бокам он
   обнулён). Иначе крайний текст отступал от края карточки на сумму двух отступов, а от
   разделительной черты — только на свой, и просветы читались разными. Теперь и от края, и от
   черты одно и то же расстояние. */
.about-values .usp__item {
    text-align: left;
    padding-inline: var(--space-5);
}

.about-values .usp__item + .usp__item {
    border-left: 1px solid rgba(30, 30, 30, 0.12);
}

/* Heading centred over its own (left-aligned) paragraph. */
.about-values .usp__item h3 {
    /* 600, а не 500: на широкой светлой карточке заголовки колонок читались как обычный текст —
       владелица описала это как «слетела жирность». Отличать их от абзаца должен вес, а не размер:
       поднимать кегль здесь нельзя, три заголовка встанут в разную ширину строки. */
    font-weight: 600;
    font-size: 1.05rem;
    margin-bottom: var(--space-3);
    text-align: center;
}

.about-values .usp__item p {
    line-height: 1.7; /* same line spacing as the "О нас" story text */
    color: var(--color-text-muted);
    text-align: justify;
}

@media (max-width: 767px) {
    /* Stack to ONE column on phones. Without this the block kept its 3-column grid, squeezing each
       paragraph into a ~120px column where justified text stretched and broke apart.
       The three points also sit inside ONE light card (rounded + soft shadow), lifted off the beige
       band, so the "Что лежит в основе каждой вещи" heading above reads as a separate intro and no
       longer blends into "Собственная разработка". */
    .about-values .usp__grid {
        grid-template-columns: 1fr;
        background: var(--color-surface);
        border-radius: 16px;
        margin: var(--space-6) var(--space-3) 0;
        padding: var(--space-4) var(--space-5);
        box-shadow: 0 6px 24px rgba(30, 30, 30, 0.08);
    }

    /* Heading is the section intro on the plain beige; the gap down to the card (grid margin-top)
       does the separating now, so drop the old divider line under it. */
    .about-values h2 {
        margin-bottom: 0;
        padding-bottom: 0;
        border-bottom: none;
    }

    .about-values .usp__item:first-child {
        padding-top: var(--space-4);
    }

    /* On mobile the headings stay centred and the paragraphs justified (по ширине), same as desktop,
       at the owner's request - only the column layout and dividers change for the narrow screen. */
    .about-values .usp__item {
        padding-inline: 0;
        padding-block: var(--space-5);
    }

    .about-values .usp__item + .usp__item {
        border-left: none;
        border-top: 1px solid rgba(30, 30, 30, 0.12);
    }
}

/* Узкий планшет (768–899): колонок по-прежнему три, но светлой карточки ещё нет, и ширины на
   текст остаётся около 220 px. С отступом в 24 px выключка по ширине начинает растягивать строки
   пробелами. Возвращаем здесь прежние 12 px: равенство отступов «от края карточки» и «от черты»
   тут не нарушается, потому что карточки — и её собственных отступов — на этой ширине нет. */
@media (min-width: 768px) and (max-width: 899px) {
    .about-values .usp__item {
        padding-inline: var(--space-3);
    }
}

/* Desktop: lift the three points into a light card (same treatment as mobile) so the heading
   "Что лежит в основе каждой вещи" reads as an intro, clearly set off from the points below. The
   vertical hairlines between columns come from the base .usp__item+.usp__item rule. */
@media (min-width: 900px) {
    .about-values h2 {
        margin-bottom: 0;
    }

    .about-values .usp__grid {
        /* Был #FBFAF6 — тон из белой эпохи: красного на единицу больше зелёного, разница с
           синим всего 5. Ровно тот рецепт, который на тёплой бумаге читается розоватым.
           Теперь общий тон поверхностей: красного и зелёного поровну, синего на 11 меньше. */
        background: var(--color-surface);
        border-radius: 18px;
        margin-top: var(--space-7);
        /* По бокам нуля: отступы дают сами колонки, чтобы расстояние от текста до края карточки
           совпадало с расстоянием от текста до разделительной черты. */
        padding: var(--space-6) 0;
        box-shadow: 0 8px 30px rgba(30, 30, 30, 0.08);
    }
}

/* Atelier triptych directly under the copy: three production photos edge to edge across the full
   width, no gaps between them and no margins around them. Pre-graded to one warm film tone; this
   light filter holds the band consistent; a shared aspect-ratio keeps all three the same height. */
.about-work {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0;
    /* На всю ширину, без белых краёв (edge-to-edge). */
    margin: 0;
    line-height: 0;
    /* start — фото держат заданную пропорцию и НЕ растягиваются по высоте. */
    align-items: start;
}

.about-work img {
    width: 100%;
    height: auto;        /* высоту задаёт aspect-ratio (не растягиваем) */
    /* Кадр стал ниже по просьбе владелицы: 6/5 вместо 14/15. Уменьшаем именно ПРОПОРЦИЮ, а не
       ширину — полоса из трёх фото должна остаться во всю ширину экрана, без белых полей по бокам,
       иначе развалится вся композиция низа страницы. */
    aspect-ratio: 6 / 5;
    object-fit: cover;
    display: block;
    filter: saturate(0.94) contrast(0.98);
    background-color: #e7dfd2; /* тёплая подложка, пока фото грузится — без белой вспышки/сдвига */
}

/* The About page ends on the full-bleed photo band, so drop the footer's usual top margin and let
   the footer sit flush under the photos (owner's request - no white gap between the production
   photos and "Покупателям"). `.about` is only on this page's <main>, so other pages keep the gap. */
.about ~ .site-footer {
    margin-top: 0;
}

/* Мобилка: фото производства делаем компактнее и с зазором, чтобы три снимка читались как отдельные,
   а не сливались вплотную («друг на друге»). Десктоп остаётся прежним (сплошная полоса без зазоров). */
@media (max-width: 600px) {
    /* Без зазоров и полей — сплошная полоса, как было раньше (белые рамки убраны).
       align-items:start и height:auto уже заданы в базовом правиле выше, поэтому фото не
       растягиваются. На телефоне колонка узкая — берём вертикальный кадр. */
    .about-work img {
        /* На телефоне фото стоят в один столбец и оттого кажутся выше — пропорцию держим ближе к
           квадрату, чтобы полоса не растянулась на три экрана прокрутки. */
        aspect-ratio: 1 / 1;
    }
}

/* --------------------------------------------------------------------------
   Legal pages (Task 14): one shared template for /legal/privacy, /legal/terms, /legal/returns.
   -------------------------------------------------------------------------- */

.legal-page {
    /* Одинаковый воздух сверху и снизу: столько же, сколько от шапки до «← Вернуться назад».
       Широкую белую полосу (было 48 + 72 = 120 px) убирает не этот отступ, а обнулённый
       margin подвала ниже — сам по себе отступ страницы остаётся симметричным. */
    padding-block: var(--space-7);
    max-width: 46.5rem;
}

/* Подвал вплотную к тексту «Покупателям» (Доставка, Возврат, Политика, Соглашение, Контакты).
   Тот же приём, что уже применён к каталогу чуть выше: у этих страниц контент заканчивается
   обычным абзацем, и 72 px отступа подвала читались как «страница оборвалась». */
.site-main:has(.legal-page) ~ .site-footer,
.site-main:has(.legal-page) + .site-footer {
    margin-top: 0;
}

/* Body copy on the "Покупателям" pages (Доставка, Возврат, Политика, Соглашение — all use
   .legal-page) is justified (по ширине), the same as the "О нас" story, so every page reads evenly
   on mobile. Justify only — no word hyphenation (owner asked for alignment only). Headings and the
   short courier-method lines are left as-is. */
.legal-page__lead,
.legal-page p,
.legal-page li {
    text-align: justify;
}

.legal-page__lead {
    font-size: 1.05rem;
    line-height: 1.6;
    margin-bottom: var(--space-6);
}

.legal-page__title {
    margin-bottom: var(--space-4);
}

.legal-page__note {
    color: var(--color-text-muted);
    font-size: 0.9rem;
    margin-bottom: var(--space-6);
}

/* A closing note that follows the sections (not a lead-in) needs breathing room above it. */
.legal-page__section + .legal-page__note {
    margin-top: var(--space-6);
}

/* Ссылка-действие в конце правовой страницы («Заполнить заявку на возврат»).
   Отдельный вариант, а не правка .legal-page__note: тем же классом набраны сноски на «Контактах»,
   в размерной сетке и на страницах подписки, и там укрупнять нечего.

   Крупнее сноски, потому что это единственное действие на странице: человек, дочитавший условия,
   идёт именно сюда. Дата редакции прижата к ней вплотную и набрана мельче — это подпись под
   документом, а не следующий шаг, и разделять их воздухом было незачем. */
.legal-page__note--action {
    font-size: 1.05rem;
    margin-bottom: var(--space-1);
}

.legal-page__note--action + .legal-page__revision {
    margin-top: 0;
    font-size: 0.78rem;
}

/* Дата редакции документа. Служебная строка: нужна в споре и при проверке, но читателю не адресована,
   поэтому — мельче основного текста и приглушённым цветом, как сноска. */
.legal-page__revision {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    margin-bottom: var(--space-6);
}

/* Дата, стоящая ПОСЛЕ разделов (страница возврата), — это подпись под документом, а не подзаголовок
   под названием: сверху ей нужен воздух и отделяющая линия. */
.legal-page__section + .legal-page__revision {
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-border);
}

.legal-page__section + .legal-page__section {
    margin-top: var(--space-6);
}

.legal-page__section h2 {
    font-size: 1.1rem;
}

.legal-page__section h3 {
    font-size: 1rem;
    margin-bottom: var(--space-2);
}

/* Inline "свяжитесь с нами…" contact chooser: an underlined trigger that reveals the contact
   methods (same as the footer) on hover/focus. */
/* Выбор действия под каждой вещью в заявке: появляется по галочке, поэтому отбит слева,
   чтобы визуально принадлежать вещи, а не форме целиком. */
/* Выбор — второй строкой, с отступом ровно под название: миниатюра 56 px, галочка и два зазора.
   Так вторая строка начинается там же, где название, а не от края карточки. */
.return-item__choice {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0 0 0 calc(56px + 1rem + var(--space-3) * 2);
}

/* На телефоне отступ съедает половину ширины — там выбор идёт от края. */
@media (max-width: 700px) {
    .return-item__choice { margin-left: 0; }
}

.return-item__action {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.95rem;
}

.contact-dropdown {
    position: relative;
}

.contact-dropdown__trigger {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}

.contact-dropdown__trigger:hover {
    color: var(--color-payne-gray);
}

.contact-dropdown__menu {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 30;
    min-width: 190px;
    display: none;
    flex-direction: column;
    padding: var(--space-2);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    box-shadow: 0 14px 34px rgba(30, 30, 30, 0.14);
}

.contact-dropdown:hover .contact-dropdown__menu,
.contact-dropdown:focus-within .contact-dropdown__menu {
    display: flex;
}

.contact-dropdown__item {
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    color: var(--color-text);
    font-size: 0.95rem;
}

.contact-dropdown__item:hover {
    background: var(--color-bg-soft);
}

/* Delivery page: the "Доставка заказа" page title is sized to match the section-level
   "Оплата заказа" heading (rather than the larger default legal-page h1). */
.legal-page__heading--section {
    font-size: 1.1rem;
    margin-bottom: var(--space-3);
}

/* Consistent vertical rhythm between every block in a section (paragraphs, lists, etc.),
   with readable line spacing. */
.legal-page__section p {
    line-height: 1.6;
}

.legal-page__section > * + * {
    margin-top: var(--space-3);
}

.legal-page__section ul {
    list-style: disc;
    padding-left: 1.4em;
}

.legal-page__section li + li {
    margin-top: var(--space-1);
}

/* Free-shipping perk: a quietly emphasised line. */
.legal-page__highlight {
    font-weight: 600;
    color: var(--color-text);
}

/* Delivery methods (delivery.html): each courier as an icon + name + one-line description, instead
   of a plain bullet. Not the disc-bullet list above - reset the list styling and lay each row out. */
.delivery-methods {
    list-style: none;
    padding-left: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    margin-block: var(--space-2);
}

.delivery-method {
    display: grid;
    grid-template-columns: 96px 1fr;
    align-items: center;
    gap: var(--space-4);
}

.delivery-method + .delivery-method {
    margin-top: 0; /* overrides the generic `li + li` spacing; the grid gap handles it */
}

/* Courier logos as coloured wordmarks in each brand's colour, rendered in SVG so both are the exact
   same height and share one visual style (the raw icons ship in different styles/sizes). Fixed 24px
   SVG height + a fixed-width column keeps the two aligned and the descriptions flush. */
.courier-logo {
    display: inline-flex;
    align-items: center;
}

.courier-logo svg {
    height: 24px;
    width: auto;
}

.courier-logo__word {
    font-family: var(--font-heading);
    font-weight: 800;
    font-size: 30px;
    letter-spacing: 0.01em;
}

.courier-logo--cdek .courier-logo__word {
    fill: #1ab248; /* СДЭК green */
}

.courier-logo--5post .courier-logo__word {
    fill: #1d1d1b; /* 5post dark */
}

.courier-logo--5post .courier-logo__five {
    fill: #e5006d; /* 5post magenta */
}

.courier-logo--yandex .courier-logo__word {
    fill: #fc3f1d; /* Яндекс red */
}

.delivery-method__desc {
    color: var(--color-text);
}

/* --------------------------------------------------------------------------
   Brand-emblem intro splash (emblem task, item 2): layout/base.html, static/js/intro.js.
   A fixed overlay, `hidden` by default in the markup (so no-JS visitors/crawlers never see it and
   the real page underneath is never delayed), that intro.js reveals once per visitor and draws
   the two emblem paths via stroke-dashoffset before fading itself out. See intro.js for the
   localStorage gate + prefers-reduced-motion handling; the media query below is a CSS-only
   backstop in case that JS check is ever bypassed.
   -------------------------------------------------------------------------- */

.brand-intro {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-alabaster);
    transition: opacity 0.4s ease;
}

.brand-intro[hidden] {
    display: none;
}

.brand-intro.is-fading {
    opacity: 0;
}

.brand-intro__emblem {
    width: min(36vw, 168px);
    height: auto;
    color: var(--color-payne-gray);
}

.brand-intro__emblem path {
    transition: stroke-dashoffset 0.9s ease;
}

@media (prefers-reduced-motion: reduce) {
    /* Belt-and-braces: intro.js already skips showing this overlay at all when reduced motion is
       requested, but if script execution is ever delayed/interrupted after the element is
       unhidden, this guarantees no animated content is ever forced on a reduced-motion visitor. */
    .brand-intro {
        display: none !important;
    }
}

/* --------------------------------------------------------------------------
   Error pages (Task 14): templates/error/404.html, templates/error/500.html.
   -------------------------------------------------------------------------- */

.error-page {
    padding-block: var(--space-8);
    min-height: 40vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: var(--space-4);
}

.error-page__code {
    font-family: var(--font-heading);
    font-weight: 800;
    font-size: clamp(3rem, 2rem + 6vw, 6rem);
    /* Deep tone, not the pale blue accent, for legibility at this size against a white page. */
    color: var(--color-accent-dark);
    line-height: 1;
}

.error-page__text {
    color: var(--color-text-muted);
    max-width: 33rem;
}

/* --------------------------------------------------------------------------
   Favorites page (revamp item 9): /favorites is populated entirely client-side by
   static/js/favorites.js from localStorage - #favorites-grid reuses .product-grid/.card exactly
   like the catalog, #favorites-empty is the "nothing saved yet" state.
   -------------------------------------------------------------------------- */

.favorites-page {
    padding-block: var(--space-7);
}

.favorites-page h1 {
    font-weight: 400;          /* лёгкий, как «Каталог» */
    letter-spacing: -0.01em;
    margin-bottom: var(--space-6);
}

.favorites-empty {
    position: relative;
    isolation: isolate;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-4);
    padding: var(--space-8) 0;
    color: var(--color-text-muted);
}

/* Both rules above (`.favorites-empty { display: flex }` and `.product-grid { display: grid }`,
   see line ~1125) are AUTHOR styles with the same specificity as the browser's own UA default
   `[hidden] { display: none }` - author styles always win a same-specificity tie against UA
   defaults, so plain `element.hidden = true/false` (favorites.js) had no visual effect at all
   without these overrides: a class+attribute selector's higher specificity is what actually hides
   either element once its `hidden` attribute is set. */
.favorites-empty[hidden] {
    display: none;
}

#favorites-grid[hidden] {
    display: none;
}

/* "Добавить в корзину" (static/js/favorites.js's favoriteCardMarkup) sits as a sibling AFTER
   .product-card__link, not inside it (so clicking it never navigates to the product page) - its
   horizontal margin mirrors .product-card__body's own padding so it lines up with the name/price
   text above it, and its bottom margin gives it the same breathing room as that padding does at
   the top. */
.favorite-card__add-btn {
    display: flex;
    width: calc(100% - var(--space-4) * 2);
    margin: 0 var(--space-4) var(--space-4);
}


/* --------------------------------------------------------------------------
   Breakpoints
   -------------------------------------------------------------------------- */

@media (min-width: 768px) {
    .site-header .wordmark__img {
        width: 220px;
    }

    .collections__grid {
        grid-template-columns: repeat(4, 1fr);
    }

    .usp__grid {
        grid-template-columns: repeat(3, 1fr);
    }

    .site-footer__grid {
        grid-template-columns: 1.1fr 0.9fr 1.4fr;
        gap: var(--space-7);
    }

    /* Колонки встали в ряд — и с этой ширины раскрытая панель «Контакты» вынимается из потока.
       Пока она была в потоке, её высота входила в высоту строки сетки: на одних ширинах панель
       умещалась, на других (около 1180px) оказывалась выше соседних колонок и толкала нижнюю
       полосу с реквизитами вниз — подвал подпрыгивал на каждом нажатии «Контакты».

       Вертикаль не задана намеренно: без top абсолютный элемент встаёт ровно туда, где стоял бы
       в потоке (static position), то есть сразу под кнопкой «Контакты». left/right: 0 задают ему
       ширину колонки. Место под него колонке резервирует main.js через min-height — иначе
       раскрытая панель налезала бы на реквизиты на узких экранах этого диапазона. */
    .site-footer__contacts {
        position: relative;
    }

    .site-footer__contacts-panel {
        position: absolute;
        left: 0;
        right: 0;
    }

    .product-detail__layout {
        grid-template-columns: 1fr 1fr;
        align-items: start;
    }

    /* The info column is forced to the MAIN photo's height (both columns are the same width and the
       photo is 4:5, so this aspect-ratio reproduces its height exactly), and `margin-top: auto` on
       .product-tabs then pushes the "О модели" / "Детали" accordions to the column's bottom edge -
       so the bottom of "Детали" ends on the same line as the bottom of the first photo, which is
       the layout the owner wants. This only holds while the info content fits inside the photo's
       height; the seam-colour swatches were shrunk (see .color-swatch) partly to keep the
       longsleeve's taller info column within it so the accordions align rather than overflow below. */
    .product-info {
        display: flex;
        flex-direction: column;
        aspect-ratio: 4 / 5;
    }

    .product-tabs {
        margin-top: auto;
    }

    .cart-page__layout {
        display: grid;
        grid-template-columns: 1fr 320px;
        align-items: start;
        gap: var(--space-7);
    }

    .cart-line__media {
        flex-basis: 120px;
        width: 120px;
    }

    .checkout-page__layout {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 440px;
        gap: var(--space-7);
        align-items: start;
    }

    /* «Ваш заказ»: держится на уровне формы при прокрутке (sticky) и растянут по высоте —
       содержимое сверху, кнопка «Перейти к оплате» прижата к низу карточки. */
    .checkout-summary {
        position: sticky;
        top: 96px;
        align-self: start;
        display: flex;
        flex-direction: column;
        min-height: 540px;
    }

    .checkout-summary .checkout-summary__submit {
        margin-top: auto;
    }

    .checkout-confirmation__layout {
        display: grid;
        grid-template-columns: 1fr 380px;
        gap: var(--space-7);
    }

    .account-dashboard__grid,
    .address-list {
        grid-template-columns: repeat(2, 1fr);
    }

    .admin-stats {
        grid-template-columns: repeat(4, 1fr);
    }

    .cookie-consent__inner {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
    }
}

@media (min-width: 1024px) {
    .header-utility__pill {
        display: inline-flex;
    }

    /*
      Одинаковые просветы между колонками подвала. Раньше «Будем на связи» и «Покупателям» стояли
      заметно ближе друг к другу, чем «Покупателям» и «Контакты», хотя gap у грида один на все
      стыки. Дело не в gap, а в том, что колонки шире своего содержимого: форма подписки ограничена
      340px внутри дорожки 1.1fr, список ссылок — своей длины внутри 0.9fr. Пустой остаток дорожки
      прибавляется к gap, и каждый стык получает свой, отличный от соседнего, просвет.

      Лечится не подбором долей, а тем, что первые две дорожки делаются РОВНО по содержимому:
      340px — та самая ширина формы, max-content — длина самой длинной ссылки. Тогда после каждой
      колонки остаётся только сам gap, один и тот же. Остаток забирают «Контакты» — им это кстати,
      там разворачивается абзац с текстом.

      Только с 1024px: на планшете 340px + ссылки + два отступа уже не оставляют «Контактам»
      осмысленной ширины, поэтому там прежние доли (см. брейкпоинт 768px) остаются как есть.
    */
    .site-footer__grid {
        /* Первая дорожка была жёсткие 340px — ширина формы, а не ширина её содержимого. Подписи
           под галочками в неё не помещались и переносились на вторую строку, из-за чего кнопка
           «Подписаться» опускалась ниже последней ссылки соседней колонки. Теперь дорожка сама
           берёт ширину по самой длинной строке согласия (см. nowrap ниже), и колонки снова
           заканчиваются на одном уровне. */
        grid-template-columns: max-content max-content 1fr;
        /* Шире, чем --space-7 на брейкпоинте 768px: там доли дорожек сами добавляли к стыку свой
           остаток, и просветы казались больше, чем заданный отступ. Теперь дорожки ровно по
           содержимому, отступ виден как есть — и трёх рем стало мало, колонки читались как одна
           сплошная простыня. */
        gap: var(--space-8);
    }

    /* Обе подписи — в одну строку каждая. Ограничения ширины, которые держали форму в 340px,
       здесь сняты: дорожка теперь сама подстраивается под содержимое, и поле ввода с кнопкой
       растягиваются на ту же ширину, что и строки согласий.

       Только с 1024px: ниже дорожки заданы долями (1.1fr / 0.9fr / 1.4fr), и неразрывная строка
       в 390px там не поместилась бы в свою колонку — вылезла бы за край и растянула страницу
       горизонтальной прокруткой. На узких экранах перенос на вторую строку — правильное поведение. */
    .site-footer__newsletter .newsletter-form,
    .site-footer__newsletter .newsletter-form__consents {
        max-width: none;
    }

    .site-footer__newsletter .newsletter-consent {
        white-space: nowrap;
    }

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

       Поэтому кнопка прижимается к НИЗУ своей колонки: ячейки грида по умолчанию
       растягиваются на высоту самой высокой в строке, а margin-top: auto отдаёт кнопке
       весь остаток. Цепочка height/flex ниже нужна, чтобы эта высота дошла от ячейки
       грида до самой формы — без неё промежуточные обёртки схлопываются по содержимому
       и прижимать кнопку становится не к чему.

       Побочный эффект: просвет между галочками и кнопкой становится на несколько
       пикселей больше. Это осознанный размен — выровненный низ колонок виден сразу,
       а лишние пять пикселей внутри одной колонки не видит никто. */
    .site-footer__brand,
    .site-footer__newsletter {
        height: 100%;
    }

    .site-footer__newsletter .newsletter-block,
    .site-footer__newsletter .newsletter-form {
        flex: 1;
    }

    .site-footer__newsletter .newsletter-form__submit {
        margin-top: auto;
    }
}

/* --------------------------------------------------------------------------
   Free-shipping nudge toast (cart page): pops up near the bottom of the viewport when the
   cart subtotal is close to the 7 000 ₽ free-delivery threshold. Slides/fades in via the
   .is-visible class that cart.js toggles; `hidden` keeps it fully out until then.
   -------------------------------------------------------------------------- */
.free-ship-toast {
    position: fixed;
    left: 50%;
    bottom: var(--space-5);
    z-index: 60;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    max-width: min(92vw, 440px);
    padding: var(--space-3) var(--space-3) var(--space-3) var(--space-5);
    background: var(--color-old-burgundy, #442D2A);
    color: var(--color-white);
    border-radius: 999px;
    box-shadow: 0 12px 32px rgba(30, 30, 30, 0.28);
    transform: translate(-50%, calc(100% + var(--space-6)));
    opacity: 0;
    transition: transform 0.45s cubic-bezier(0.2, 0.7, 0.3, 1), opacity 0.45s ease;
}

/* An author `display:flex` beats the UA `[hidden]{display:none}` on a same-specificity tie,
   so `hidden` alone would NOT hide the toast (same gotcha as .favorites-empty[hidden]). */
.free-ship-toast[hidden] {
    display: none;
}

.free-ship-toast.is-visible {
    transform: translate(-50%, 0);
    opacity: 1;
}

.free-ship-toast__text {
    font-size: 0.95rem;
    line-height: 1.35;
}

.free-ship-toast__close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    font-size: 1.1rem;
    line-height: 1;
    color: var(--color-white);
    background: rgba(255, 255, 255, 0.16);
    transition: background-color 0.15s ease;
}

.free-ship-toast__close:hover {
    background: rgba(255, 255, 255, 0.28);
}

@media (prefers-reduced-motion: reduce) {
    .free-ship-toast {
        transition: opacity 0.2s ease;
        transform: translate(-50%, 0);
    }
}

/* ============================================================================
   Moments wall (/moments) — a curated pinboard of customer photos, styled as
   scattered polaroids in a masonry column layout.
   ============================================================================ */
.moments-intro {
    text-align: center;
    max-width: 640px;
    padding-top: var(--space-8);
    padding-bottom: var(--space-6);
}

.moments-intro__title {
    font-weight: 400;
    font-size: clamp(2rem, 1.4rem + 3vw, 3.4rem);
    letter-spacing: -0.02em;
    margin: var(--space-2) 0 var(--space-3);
}

.moments-intro__lede {
    color: var(--color-text-muted);
}

.moments-wall-wrap {
    padding-inline: clamp(var(--space-4), 2.5vw, var(--space-7));
    padding-bottom: var(--space-8);
}

.moments-wall {
    column-count: 2;
    column-gap: var(--space-5);
    max-width: 1200px;
    margin-inline: auto;
}

@media (min-width: 640px) { .moments-wall { column-count: 3; } }
@media (min-width: 980px) { .moments-wall { column-count: 4; } }

/* Each moment is a polaroid pinned to the board: white frame, caption in the thicker bottom band,
   a small tilt that straightens on hover. */
.moment {
    break-inside: avoid;
    margin: 0 0 var(--space-6);
    background: var(--color-surface);
    padding: var(--space-2) var(--space-2) var(--space-3);
    border-radius: 3px;
    box-shadow: 0 10px 26px rgba(30, 30, 30, 0.14);
    transform: rotate(var(--tilt, 0deg));
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.moment:nth-child(4n+1) { --tilt: -2.5deg; }
.moment:nth-child(4n+2) { --tilt: 1.8deg; }
.moment:nth-child(4n+3) { --tilt: -1.2deg; }
.moment:nth-child(4n)   { --tilt: 2.6deg; }

.moment:hover {
    transform: rotate(0deg) scale(1.03);
    box-shadow: 0 18px 40px rgba(30, 30, 30, 0.2);
    position: relative;
    z-index: 2;
}

.moment__photo {
    overflow: hidden;
    border-radius: 2px;
    background: var(--color-bg-soft);
}

.moment__photo img {
    display: block;
    width: 100%;
    height: auto;
}

.moment__caption {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--space-2) var(--space-1) var(--space-1);
    text-align: center;
}

.moment__text {
    font-family: var(--font-heading);
    font-weight: 400;
    font-size: 0.9rem;
}

.moment__author {
    font-size: 0.78rem;
    color: var(--color-text-muted);
    letter-spacing: 0.02em;
}

.moments-cta {
    text-align: center;
    max-width: 620px;
    margin-block: var(--space-7) var(--space-8);
    background: var(--color-bg-tint-blue);
    border-radius: var(--radius-md);
    padding: var(--space-7) var(--space-6);
}

.moments-cta__title {
    font-weight: 400;
    margin-bottom: var(--space-3);
}

.moments-cta p {
    color: var(--color-text-muted);
    margin-bottom: var(--space-5);
}

/* ============================================================================
   Slide-in cart drawer (fragments/cart-drawer.html, static/js/cart-drawer.js).
   ============================================================================ */
/* NB: no `visibility: hidden` toggle here on purpose — WebKit won't run/apply the panel's transform
   transition while an ancestor is visibility:hidden, which left the panel stuck off-screen. Instead
   the container stays rendered but clips the off-screen panel (overflow:hidden, so no h-scroll) and
   ignores pointer events until open; the backdrop (opacity 0) and off-screen panel stay invisible. */
.cart-drawer {
    position: fixed;
    inset: 0;
    z-index: 1200;
    overflow: hidden;
    pointer-events: none;
}

.cart-drawer.is-open {
    pointer-events: auto;
}

.cart-drawer__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(30, 30, 30, 0.45);
    opacity: 0;
    transition: opacity 0.3s ease;
}

.cart-drawer.is-open .cart-drawer__backdrop {
    opacity: 1;
}

.cart-drawer__panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(440px, 94vw);
    display: flex;
    flex-direction: column;
    background: var(--color-surface);
    box-shadow: -12px 0 40px rgba(30, 30, 30, 0.18);
    transform: translateX(100%);
    transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1);
}

.cart-drawer.is-open .cart-drawer__panel {
    transform: translateX(0);
}

.cart-drawer__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--color-border);
    background: var(--color-beige);
}

.cart-drawer__title {
    font-weight: 400;
    font-size: 1.2rem;
    margin: 0;          /* убираем унаследованный от h2 нижний отступ — иначе заголовок уезжает вверх */
    line-height: 1;     /* выравниваем по центру с крестиком закрытия */
}

.cart-drawer__close {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--color-text-muted);
}

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

.cart-drawer__body {
    flex: 1;
    overflow-y: auto;
}

.cart-drawer__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-8) var(--space-5);
    text-align: center;
    color: var(--color-text-muted);
}

.cart-drawer__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.cart-drawer__item {
    display: grid;
    grid-template-columns: 88px 1fr auto;
    gap: var(--space-4);
    align-items: start;
    padding: var(--space-5);
    border-bottom: 1px solid var(--color-border);
}

.cart-drawer__thumb img {
    width: 88px;
    height: 112px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    background: var(--color-bg-soft);
}

.cart-drawer__info {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.cart-drawer__name {
    font-family: var(--font-heading);
    font-weight: 400;
    font-size: 1.02rem;
    line-height: 1.35;
}

.cart-drawer__variant {
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.cart-drawer__line {
    display: flex;
    gap: var(--space-3);
    align-items: baseline;
    margin-top: var(--space-1);
    font-size: 0.85rem;
}

.cart-drawer__price {
    font-weight: 600;
    color: var(--color-accent-dark);
}

.cart-drawer__remove {
    background: none;
    border: none;
    cursor: pointer;
    padding: var(--space-1);
    font-size: 0.9rem;
    color: var(--color-text-muted);
}

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

.cart-drawer__summary {
    /* Раньше было position:sticky; bottom:0 — на невысоком экране (телефон) сводка прилипала к низу
       и НАЕЗЖАЛА на товар/промокод («съезжало друг на друга»). Теперь обычный поток: всё
       прокручивается в теле шторки единым столбцом, без наложений. */
    padding: var(--space-5);
    border-top: 1px solid var(--color-border);
    background: var(--color-surface);
}

.cart-drawer__total {
    display: flex;
    justify-content: space-between;
    margin-bottom: var(--space-2);
    font-family: var(--font-heading);
    font-size: 1.05rem;
}

.cart-drawer__note {
    margin-bottom: var(--space-4);
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.cart-drawer__checkout {
    width: 100%;
    margin-bottom: var(--space-3);
}

.cart-drawer__full-link {
    display: block;
    text-align: center;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

/* --- Полноценная корзина в шторке: единичная цена, степпер, промокод, наличие, итоги --- */
.cart-drawer__unit {
    font-size: 0.72rem;
    color: var(--color-text-muted);
}
.cart-drawer__controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: var(--space-3);
}
.quantity-stepper--sm .quantity-stepper__btn {
    width: 28px;
    height: 28px;
    font-size: 0.95rem;
}
.quantity-stepper--sm .quantity-stepper__val {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 30px;
    height: 28px;
    border-left: 1px solid var(--color-border);
    border-right: 1px solid var(--color-border);
    font-size: 0.85rem;
}
.cart-drawer__price--struck {
    margin-top: var(--space-2);
}
.cart-drawer__item--unavailable { opacity: 0.9; }
.cart-drawer__stock-badge {
    color: #B24A2E;
    font-weight: 600;
    font-size: 0.8rem;
    margin-top: 4px;
}
.cart-drawer__pick-size {
    color: #B24A2E;
    font-size: 0.8rem;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.cart-drawer__pick-size:hover { text-decoration: none; }

.cart-drawer__promo {
    /* Одинаковый отступ сверху и снизу — поле промокода ровно по центру между двумя линиями. */
    padding: var(--space-5) var(--space-5);
}
/* Сетка, а не flex: сообщение об ошибке ложится во вторую строку ПЕРВОГО столбца, то есть точно
   под поле ввода. Во flex оно было соседом всего блока и центрировалось вместе с кнопкой —
   визуально уезжало вправо. */
.cart-drawer__promo-form {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--space-2);
    align-items: start;
}
.cart-drawer__promo-input {
    flex: 1;
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
}
.cart-drawer__promo-apply { white-space: nowrap; }
.cart-drawer__promo-applied {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    background: #eaf3ea;
    color: #2e6b3e;
    font-size: 0.85rem;
    flex-wrap: wrap;
}
.cart-drawer__promo-remove {
    background: none;
    border: none;
    cursor: pointer;
    color: #2e6b3e;
    text-decoration: underline;
    font-size: 0.8rem;
}
.cart-drawer__promo-error {
    grid-column: 1;
    margin-top: 0;
    color: #B24A2E;
    font-size: 0.8rem;
    /* По центру относительно поля с промокодом: короткая строка, прижатая к левому краю широкого
       блока, выглядит как случайно оставшийся текст, а не как ответ на нажатие «Применить». */
    text-align: center;
}
.cart-drawer__promo-error[hidden] { display: none; }

.cart-drawer__row {
    display: flex;
    justify-content: space-between;
    font-size: 0.9rem;
    margin-bottom: 4px;
    color: var(--color-text-muted);
}
.cart-drawer__row--total {
    margin: var(--space-2) 0;
    font-family: var(--font-heading);
    font-size: 1.05rem;
    color: var(--color-text);
}
.cart-drawer__stock-note {
    margin-bottom: var(--space-3);
    color: #B24A2E;
    font-size: 0.8rem;
    line-height: 1.4;
}
.cart-drawer__checkout[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
}

/* На мобильном шторка = полноценная корзина во весь экран. */
@media (max-width: 600px) {
    .cart-drawer__panel { width: 100vw; }
    .cart-drawer__item { padding: var(--space-3) var(--space-4); }
    .cart-drawer__promo { padding: var(--space-3) var(--space-4) 0; }
    .cart-drawer__summary { padding: var(--space-4); }
}

/* ============================================================================
   Moments strip (home page): a loomknits-style horizontal, arrow-scrollable
   row of the same customer polaroids shown in full on /moments.
   ============================================================================ */
/* Full-bleed strip: spans the whole viewport width (edge to edge), only a small responsive gutter
   on the heading and on the first/last photo keeps them off the very edge. */
.moments-strip {
    /* margin-top overrides the generic `section + section` gap; kept small so the top gap (hero →
       heading) roughly matches the bottom gap (photos → footer). */
    margin-top: var(--space-5);
    padding-block: var(--space-4) var(--space-5);
}

.moments-strip__head {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-bottom: var(--space-6);
    padding-inline: clamp(var(--space-4), 2.5vw, var(--space-7));
}

.moments-strip__head h2 {
    font-weight: 600;
    font-size: clamp(1.6rem, 1.2rem + 1.4vw, 2.4rem);
    letter-spacing: -0.01em;
}

.moments-strip__subtitle {
    /* Wide enough that each <br/>-separated sentence stays on one line (two lines total). */
    max-width: 64rem;
    color: var(--color-text-muted);
    line-height: 1.55;
}

.moments-strip__all {
    color: var(--color-text-muted);
    font-size: 0.9rem;
    white-space: nowrap;
}

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

.moments-strip__viewport {
    position: relative;
}

.moments-strip__track {
    display: flex;
    gap: var(--space-4);
    list-style: none;
    margin: 0;
    padding: var(--space-2) clamp(var(--space-4), 2.5vw, var(--space-7)) var(--space-3);
    overflow-x: auto;
    scroll-behavior: smooth;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.moments-strip__track::-webkit-scrollbar {
    display: none;
}

.moments-strip__item {
    flex: 0 0 auto;
    width: clamp(200px, 44vw, 280px);
    scroll-snap-align: start;
}

/* Upright polaroids in the strip - the wall's random tilt would look messy in a neat row. */
.moments-strip .moment {
    margin: 0;
    transform: none;
}

/* Uniform card height: crop every photo to the same 4:5 frame so the row lines up neatly. */
.moments-strip .moment__photo {
    aspect-ratio: 4 / 5;
}

.moments-strip .moment__photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.moments-strip .moment:hover {
    transform: translateY(-4px);
}

.moments-strip__arrow {
    position: absolute;
    top: 42%;
    transform: translateY(-50%);
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    box-shadow: 0 6px 18px rgba(30, 30, 30, 0.12);
    cursor: pointer;
    transition: background 0.15s ease, opacity 0.15s ease;
}

.moments-strip__arrow:hover {
    background: var(--color-bg-soft);
}

.moments-strip__arrow--prev {
    left: var(--space-2);
}

.moments-strip__arrow--next {
    right: var(--space-2);
}

.moments-strip__arrow:disabled {
    opacity: 0.35;
    cursor: default;
}

@media (hover: none) {
    .moments-strip__arrow {
        display: none;   /* touch devices swipe the row instead */
    }
}

/* ============================================================================
   Admin dashboard extras: status breakdown chips + status badges + table link.
   ============================================================================ */
.admin-status-grid {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

.admin-status-chip {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 120px;
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-border);
    border-left: 3px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    transition: background 0.15s ease;
}

.admin-status-chip:hover {
    background: var(--color-bg-soft);
}

.admin-status-chip__label {
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.admin-status-chip__count {
    font-family: var(--font-heading);
    font-size: 1.4rem;
}

.admin-status-chip--new       { border-left-color: var(--color-pastel-blue); }
.admin-status-chip--confirmed { border-left-color: var(--color-camel); }
.admin-status-chip--shipped   { border-left-color: var(--color-payne-gray); }
.admin-status-chip--delivered { border-left-color: #6b8f71; }
.admin-status-chip--cancelled { border-left-color: #c0504d; }

.admin-status-badge {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.8rem;
    background: var(--color-bg-soft);
    border: 1px solid var(--color-border);
}

/* Раньше все метки были одинаково серыми, и «Новый» ничем не отличался от «Отправлен» — цвет
   несла только полоса слева. Теперь метка повторяет цвет этапа: взгляд ловит её и в столбце
   «Статус», и когда список отфильтрован и полос почти не видно. */
.admin-status-badge--new       { background: rgba(26, 127, 55, 0.16);  border-color: rgba(26, 127, 55, 0.35);  color: #14622b; }
.admin-status-badge--confirmed { background: rgba(70, 104, 90, 0.16);  border-color: rgba(70, 104, 90, 0.35);  color: #33513f; }
.admin-status-badge--shipped   { background: rgba(98, 114, 127, 0.16); border-color: rgba(98, 114, 127, 0.35); color: #47545f; }
.admin-status-badge--delivered { background: rgba(177, 152, 112, 0.20); border-color: rgba(177, 152, 112, 0.45); color: #7a6338; }
.admin-status-badge--cancelled { background: rgba(192, 80, 77, 0.14);  border-color: rgba(192, 80, 77, 0.35);  color: #a3403d; }

.admin-table__link {
    color: var(--color-accent-dark);
    font-weight: 500;
}

/* Admin order-list filter: search field grows, export button sits to the right. */
.admin-filter {
    flex-wrap: wrap;
    align-items: flex-end;
}

.admin-filter__field--search {
    flex: 1 1 240px;
}

.admin-filter__export {
    margin-left: auto;
}

/* Orders-per-day bar chart (dashboard) - pure CSS bars, no external chart lib. */
.admin-chart {
    display: flex;
    align-items: flex-end;
    gap: var(--space-1);
    padding-top: var(--space-5);
}

.admin-chart__col {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.admin-chart__area {
    height: 150px;
    width: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
}

.admin-chart__bar {
    position: relative;
    width: 70%;
    max-width: 26px;
    min-height: 3px;
    background: var(--color-pastel-blue);
    border-radius: 3px 3px 0 0;
}

.admin-chart__count {
    position: absolute;
    top: -16px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 0.7rem;
    color: var(--color-text-muted);
}

.admin-chart__label {
    font-size: 0.66rem;
    color: var(--color-text-muted);
    white-space: nowrap;
}

/* ============================================================================
   Admin: bulk-status bar, order-detail head, and print styles.
   ============================================================================ */
.admin-bulk-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-soft);
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
}

.admin-bulk-bar__select {
    min-width: 160px;
}

.admin-table__check {
    width: 40px;
    text-align: center;
}

.admin-order-detail__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

/* Print an order cleanly: drop all site/admin chrome and anything marked .no-print. */
@media print {
    .marquee,
    .site-header,
    .site-footer,
    .cookie-consent,
    .welcome-modal,
    .brand-intro,
    .admin-nav,
    .free-ship-toast,
    .cart-drawer,
    .no-print {
        display: none !important;
    }

    body {
        background: var(--color-surface);
        color: #000;
    }

    .admin-shell,
    .admin-shell__body,
    .container {
        max-width: none;
        margin: 0;
        padding: 0;
    }

    .admin-panel {
        border: none;
        box-shadow: none;
        padding: 0 0 10px;
        break-inside: avoid;
    }

    a {
        color: #000;
        text-decoration: none;
    }
}

/* ============================================================================
   Sticky mobile buy bar on the product page (appears when the main add button
   scrolls out of view).
   ============================================================================ */
.pdp-sticky {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 100;
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    box-shadow: 0 -6px 20px rgba(30, 30, 30, 0.08);
}

.pdp-sticky[hidden] {
    display: none;
}

@media (max-width: 740px) {
    .pdp-sticky:not([hidden]) {
        display: flex;
    }
}

.pdp-sticky__info {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.pdp-sticky__name {
    font-size: 0.82rem;
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pdp-sticky__price {
    font-family: var(--font-heading);
    font-weight: 600;
}

.pdp-sticky__btn {
    flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   Админка: что появилось с прошлого захода.

   Зелёная полоса слева, а не заливка всей строки: заливка спорит с колонкой статуса заказа
   (там свои цветные метки) и через десяток строк превращает таблицу в светофор. Полоса читается
   так же быстро, но не мешает читать сами данные. Подсветка держится до следующего открытия
   раздела — отметка о просмотре ставится в момент, когда страница открылась.
   -------------------------------------------------------------------------- */

.admin-row--new > td:first-child {
    box-shadow: inset 5px 0 0 0 #1a7f37;
}

.admin-row--new > td {
    background: rgba(26, 127, 55, 0.13);
}

/* --- ЦВЕТ СТРОКИ ЗАКАЗА = ЧТО ОН ЖДЁТ ОТ ВЛАДЕЛИЦЫ ------------------------------------------
   Не «какой статус», а «чем заняться». Полоса слева и очень слабая заливка: цвет должен
   подсказывать, а не кричать — в списке из тридцати строк яркая заливка мешает читать.

   янтарный  — денег нет, заказ трогать нельзя;
   зелёный   — оплачен, надо собрать и отправить (единственное, что требует рук);
   синий     — уехал, ждём перевозчика, делать нечего;
   песочный  — вручён, но идёт срок возврата: заказ ещё может вернуться;
   без цвета — вручён больше семи дней назад, всё закончилось (решение владелицы: сделанное
               не должно мозолить глаза);
   серый     — отменён.
   Класс ставится по AdminOrderController.stage(): логика в коде, а не в разметке. */
.admin-row--unpaid > td:first-child   { box-shadow: inset 5px 0 0 0 #8a6d00; }
.admin-row--unpaid > td               { background: rgba(138, 109, 0, 0.15); }
.admin-row--pack > td:first-child     { box-shadow: inset 5px 0 0 0 #46685a; }
.admin-row--pack > td                 { background: rgba(70, 104, 90, 0.14); }
.admin-row--transit > td:first-child  { box-shadow: inset 5px 0 0 0 #62727f; }
.admin-row--transit > td              { background: rgba(98, 114, 127, 0.13); }
.admin-row--window > td:first-child   { box-shadow: inset 5px 0 0 0 #b19870; }
.admin-row--window > td               { background: rgba(177, 152, 112, 0.18); }
.admin-row--cancelled > td            { color: var(--color-text-muted); }
.admin-row--cancelled > td:first-child { box-shadow: inset 5px 0 0 0 #c9c9bd; }
/* Заказ, который и новый, и ждёт оплаты: зелёная пометка «новый» не должна перебивать янтарную
   полосу «денег нет» — иначе к нему потянутся собирать. Побеждает то, что важнее. */
.admin-row--unpaid.admin-row--new > td:first-child { box-shadow: inset 5px 0 0 0 #8a6d00; }
.admin-row--unpaid.admin-row--new > td { background: rgba(138, 109, 0, 0.15); }

/* Метки в ячейках: оплата, заявка на возврат. */
.admin-chip {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.74rem;
    font-weight: 600;
    white-space: nowrap;
}
.admin-chip--paid   { background: rgba(70, 104, 90, 0.14); color: #33513f; }
.admin-chip--unpaid { background: rgba(138, 109, 0, 0.16); color: #6b5400; }
.admin-chip--return { background: rgba(178, 74, 46, 0.12); color: #8c3a24; text-decoration: none; }
.admin-chip--return:hover { background: rgba(178, 74, 46, 0.2); }
.admin-muted { color: var(--color-text-muted); }

/* Номер заказа — в одну строку и по центру столбца. Раньше «SV-2026-100001» переносился
   пополам и читался как два разных числа.

   СЕЛЕКТОР ИЗ ДВУХ ЧАСТЕЙ ОБЯЗАТЕЛЕН: у `.admin-table th, .admin-table td` стоит
   `text-align: left`, а это класс ВМЕСТЕ С ТЕГОМ — он весомее одного класса, и центрирование
   по `.admin-col-number` молча не срабатывало. Ровно та же ловушка, что была со скрытой
   подсказкой про брак. */
.admin-table .admin-col-number {
    white-space: nowrap;
}
.admin-table td.admin-col-number { min-width: 9.5rem; }

/* Дата и время — тоже одной строкой: «07.09.2026» и «12:40» на разных строках читались
   как два разных поля, и строка таблицы становилась выше без всякой пользы. */
.admin-table .admin-col-date { white-space: nowrap; }

/* «согласие есть,» и «не подтверждена» — двумя строками, а не одной длинной. */
/* Сумма не переносится: «3 000» и «₽» разъезжались по строкам, знак рубля уезжал вниз. */
.admin-table .admin-col-money { white-space: nowrap; }
.admin-table td.admin-col-money { min-width: 7rem; }

.admin-table .admin-col-newsletter { white-space: nowrap; }
.admin-table .admin-col-newsletter span { display: block; }

/* СТОЛБЕЦ ДЕЙСТВИЙ В ЗАЯВКАХ. Кнопки лежали отдельными формами подряд, и у форм свои отступы:
   визуально «Обмен отправила» и «Не в товарном виде» наезжали друг на друга, а ширина у них
   была разная — по длине надписи. Теперь это колонка с зазором, и кнопки одной ширины: глаз
   читает их как один список действий, а не как случайно упавшие рядом элементы. */
.admin-actions-cell {
    min-width: 13rem;
}
/* ЯЧЕЙКУ НЕ ДЕЛАЕМ FLEX-КОНТЕЙНЕРОМ: `display:flex` на <td> отменяет табличное поведение —
   ячейка перестаёт растягиваться на всю высоту строки, и справа появляется белая проплешина.
   Поэтому раскладку задаём содержимому: формы блоками с отступом, кнопки во всю ширину. */
.admin-table td.admin-actions-cell form { margin: 0 0 8px; }
.admin-table td.admin-actions-cell form:last-child { margin-bottom: 0; }
.admin-table td.admin-actions-cell .btn {
    display: block;
    width: 100%;
    white-space: normal;
}

/* Заголовок-ссылка = сортировка по столбцу. */
.admin-sort {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dashed var(--color-border);
    white-space: nowrap;
}
.admin-sort:hover { border-bottom-color: var(--color-payne-gray); }
.admin-sort.is-on { border-bottom-style: solid; border-bottom-color: var(--color-payne-gray); }

/* Быстрые фильтры «чего заказ ждёт»: те же цвета, что у полосы слева у строки. */
.admin-stages {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 var(--space-4);
}
.admin-stage {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 0.85rem;
    text-decoration: none;
    white-space: nowrap;
}
.admin-stage span {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-muted);
}
.admin-stage:hover { border-color: var(--color-payne-gray); }
.admin-stage.is-on { border-width: 2px; padding: 5px 11px; }
.admin-stage--unpaid.is-on  { border-color: #8a6d00; background: rgba(138, 109, 0, 0.08); }
.admin-stage--pack.is-on    { border-color: #46685a; background: rgba(70, 104, 90, 0.08); }
.admin-stage--transit.is-on { border-color: #62727f; background: rgba(98, 114, 127, 0.08); }
.admin-stage--window.is-on  { border-color: #b19870; background: rgba(177, 152, 112, 0.10); }
.admin-stage--all.is-on     { border-color: var(--color-text); }
/* У отменённого заказа метка «не оплачен» — уже не новость: приглушаем, чтобы она не тянула
   взгляд на строку, с которой делать нечего. */
.admin-row--cancelled .admin-chip { opacity: 0.5; }

/* Заявки на возврат: цвет строки — по типу заявки (брак / обмен / деньги). */
.admin-row--defect > td:first-child   { box-shadow: inset 5px 0 0 0 #b24a2e; }
.admin-row--defect > td               { background: rgba(178, 74, 46, 0.14); }
.admin-row--exchange > td:first-child { box-shadow: inset 5px 0 0 0 #8a6d00; }
.admin-row--exchange > td             { background: rgba(138, 109, 0, 0.15); }
.admin-row--money > td:first-child    { box-shadow: inset 5px 0 0 0 #b19870; }
.admin-row--money > td                { background: rgba(177, 152, 112, 0.18); }
.admin-chip--defect { background: rgba(178, 74, 46, 0.16); color: #8c3a24; }
.admin-chip--photos { background: rgba(98, 114, 127, 0.14); color: #4a5763; }

/* Миниатюра товара в списке. Фиксированный размер, чтобы строки не прыгали по высоте. */
.admin-thumb { width: 56px; }
.admin-thumb img {
    width: 48px;
    height: 60px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
    background: var(--color-bg-soft);
    display: block;
    margin: 0 auto;            /* картинка — блок, и без этого она липнет к левому краю ячейки */
}
/* Суммы и даты не переносим: «3 550 ₽», разорванное на две строки, читается как две цифры. */
.admin-table td:nth-last-child(2) { white-space: nowrap; }

.admin-new-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 7px;
    border-radius: 999px;
    background: #1a7f37;
    color: #fff;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    vertical-align: middle;
}

/* Кнопка необратимого действия в админке (удаление заказов). Красная не для красоты: рядом стоит
   «Применить», и обе нажимаются одним движением — цвет здесь единственное, что успевает
   предупредить руку. */
.btn--danger {
    background: #b3261e;
    color: #fff;
    border-color: #b3261e;
}

.btn--danger:hover {
    background: #8c1d18;
    border-color: #8c1d18;
}

.admin-bulk-bar__delete {
    margin-left: auto;
}

/* --------------------------------------------------------------------------
   Таблица вариантов в карточке товара: колонка артикула шире остальных.
   Артикул вида SV-DTM-001-104110 — 18 символов, а колонка делила ширину поровну
   с «Размером» и обрезала его на середине; владелице приходилось щёлкать в поле
   и прокручивать текст, чтобы прочитать целиком.
   -------------------------------------------------------------------------- */

.admin-col--sku {
    min-width: 13rem;
}

/* Подпись под заголовком колонки — поясняет необязательное поле, не занимая ширины. */
.admin-th-hint {
    display: block;
    font-size: 0.72rem;
    font-weight: 400;
    color: var(--color-text-muted);
    letter-spacing: 0;
    text-transform: none;
}

/* --------------------------------------------------------------------------
   Выравнивание в админке.
   -------------------------------------------------------------------------- */

/* Заголовки таблицы вариантов — по ВЕРХНЕМУ краю. У «Своей цены» под названием есть пояснение,
   ячейка из-за него выше остальных, и при выравнивании по центру (общее правило .admin-table)
   все прочие названия провисали вниз относительно неё. */
.admin-table--form th {
    vertical-align: top;
}

/* Фильтр заказов: подписи «Статус» и «Поиск» — на одной линии, поля под ними — тоже.
   Расходились не блоки, а сами контролы: <select> и <input type="search"> считают
   собственную высоту по-разному, и этой разницы в пару пикселей хватало, чтобы подпись
   над более высоким полем уехала вверх. Выравнивание по нижнему краю тут не спасает — оно
   как раз и переносит всю разницу наверх, к подписям. Задаём обоим полям одну высоту —
   ту же, что у кнопок рядом, — и линия становится общей для всей строки фильтра. */
.admin-filter .field__input {
    height: 2.8rem;
}

/* Подпись — всегда в одну строку: перенос опустил бы поле под ней ниже соседнего. */
.admin-filter__field .field__label {
    white-space: nowrap;
}


/* --------------------------------------------------------------------------
   Заявка на возврат (/legal/return-request)
   -------------------------------------------------------------------------- */

/* Форму намеренно собираем из уже существующих .field / .field__input / .btn — она должна
   выглядеть ровно как оформление заказа, а не как отдельный бланк на чужом сайте. Здесь только
   то, чего в общих классах нет. */
.return-request-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    max-width: 620px;
    margin-top: var(--space-5);
}

/* Ловушка для роботов. Не display:none и не hidden: часть автоматов такие поля пропускает
   осознанно. Поле остаётся в потоке, но уводится за пределы экрана — для человека его нет,
   для наивного бота оно обычное. */
.return-request-form__trap {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.return-request-form__choice {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.return-request-form__choice legend {
    padding: 0 var(--space-2);
}

.return-request-form__choice label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
}

.return-request-form__details {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
}

.return-request-form__details summary {
    cursor: pointer;
    font-weight: 500;
}

.return-request-form__details[open] summary {
    margin-bottom: var(--space-3);
}

.return-request-form__consent {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    line-height: 1.6;
}

.return-request-form__consent input {
    margin-top: 0.25em;
    flex: none;
}

/* Подсказка в свёрнутом блоке реквизитов прижималась вплотную к первому полю — читалась как его
   подпись, а не как условие для всего блока. */
.return-request-form__details-hint {
    margin-bottom: var(--space-4);
}

/* Поля внутри details идут той же лесенкой, что и в основной форме. */
.return-request-form__details .field + .field {
    margin-top: var(--space-4);
}

/* Подпись над отключённым списком размеров гаснет вместе с ним: активная строка над серым полем
   читается как сбой вёрстки, а не как «здесь пока нечего выбирать». */
.field__label.is-disabled {
    opacity: 0.5;
}

/* Одной прозрачности мало: поле со своим фоном и рамкой всё равно читалось как рабочее. Гасим
   тремя признаками сразу — приглушённый текст, притопленный фон и пунктирная рамка. Пунктир здесь
   несёт смысл: сплошная рамка у соседних полей означает «сюда можно писать». */
.return-request-form__choice select:disabled {
    color: var(--color-text-muted);
    background-color: var(--color-bg-soft);
    border-style: dashed;
    opacity: 0.75;
    cursor: not-allowed;
}

/* Позиции заказа в заявке на возврат: человек узнаёт свою вещь по фото, а не вспоминает название. */
.return-items { display: flex; flex-direction: column; gap: var(--space-2); }

/*
  ДВЕ СТРОКИ, А НЕ ДВА СТОЛБЦА. Сначала было flex в одну линию — и колонка выбора занимала то,
  что осталось от названия: у «Футболки» переключатели стояли в одном месте, у «Лонгслива
  с контрастными швами» уезжали вправо и ломались на две строки. Фиксированная колонка это
  выровняла, но зажимала и название, и размеры.

  Теперь вещь читается сверху вниз, как её и рассказывают: первая строка — фотография, название
  и размер; вторая — что с ней сделать, во всю ширину. Одинаково у всех позиций независимо
  от длины названия, и размеры для обмена умещаются в один ряд.
*/
.return-item {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
}

/* Галочка, миниатюра и название — одной строкой. */
.return-item > label {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.return-item:has(input:checked) {
    border-color: var(--color-accent-dark);
    background: var(--color-bg-soft);
}

.return-item__img {
    width: 56px;
    height: 70px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    flex: none;
}

.return-item__text { line-height: 1.5; }

/* Размеры для обмена. Отсутствующий размер не прячем, а показываем зачёркнутым: человек должен
   видеть, что размер существует, но кончился, — иначе он решит, что ошибся сайтом. */
.return-sizes { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-3); }
/* Подпись начинается там же, где первый размер: 12 px — боковое поле «таблетки», то есть её
   прямая часть, а не скруглённый край. Иначе строка висела левее ряда и читалась отдельно
   от него. */
.return-sizes .field__label { flex-basis: 100%; margin: 0 0 var(--space-1) 12px; }

.return-size {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    cursor: pointer;
}

.return-size:has(input:checked) {
    border-color: var(--color-accent-dark);
    background: var(--color-bg-soft);
}

.return-size--out {
    opacity: 0.55;
    cursor: not-allowed;
    text-decoration: line-through;
    border-style: dashed;
}

/* Атрибут hidden обязан побеждать display из классов. Классическая ловушка: .return-sizes задаёт
   display:flex, .btn — inline-flex, и элемент с hidden всё равно остаётся на экране. Скрипт формы
   возврата полагается именно на hidden, поэтому здесь он усилен точечно. */
.return-sizes[hidden],
#return-find[hidden] {
    display: none;
}

/* Пояснение в скобках прямо в подписи: «Номер заказа (он есть в письме о заказе)». Размер и тон
   у него прежние, подписи не принадлежит — поэтому вес сбрасываем обратно. */
.field__label .field__hint--inline {
    display: inline;
    margin: 0;
    font-weight: 400;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

/* Подпись внутри свёрнутого блока реквизитов — того же веса, что и остальные подписи. */
.return-request-form__details-hint {
    color: #4A5866;
}

/* ССЫЛКИ В ТЕКСТЕ ПОДЧЁРКНУТЫ. Глобально у ссылок на сайте `text-decoration: none` и цвет
   наследуется — в меню и в подвале это правильно, там ссылка опознаётся по месту. Но в абзаце
   она становится невидимой: владелица не заметила, что «Заполните заявку на возврат» — ссылка.

   Подчёркивание здесь не украшение, а требование доступности: отличать ссылку одним цветом
   нельзя, дальтоник его не увидит. Линия работает всегда.

   Подчёркивание отодвинуто от текста и сделано тонким, чтобы не спорить с кириллическими
   выносными элементами (у «р», «у», «д» они уходят вниз и упираются в линию). */
.legal-page__section p a,
.legal-page__section li a,
.legal-page__note a,
.field__hint a {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.22em;
    text-decoration-color: rgba(31, 41, 51, 0.35);
}

.legal-page__section p a:hover,
.legal-page__section li a:hover,
.legal-page__note a:hover,
.field__hint a:hover {
    text-decoration-color: currentColor;
}
