/* ==========================================================================
   СЛОВНОВЧЕРА — 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.woff2') format('woff2');
    font-weight: 300;
    font-style: normal;
    font-display: swap;
}

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

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

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

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

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

/* --------------------------------------------------------------------------
   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);
    --color-bg: var(--color-white);
    --color-bg-soft: var(--color-alabaster);
    --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);

    --font-heading: 'Onest', sans-serif;
    --font-body: 'Onest', 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;
}

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;
    }
}

.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-white);
}

/* 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;
}

/* 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-white);
    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%;
    background: var(--color-bg);
    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);
}

/* Faint brand-pattern watermark (emblem task, item 1): a seamless half-drop tile of tiny
   emblems (pattern.svg, already a muted butter tone) repeated behind the footer content at very
   low opacity so it reads as a quiet texture, never competing with the link/text contrast above
   it. `isolation: isolate` on .site-footer gives this ::before its own stacking context so the
   negative z-index only escapes back to *this* element's own background (not further behind the
   page), while every real child stays default-positioned and therefore paints on top of it
   automatically - no z-index bookkeeping needed on the footer's own markup. */

.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: 32ch;
}

/* "Будьте на связи" + 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);
}

.site-footer__newsletter-title {
    font-family: var(--font-heading);
    font-weight: 400;
    font-size: 1.05rem;
    margin-bottom: 0;
}

/* 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. */
.site-footer__newsletter .newsletter-form {
    flex-direction: column;
    align-items: stretch;
    max-width: 340px;
    gap: var(--space-3);
}

.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%;
}

.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);
}

.site-footer__contacts-panel {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.3s ease;
}

.site-footer__contacts-panel.is-open {
    max-height: 520px;
}

/* 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;
    line-height: 1.5;
}

.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);
    margin-top: var(--space-3);
}

.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);
}

/* Star footnote marker sitting just above the Instagram icon (ties it to the "*" disclaimer). */
.site-footer__social-link--ig {
    position: relative;
    overflow: visible;
}

.site-footer__social-star {
    position: absolute;
    top: -5px;
    right: -3px;
    color: var(--color-camel);
    pointer-events: none;
}

.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-white);
    padding: var(--space-2);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
}

.site-footer__bottom {
    margin-top: var(--space-7);
    padding-block: var(--space-4);
    border-top: 1px solid var(--color-border);
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

.site-footer__disclaimer {
    margin-bottom: var(--space-2);
    font-size: 0.72rem;
    line-height: 1.5;
    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-white);
}

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

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

.card,
.collection-card {
    display: block;
    background: var(--color-white);
    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: 46ch;
    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: 68ch;
}

.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);
}

/* Faint brand-pattern watermark (emblem task, item 1) - same technique as .site-footer::before
   above: isolated stacking context + negative z-index so the tile sits just above this section's
   own butter background and below its (default-positioned) heading/copy/form. border-radius:
   inherit keeps the tile from poking past the section's rounded corners. */

/* --------------------------------------------------------------------------
   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);
}

.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: 70ch;
}

.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-6);
}

/* Lighter, less "heavy/rough" category title: Unbounded at its regular weight (not the bold 700
   the global h1 uses) with a touch of negative tracking reads calmer and more modern. */
.catalog__header h1 {
    font-weight: 400;
    letter-spacing: -0.01em;
}

.catalog__description {
    color: var(--color-text-muted);
    max-width: 60ch;
}

/* 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-white);
}

.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;
    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-white);
}

.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: 68ch;
    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;
    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-white);
    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-white);
}

/* 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%);
}

.welcome-modal__body .brand-emblem {
    width: 44px;
    color: var(--color-payne-gray);
}

.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-white);
    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-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: 30ch;
    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);
}

/* Error pages (404/500): emblem above the big code. */
.error-page .brand-emblem {
    width: 54px;
    margin: 0 auto var(--space-4);
    color: var(--color-accent);
}

/* 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);
}

/* Faint brand-pattern watermark (emblem task, item 1) - same isolated-stacking-context +
   negative-z-index technique used on the footer/newsletter/welcome-modal above, applied here to
   the empty-cart state so it reads as a quiet textured "nothing here yet" surface rather than a
   blank void. No extra padding added (kept 0 horizontal, matching the container's own gutter) so
   the copy/CTA stay exactly where they were before this pattern was layered in behind them. */

.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);
}

.cart-summary {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--space-5);
    background: var(--color-bg-soft);
    border-radius: var(--radius-md);
}

.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-white);
}

.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 {
    margin-bottom: var(--space-6);
}

.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);
}

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

.field__input {
    width: 100%;
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-white);
    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-white);
    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: flex;
    align-items: flex-start;
    gap: var(--space-3);
    font-size: 0.95rem;
}

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

