/* mirusha public — warm boutique, not a marketplace.
   One accent color, used in exactly two places: the Wildberries button and an
   active search field. Everything else stays quiet on purpose.

   Not one inline style= exists anywhere in this project's templates — that is
   what makes the strict `style-src 'self'` CSP possible. See web/csrf.py. */

:root {
  /* This site has no dark palette of its own — without this, a browser in
     OS dark mode still dark-styles native controls (the search input's
     chrome, the scrollbar) while everything else stays on the light warm
     theme, which is what made the page look broken/harsh at night. */
  color-scheme: light;

  --bg: #faf6ee;
  --surface: #ffffff;
  --border: #e7ded0;
  --text: #2b2621;
  --text-muted: #7d7267;
  --accent: #6b7355;          /* dusty olive — WB button + active search ONLY */
  --accent-ink: #ffffff;
  --sold-bg: #eeeae0;
  --sold-text: #635a4e;

  --font-display: 'Alice', Georgia, 'Times New Roman', serif;
  --font-body: 'Golos Text', -apple-system, 'Segoe UI', Roboto, sans-serif;

  --radius: 14px;
  --radius-sm: 8px;
  --tap: 44px;

  --gutter: clamp(16px, 4vw, 40px);
  --content-max: 1280px;

  /* The sliver of the next row visible below the fold on load. Must stay well
     under the shortest card height at every breakpoint, or the "crop" reads
     as a whole short card instead of a hint to scroll. See CLAUDE.md. */
  --peek: clamp(72px, 12vh, 160px);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 var(--font-body);
  -webkit-font-smoothing: antialiased;
}

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

a { color: inherit; }

.font-display {
  font-family: var(--font-display);
  /* Alice ships weight 400 only — without this the browser fake-bolds it,
     which looks worse than just staying regular. */
  font-synthesis: none;
}

.page {
  max-width: var(--content-max);
  margin: 0 auto;
  padding-inline: var(--gutter);
}

/* ── Hero ─────────────────────────────────────────────────────────────────
   The whole "cropped first row" effect lives in one property: the height
   unit. 100vh is measured against the LARGE mobile viewport (address bar
   hidden) — on load, with the bar visible, the hero overflows the visible
   area and the peeking row vanishes entirely under the fold. 100dvh is worse:
   it recalculates as the bar collapses, so the layout jumps mid-scroll,
   exactly when the trick is supposed to fire. 100svh is the SMALL viewport
   (bar assumed visible) and never recalculates — the peek is guaranteed
   visible on first paint. The vh line is a fallback for browsers without svh
   support and must stay first. */
.hero {
  display: flex;
  align-items: center;
  min-height: calc(100vh - var(--peek));
  min-height: calc(100svh - var(--peek));
  border-bottom: 1px solid var(--border);
  background-color: var(--bg);
  background-image: url('/static/hero-linework.webp');
  background-repeat: no-repeat;
  background-size: cover;
  /* The artwork's illustrated items sit in its left and right thirds with a
     calm empty middle for the title. A narrow/tall hero crops most of the
     width away under cover-fit, so below 900px anchor left — that keeps the
     dress-and-florals cluster in frame instead of showing just blank middle. */
  background-position: 15% center;
}

@media (min-width: 900px) {
  .hero {
    background-position: center;
  }
}

.hero__inner {
  width: 100%;
  padding-block: 48px;
  text-align: center;
}

/* A quiet entrance for the hero on load — title, tagline, and search settle
   in one after another instead of all snapping in at once. Scoped inside
   prefers-reduced-motion: no-preference, so it simply never runs (elements
   render at their normal opacity) for anyone who's asked the OS for less
   motion, rather than needing a separate "undo the animation" rule. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes hero-rise {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: none; }
  }

  .hero__inner > * {
    animation: hero-rise 0.6s ease both;
  }

  .hero__inner > *:nth-child(1) { animation-delay: 0s; }
  .hero__inner > *:nth-child(2) { animation-delay: 0.1s; }
  .hero__inner > *:nth-child(3) { animation-delay: 0.2s; }
  .hero__inner > *:nth-child(4) { animation-delay: 0.3s; }
}

.hero__title {
  margin: 0 0 12px;
  font-size: clamp(34px, 7vw, 58px);
  font-weight: 400;
  letter-spacing: 0.01em;
}

.hero__tagline {
  margin: 0 auto 32px;
  max-width: 42ch;
  color: var(--text-muted);
  font-size: clamp(15px, 2vw, 18px);
}

/* ── Search ───────────────────────────────────────────────────────────────── */
.search {
  max-width: 420px;
  margin: 0 auto;
}

.search__input {
  width: 100%;
  min-height: var(--tap);
  padding: 10px 16px;
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  text-align: center;
  transition: border-color 0.15s ease;
}

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

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

/* The one other spot the accent is allowed: a non-empty query gets a visibly
   "live" field, so typing feels connected to the counter below it. */
.search__input.is-active {
  border-color: var(--accent);
}

.search__count {
  margin: 12px 0 0;
  color: var(--text-muted);
  font-size: 14px;
}

/* ── Grid ─────────────────────────────────────────────────────────────────── */
.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px 12px;
  padding-block: 28px 56px;
}

@media (min-width: 600px) {
  .grid { grid-template-columns: repeat(3, 1fr); gap: 24px 20px; }
}

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

.state-message {
  padding: 64px var(--gutter) 96px;
  text-align: center;
  color: var(--text-muted);
  font-size: 16px;
}

