body { margin: 0; background: var(--color-bg); }
  h1, h2, h3 { font-weight: var(--heading-weight, 700); zoom: var(--heading-zoom, 1); }
  a { color: var(--color-accent-700); text-decoration: none; }
  a:hover { color: var(--color-accent); }
  img { max-width: 100%; }
:root {
  --font-heading: Literata, serif;
  --font-body: Onest, sans-serif;
  --heading-weight: 600;
  --heading-zoom: 1;
}

/* interaction states lifted out of the canvas style-hover/style-active attributes */
.ix-1:hover { color:var(--color-accent-700); }
.ix-1:active { color:var(--color-accent-800); }
.ix-2:hover { background:var(--color-accent-600);color:var(--color-bg); }
.ix-2:active { background:var(--color-accent-700); }

/* official App Store badge — Apple's asset, used unmodified: only the whole
   thing fades on hover, nothing is recoloured or reshaped */
.badge { transition: opacity .15s ease; }
.badge:hover { opacity: .82; }
.badge:active { opacity: .7; }

/* The stamp heart sitting behind the hero phone. Decoration only: it fades at the
   edges instead of ending on a hard circle, and never catches a click.

   Geometry lives here rather than inline so there is one place to tune it. The
   offsets are percentages of the image's own box, which the browser resolves
   against its *used* size — worth the indirection, because `img { max-width:100% }`
   caps this one to the column long before the clamp() below reaches 780px. Heart
   and offset therefore shrink as one piece and the composition holds at every
   width. Tune it live: the panel in .heart-tuner.js loads on any local preview and
   hands you a replacement for the :root block. */
.stamp-heart {
  position: absolute;
  right: clamp(-120px, -6vw, -20px);
  top: clamp(-120px, -8vw, -60px);
  width: clamp(330px, 66vw, 780px);
  height: auto;
  pointer-events: none;
  opacity: .45;
  transform:
    translate(calc(var(--heart-x, 0) * 100%), calc(var(--heart-y, 0) * 100%))
    scale(var(--heart-scale, 1));
  transform-origin: 50% 50%;
  -webkit-mask-image: radial-gradient(circle at 50% 46%, #000 55%, transparent 79%);
          mask-image: radial-gradient(circle at 50% 46%, #000 55%, transparent 79%);
}
@media (max-width: 720px) {
  /* on a phone the heart is nearly as wide as the screen, so it steps back */
  .stamp-heart { opacity: .3; }
}

/* tuned values — replace this whole block with what the tuner's Copy CSS gives you */
:root {
  --heart-scale: 1.54;
  --heart-x: -0.161;   /* -90px at the ~556px the heart renders at on a desktop */
  --heart-y: 0.549;    /* +304px */
}

/* Баннер согласия на аналитику (assets/js/consent.js).
   Полоса внизу, а не модальное окно поверх страницы: посетитель пришёл читать
   про приложение, а не разбирать юридический вопрос, и первый экран должен
   остаться первым экраном. Поэтому же он ничего не перекрывает и не блокирует
   прокрутку — до ответа GA всё равно сидит в denied и cookie не ставит. */
.consent {
  position: fixed;
  left: max(16px, env(safe-area-inset-left));
  right: max(16px, env(safe-area-inset-right));
  bottom: max(16px, env(safe-area-inset-bottom));
  z-index: 50;
  max-width: 760px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px 22px;
  padding: 18px 22px;
  border-radius: 24px;
  background: var(--color-neutral-100);
  box-shadow: 0 18px 44px rgba(46, 43, 37, .22);
  /* появление снизу; в конечном состоянии выставляется классом .is-in */
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .24s ease, transform .24s ease;
}
.consent.is-in { opacity: 1; transform: none; }
.consent.is-leaving { opacity: 0; transform: translateY(14px); }

.consent-text {
  flex: 1 1 320px;
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-neutral-800);
  text-wrap: pretty;
}
.consent-text a { color: var(--color-accent-700); text-decoration: underline;
                  text-underline-offset: 2px }

.consent-actions { display: flex; gap: 10px; margin-left: auto }
.consent-actions .btn { font-size: 15px; padding: 10px 20px }

@media (max-width: 560px) {
  /* на телефоне кнопки уезжают на свою строку и делят её пополам,
     иначе «Accept» вытесняет «Decline» за край */
  .consent { border-radius: 20px; padding: 16px 18px }
  .consent-actions { width: 100%; margin-left: 0 }
  .consent-actions .btn { flex: 1 }
}

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

/* Адрес почты записан в разметке задом наперёд и разворачивается здесь
   (assets/js/email-cloak.js). Смысл в том, что без JS страница всё равно
   показывает читаемый адрес, а простой сборщик адресов в исходнике не
   находит ничего похожего на почту. */
.cloak-rtl { unicode-bidi: bidi-override; direction: rtl; }