/* --------------------------------------------------------------------------
   "Адрес и способ доставки" 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 {
    font-size: 0.9rem;
    color: var(--color-text-muted);
}

.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 {
    width: 100%;
    text-align: left;
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-white);
    font-family: var(--font-body);
    font-size: 0.9rem;
}

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

/* Согласия 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%;
}

.checkout-summary__line {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    font-size: 0.9rem;
}

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

/* Keep the quantity and price on one line each (a long name/variant must not squeeze them into
   a broken "1 / 990 / ₽" stack). */
.checkout-summary__line-qty,
.checkout-summary__line-price {
    flex: 0 0 auto;
    white-space: nowrap;
}

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

.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);
}

/* Faint brand-pattern watermark (emblem task, item 1) - same isolated-stacking-context +
   negative-z-index technique as the other surfaces above, given a touch more presence here
   (0.1 vs the 0.08 used elsewhere) since "Спасибо за покупку!" is meant to feel a little more
   celebratory than a quiet empty-state or footer - still well within the "never hurts legibility"
   range the rest of the copy on this page relies on. */

.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: 46ch;
}

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

.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-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.admin-table th,
.admin-table td {
    text-align: left;
    padding: var(--space-3);
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
}

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

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

.admin-table__actions {
    display: flex;
    align-items: center;
    gap: 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: 70ch;
}

.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;
}

/* --------------------------------------------------------------------------
   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: 40ch;
    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 (no white gaps top/bottom), 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;
}

.about-story__media {
    margin: 0;
    line-height: 0;
}

.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);
    text-align: left;
    padding: var(--space-6) var(--space-4);
}

.about-story__eyebrow {
    display: block;
    margin-bottom: var(--space-1);
}

.about-story__lede,
.about-story__text p {
    color: var(--color-text-muted);
}

.about-story__lede {
    color: var(--color-text);
}

/* Desktop: two columns. 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 edge-to-edge and ends exactly level with
   the story - no white gaps above or below it. */
@media (min-width: 900px) {
    .about-story__grid {
        display: grid;
        grid-template-columns: minmax(0, 0.92fr) minmax(0, 1fr);
        align-items: stretch;
        max-width: 1280px;
        margin-inline: auto;
    }

    .about-story__media {
        height: 100%;
    }

    .about-story__media img {
        height: 100%;
    }

    .about-story__text {
        justify-content: center;
        max-width: 60ch;
        padding: clamp(var(--space-6), 4vw, var(--space-8)) clamp(var(--space-5), 4vw, var(--space-7));
    }
}

/* 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 {
    margin-top: var(--space-6);
    text-align: center;
    background: var(--color-beige);
    padding: var(--space-6) clamp(var(--space-3), 2vw, 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: 1520px;
    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);
}

.about-values .usp__item {
    text-align: left;
    padding-inline: var(--space-3);
}

.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 {
    font-weight: 500;
    font-size: 1.05rem;
    margin-bottom: var(--space-3);
    text-align: center;
}

.about-values .usp__item p {
    line-height: 1.65;
    color: var(--color-text-muted);
    text-align: justify;
}

@media (max-width: 767px) {
    .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);
    }
}

/* 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;
    margin: 0;
    line-height: 0;
}

.about-work img {
    width: 100%;
    aspect-ratio: 4 / 4.4; /* slightly shorter than the old 4/5 - trims the band's height a touch */
    object-fit: cover;
    display: block;
    filter: saturate(0.94) contrast(0.98);
}

/* 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;
}

/* --------------------------------------------------------------------------
   Legal pages (Task 14): one shared template for /legal/privacy, /legal/terms, /legal/returns.
   -------------------------------------------------------------------------- */

.legal-page {
    padding-block: var(--space-7);
    max-width: 70ch;
}

.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__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. */
.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-white);
    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 */
}

.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: 50ch;
}

/* --------------------------------------------------------------------------
   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 {
    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);
}

/* Faint brand-pattern watermark (emblem task, item 1) - same technique as .cart-empty::before
   above (mirrors the empty-cart state, since both are the same "nothing here yet" pattern). */

/* 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);
    }

    .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: 1fr 320px;
        gap: var(--space-7);
    }

    .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;
    }
}

/* --------------------------------------------------------------------------
   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-white);
    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(400px, 92vw);
    display: flex;
    flex-direction: column;
    background: var(--color-white);
    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);
}

.cart-drawer__title {
    font-weight: 400;
    font-size: 1.2rem;
}

.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: 64px 1fr auto;
    gap: var(--space-3);
    align-items: start;
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--color-border);
}

.cart-drawer__thumb img {
    width: 64px;
    height: 80px;
    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: 0.9rem;
}

.cart-drawer__variant {
    font-size: 0.8rem;
    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-white);
}

.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);
}

/* ============================================================================
   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-white);
    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-white);
    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: var(--color-bg-tint-blue); }
.admin-status-badge--delivered { color: #4a7050; }
.admin-status-badge--cancelled { color: #c0504d; }

.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: #fff;
        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-white);
    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;
}
