/* ==========================================================================
   АНКОМ — motion layer (all pages): reveals, curtain, side tab, parallax word
   Only transform/opacity are animated; everything is static without JS
   (html.js) and under prefers-reduced-motion (base.css kills durations).
   ========================================================================== */

/* ---------- Section reveal: children of [data-reveal] rise in with stagger ---------- */
html.js [data-reveal] > * {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}
html.js [data-reveal].is-in > *,
html.js [data-reveal]:focus-within > * { opacity: 1; transform: none; } /* keyboard focus never sits on invisible content */
/* an anchor target (contacts#write) sits in place at once: the browser scrolls to it as :target starts to match,
   and a card still 22px low would land under the header */
html.js [data-reveal] > :target { opacity: 1; transform: none; transition: none; }
[data-reveal] > :nth-child(2) { transition-delay: 0.07s; }
[data-reveal] > :nth-child(3) { transition-delay: 0.14s; }
[data-reveal] > :nth-child(4) { transition-delay: 0.21s; }
[data-reveal] > :nth-child(5) { transition-delay: 0.28s; }
[data-reveal] > :nth-child(6) { transition-delay: 0.35s; }
[data-reveal] > :nth-child(7) { transition-delay: 0.42s; }
[data-reveal] > :nth-child(8) { transition-delay: 0.49s; }
/* title lines slide up one by one (the title itself is not animated as a block) */
html.js [data-reveal] > .story__title { opacity: 1; transform: none; }
html.js [data-reveal] .story__line {
  opacity: 0;
  transform: translate3d(0, 110%, 0);
  transition: opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out);
}
html.js [data-reveal].is-in .story__line { opacity: 1; transform: none; }
[data-reveal] .story__line:nth-child(2) { transition-delay: 0.1s; }

/* ---------- Viewfinder corners: the four marks slide out to the frame edges when the block scrolls in
   (like the nav brackets). motion.js sets --frame-sx/-sy so every corner starts 22px inside. ---------- */
[data-frame] { position: relative; }
[data-frame]::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--viewfinder);
  pointer-events: none;
}
/* scroll-linked (motion.js sets --frame-k 0…1 per scroll frame; no transition, the scroll is the timeline).
   Without JS or before the first update the corners simply sit at the edges (fallback 1). */
html.js [data-frame]::after {
  opacity: min(1, calc(var(--frame-k, 1) * 2.5));
  transform: scale(calc(1 - (1 - var(--frame-sx, 0.95)) * (1 - var(--frame-k, 1))), calc(1 - (1 - var(--frame-sy, 0.95)) * (1 - var(--frame-k, 1))));
}

/* ---------- Word reveal («Про сервіс»): words brighten with scroll ---------- */
html.js [data-word-reveal] .w { opacity: 0.65; transition: opacity 0.25s; } /* dim state still ≥ 4.5:1 on --bg */
html.js [data-word-reveal] .w.is-on { opacity: 1; }

/* ---------- Page curtain (internal navigation) ---------- */
.curtain {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--bg);
  transform: scaleY(0);
  transform-origin: top;
  pointer-events: none;
}
html.is-entering .curtain { transform: scaleY(1); transform-origin: bottom; }
html.js .curtain.is-closing { transform: scaleY(1); transition: transform 0.28s var(--ease-out); }
html.js .curtain.is-opening { transform: scaleY(0); transform-origin: bottom; transition: transform 0.36s var(--ease-out); }

/* ---------- Vertical side tab (desktop): current model / section ---------- */
.side-tab {
  position: fixed;
  right: 14px;
  top: 50%;
  z-index: 50;
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--dim);
  writing-mode: vertical-rl;
  transform: translateY(-50%) rotate(180deg);
  opacity: 0;
  transition: opacity 0.35s;
  pointer-events: none;
}
.side-tab.is-on { opacity: 1; }
@media (max-width: 1599.98px) { .side-tab { display: none; } } /* narrower: it would crowd the content edge */