.link-btn {
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

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

/* ── Card ─────────────────────────────────────────────────────────────────── */
.card {
  display: flex;
  flex-direction: column;
  /* Grid items default to a content-based minimum width, so a long
     white-space:nowrap title (.card__title) would otherwise force its whole
     column wider than its 1fr share instead of ellipsis-truncating — which
     is what desynced the columns and made every card, and every button
     inside it, a different width. */
  min-width: 0;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

/* :focus-within, not just :hover — a keyboard user tabbing to the carousel
   arrows or the WB link gets the same lift a mouse hover would. */
.card:hover,
.card:focus-within {
  transform: translateY(-4px);
  box-shadow: 0 16px 28px -8px rgba(43, 38, 33, 0.16);
}

@media (prefers-reduced-motion: reduce) {
  .card, .card:hover, .card:focus-within { transition: none; transform: none; }
}

.card[hidden] { display: none; }

/* The aspect ratio lives on the OUTER box, not the slides, so a product with
   zero photos yet still reserves the same 3:4 footprint (muted background,
   no broken layout) instead of collapsing to nothing. */
.card__media {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--sold-bg);
}

.card__track {
  position: absolute;
  inset: 0;
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.card__track::-webkit-scrollbar { display: none; }

.card__slide {
  flex: 0 0 100%;
  height: 100%;
  scroll-snap-align: start;
}

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

.card__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 999px;
  background: rgba(43, 38, 33, 0.45);
  color: #fff;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.card__nav:hover { background: rgba(43, 38, 33, 0.65); }

.card__nav:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.card__nav--prev { left: 8px; }
.card__nav--next { right: 8px; }

.card__badge {
  position: absolute;
  top: 10px;
  left: 10px;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--sold-text);
  color: #fff;
  font-size: 12px;
  letter-spacing: 0.02em;
}

/* Grid stretches every card in a row to the tallest card's height, but that
   only grows .card's own box — the content inside still stacks top-down and
   stops wherever it stops. .card__body has to be a flex column that GROWS
   into that extra space, or the button lands at a different height on every
   card depending on how many optional fields are showing. */
.card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding-top: 12px;
}

.card__index {
  display: block;
  margin: 0 0 2px;
  color: var(--text-muted);
  font-size: 13px;
  letter-spacing: 0.02em;
}

.card__title {
  margin: 0 0 6px;
  font-size: 15px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card__price {
  margin: 0 0 6px;
  font-size: 17px;
  font-weight: 600;
}

.card__price-old {
  margin-left: 8px;
  color: var(--text-muted);
  font-size: 14px;
  font-weight: 400;
  text-decoration: line-through;
}

.card__attr {
  margin: 0 0 4px;
  color: var(--text-muted);
  font-size: 13px;
}

.card__attr-label { color: var(--text); }

.card__attr--description {
  white-space: pre-line;
}

.card__cta {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  /* auto, not a fixed value: this is what pins the button to the bottom of
     .card__body's now-stretched box, so it lines up across a row regardless
     of how many optional fields a given card is showing above it. */
  margin-top: auto;
  padding: 10px 16px;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-weight: 600;
  text-align: center;
  text-decoration: none;
  transition: filter 0.15s ease;
}

.card__cta:hover { filter: brightness(1.06); }

.card__cta:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

/* Sold: the button stays clickable (the listing may still be worth a look)
   but deliberately loses the accent — the one color on the page means
   "available and actionable", and a sold card is neither. */
.card--sold .card__cta {
  background: var(--sold-bg);
  color: var(--sold-text);
}

/* One button per size link instead of the single CTA above — same bottom
   pin, same accent, just wrapped so any count of sizes reads as a short
   row (or two) rather than a column. */
.card__sizes {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: auto;
}

.card__size-link {
  display: flex;
  flex: 1 1 calc(50% - 3px);
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-weight: 600;
  font-size: 14px;
  text-align: center;
  text-decoration: none;
  transition: filter 0.15s ease;
}

.card__size-link:hover { filter: brightness(1.06); }

.card__size-link:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

.card--sold .card__size-link {
  background: var(--sold-bg);
  color: var(--sold-text);
}

/* One card on its own, inside the admin edit page's preview iframe. Same
   stylesheet as the real site on purpose — the preview must be the actual
   rendered card, so anything that changes above changes the preview too. */
.card-preview {
  max-width: 300px;
  padding: 0;
}

/* Only the CTA is dead in the preview. It points at /go/{id}, which exists on
   the public app alone — clicking it from the admin panel would 404 for no
   reason. Everything else (the carousel arrows, the swipe track) stays live so
   the preview behaves like the real card she is looking at. Killing pointer
   events on the whole .card-preview instead would freeze the carousel too. */
.card-preview .card__cta,
.card-preview .card__size-link { pointer-events: none; }

/* ── Footer ───────────────────────────────────────────────────────────────── */
.site-footer {
  padding: 28px var(--gutter) 40px;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 13px;
  text-align: center;
}

.site-footer p {
  margin: 0;
}

.site-footer__contact {
  margin-top: 6px;
}

.site-footer__contact a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.site-footer__contact a:hover {
  color: var(--text);
}

/* The registry numbers are legally required but not what anyone came to read;
   the note below them is genuinely useful. Both stay quieter than the contact
   line so the footer does not compete with the catalogue above it. */
.site-footer__note {
  margin-top: 10px;
  font-size: 12px;
  opacity: 0.8;
}