/* ---------- Header scroll state: the tagline fades, the wordmark drops to the centre of the logo box ---------- */
/* paired: the fade and the drop share duration and curve; 30 = (lockup − wordmark height) / 2 in logo units
   (build-logo.py --sprite); below 768 the tagline is hidden and the wordmark sits there anyway (base.css) */
.site-header .logo__sub { transition: opacity 0.25s var(--ease-out); }
.site-header .logo__word { transition: transform 0.25s var(--ease-out); }
html.is-scrolled .site-header .logo__sub { opacity: 0; }
html.is-scrolled .site-header .logo__word { transform: translate(0, 30px); }

/* ---------- Header logo: the shutter opens once the page has loaded (motion.js → html.is-logo-open) ---------- */
/* shut by default, then a slow slide to the logo's aperture; no JS or reduced motion — open from the start */
@media (prefers-reduced-motion: no-preference) {
  html.js .site-header .logo__blade { transition: transform 1.2s cubic-bezier(0.45, 0, 0.2, 1) 0.5s; } /* soft start and landing: a mechanism, not a pop; a beat after the load, so the eye catches it */
  html.js:not(.is-logo-open) .site-header .logo__blade { transform: translate(0, 0); }
  html.js.story-3d .site-header .logo__blade { transition-delay: 1.1s; } /* home: once the preloader's zoom (≈ 0.9 s) is over */
}

/* ---------- Footer wordmark: the letters rise, the iris turns in shut and opens to the logo's aperture ---------- */
/* motion.js adds .is-in when half of it is in view — once per page view */
@media (prefers-reduced-motion: no-preference) {
  html.js .site-footer__glyph { transition: opacity 0.6s var(--ease-out), transform 0.9s var(--ease-out); }
  html.js .site-footer__glyph:nth-of-type(2) { transition-delay: 0.08s; }
  html.js .site-footer__glyph:nth-of-type(3) { transition-delay: 0.16s; }
  html.js .site-footer__glyph:nth-of-type(4) { transition-delay: 0.32s; }
  html.js .site-footer__iris { transition: opacity 0.5s var(--ease-out) 0.24s, transform 1.3s cubic-bezier(0.2, 0.8, 0.2, 1) 0.24s; }
  html.js .site-footer__blade { transition: transform 0.9s var(--ease-out) 0.8s; }
  html.js .site-footer__wordmark:not(.is-in) .site-footer__glyph { opacity: 0; transform: translate(0, 36px); }
  html.js .site-footer__wordmark:not(.is-in) .site-footer__iris { opacity: 0; transform: rotate(-120deg) scale(0.7); }
  html.js .site-footer__wordmark:not(.is-in) .site-footer__blade { transform: translate(0, 0); } /* shut */
}

/* ---------- Rotating badge (first screen) ---------- */
.story__badge {
  position: absolute;
  right: var(--gutter);
  top: 28px;
  width: 112px;
  height: 112px;
  color: var(--text-3);
}
.story__badge svg { width: 100%; height: 100%; animation: badge-spin 40s linear infinite; }
.story__badge text { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: 0.1em; text-transform: uppercase; fill: currentColor; }
@keyframes badge-spin { to { transform: rotate(360deg); } }
@media (max-width: 1023.98px) { .story__badge { display: none; } }
html:not(.story-3d) .story__badge { display: none; }

/* ---------- Parallax outline word (CTA) ---------- */
.cta { position: relative; overflow: hidden; }
.cta__inner { position: relative; }
.cta__word {
  position: absolute;
  left: 50%;
  top: 50%;
  width: auto;
  height: clamp(90px, 16.5vw, 255px); /* the wordmark from the logo sprite, as tall as the old 22vw text's capitals */
  aspect-ratio: 487.8 / 104.2;
  overflow: visible;
  fill: none;
  stroke: var(--line-3);
  stroke-width: 1px; /* non-scaling (the sprite path): a hairline at any size */
  pointer-events: none;
  user-select: none;
  transform: translate(-50%, -50%);
}
@media (max-width: 767.98px) { .cta__word { top: 100%; } } /* phones: below the text, not through it (JS moves it by transform only) */
