/* ============================================================
   TinyFolder /next/ — v2 HERO ONLY.
   Loaded AFTER /styles.css; the rest of the page is byte-identical to
   the live site. This file styles the full-screen folder-style scene
   (headline → reactive-gradient 3D carousel → Dock) and nothing else.
   All scene classes are namespaced (nhero/nstage/ncard/ndock) so none
   of the live pinned-scene CSS can reach them.
   ============================================================ */

/* The nav is scene-driven on the live page (condense + reveal the CTA once
   the pinned scene scrolls by). There's no such scene here, so just keep the
   Download button visible in the bar the whole time. */
.nav__cta { max-width: 320px !important; opacity: 1 !important; pointer-events: auto !important; padding: 0 18px !important; }
/* the En↔Download gap is scene-driven too (opens on is-cta-on); keep it open */
.nav__right { gap: 12px !important; }

/* ---- full-screen scene container (exactly one screen) ---- */
.nhero {
  position: relative; width: 100%; height: 100svh; min-height: 560px;
  display: flex; flex-direction: column; align-items: center;
  overflow: hidden;
  /* Nothing in the first screen is selectable. Dragging the carousel is a
     press-and-move over text and images, which is exactly the gesture that
     starts a selection — so the first thing a visitor does here painted the
     whole scene blue. Applies to the section as a whole: the headline is a
     poster, not a passage to copy, and a half-selected hero looks broken in
     the same way. Buttons and links are unaffected. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
/* Images additionally refuse the native drag-the-picture gesture, which would
   otherwise tear a card out of the strip and follow the cursor as a ghost. */
.nhero img, .nhero canvas {
  -webkit-user-drag: none;
  user-select: none;
}
.nhero__bg { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; display: block; }
/* soft light veil over the top so the reactive gradient can't muddy the
   headline — the colour stays vivid down in the carousel band. */
.nhero::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 66%; z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg, #f6f7fa 8%, rgba(246,247,250,.82) 40%, rgba(246,247,250,0) 100%);
}

/* ---- 1 · headline — centred in the gap between the nav and the cards ---- */
.nhero__text {
  position: relative; z-index: 2; text-align: center; max-width: 720px;
  /* Bottom padding is the ACT BREAK. The words and the carousel are two
     different statements, and the gap between them has to be bigger than any
     gap inside either one — it was 19px, tighter than the 22 between the
     sub-headline and the buttons, so the scene read as a fourth line of the
     paragraph instead of as the thing being demonstrated. */
  /* 78, not 92: the nav BOX is 92 tall but the visible pill ends at 70, so
     the old value reserved 22px of nothing and then added its own gap on top.
     Measured from what the eye actually sees, the headline still sits ~34px
     clear — and the 14 saved goes to the carousel below. */
  /* Both paddings scale with the viewport HEIGHT. Fixed values fit a 900px
     screen and overflowed an 800px one — the column ran 22px past the fold
     and the headline ended up 8px under the menu. The vh terms shrink the
     air first, which is what should give way on a short screen. */
  /* The TOP is fixed: the nav pill ends at 70px on every screen, so this is a
     clearance, not a decoration, and it must not be the thing that gives way.
     A vh top padding shrank to 69.6 on an 800px screen and put the headline
     1px under the menu. Everything BELOW scales instead. */
  padding: 94px 24px clamp(20px, 4.4vh, 40px);
  pointer-events: none;
  flex: 1 1 auto;                          /* grow to fill the space above the carousel */
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
/* ── Two sizes in the hero ────────────────────────────────────────────────
   The headline, and everything else. What separates the rest is WEIGHT and
   COLOUR, never a point or two of size:

     bold + ink    the eyebrow, the buttons, the strip's labels
     medium + dim  the sub-headline, the strip's descriptions

   So the eyebrow is set like a button, each strip label is set like a
   button, and each strip description is set like the sub-headline — one
   voice for "this is a thing" and one for "this is what it does".

   The dim colour is NOT grey. A neutral grey over this blue-lilac gradient
   has no hue in common with anything around it, and that's exactly what
   reads as dirty — like white that got dusty. A desaturated slate-blue
   belongs to the scene, so it reads as quiet rather than soiled, at the
   same contrast. */
.nhero {
  --nh-body: clamp(14px, 1.6vw, 18px);
  /* Measured against the gradient, not picked by eye. The old grey came out
     at 1.8–2.5:1 over this background — below AA everywhere, which is part of
     why it read as dirty rather than quiet. This slate clears 4.5:1 over the
     whole sweep, including the saturated part the capability strip sits on. */
  --nh-dim: #4a5670;
}

.nhero__text .hero__eyebrow { justify-content: center; }
.nhero__text .hero__eyebrow span {
  font-size: var(--nh-body); font-weight: 700; letter-spacing: -.3px;
}
.nhero__text a { pointer-events: auto; }
.nhero__title {
  margin-top: 0;                          /* the eyebrow that this cleared has moved below the carousel */
  font-weight: 700; font-size: clamp(36px, 5.6vw, 68px); line-height: 1.03;
  letter-spacing: -.03em; color: var(--text);
  /* Even out the lines instead of filling each one and dropping whatever is
     left onto the last — that leftover is what hangs. The EN headline still
     carries its own <br>; balance takes over wherever a locale wraps freely. */
  text-wrap: balance;
}
.nhero__sub {
  margin: 20px auto 0; max-width: 640px;  /* 13 was tight under a 68px headline */
  font-weight: 500; font-size: var(--nh-body); line-height: 1.38; color: var(--nh-dim);
  text-wrap: balance;
}
/* The buttons already sat at 18 — pinned to the same token so they can't
   drift apart again. */
.nhero__text .hero__actions .btn { font-size: var(--nh-body); }
.nhero__text .hero__actions { margin-top: 28px; }

/* The line that closes the scene under the carousel. Set like a button, the
   same voice the eyebrow had upstairs — it IS the eyebrow, moved. */
.nhero__caption {
  justify-content: center; margin: 0;
  font-size: var(--nh-body); font-weight: 700; letter-spacing: -.3px; color: var(--text);
}
/* The dot takes the colour of the glow behind the cards — hero.js writes the
   live value into --nh-dot every time it actually changes. Falls back to the
   original green if the script never runs. Only inside the hero: the same dot
   on the live page stays green. */
.nhero__caption .hero__eyebrow-dot {
  background: var(--nh-dot, #4ee96d);
  /* The halo has to come from its own keyframes, not from a box-shadow
     declaration: the shared heroDotBreath animation paints the ring every
     frame with a hard-coded green, and an animation outranks any normal rule.
     Left alone, the dot would turn yellow inside a green glow. */
  animation-name: nheroDotBreath;
  /* Short on purpose: any interpolation between two hues passes through
     something muddy, so the crossing should be quick enough not to be read
     as a colour of its own. */
  transition: background .12s linear;
}
@keyframes nheroDotBreath {
  0%, 100% { box-shadow: 0 0 0 3px var(--nh-dot-halo, rgba(78, 233, 109, .32)); }
  50%      { box-shadow: 0 0 0 7px var(--nh-dot-halo-soft, rgba(78, 233, 109, .12)); }
}
@media (max-width: 900px) {
}

/* ---- 2 · reactive-gradient 3D carousel (fills the middle) ---- */
/* Short screens (a 13" laptop is 800 tall, and a browser eats ~90 of that).
   The vh terms alone weren't enough: the headline's own line-height doesn't
   scale, so the column still ran past the fold. Here the AIR gives way — the
   nav clearance and the act break stay legible, the band gives up height. */
/* Порог поднят с 860 до 960. Карточки стали крупнее, а отступы вокруг подписи
   сравнялись — колонка выросла, и на экране 900 px заголовок упёрся в меню,
   оставив 2 px вместо зазора. Уступать должен кегль заголовка: 68 px — самый
   крупный несжимаемый блок в колонке, и на невысоком экране он и так
   непропорционален. */
@media (max-height: 960px) {
  /* The headline is the biggest fixed block in the column — 68px over two
     lines is 140px of the ~800 available, and its line-height doesn't care
     how tall the window is. Trimming AIR to make room only starved the gaps;
     scaling the type is both what actually fits and what looks right, since a
     68px headline on a 13" screen is out of proportion anyway. */
  .nhero__title { font-size: clamp(32px, 4.4vw, 54px); }
  .nhero__text { padding-bottom: 26px; }
  .nstage { height: clamp(240px, 34vh, 360px); }
  .ndockwrap { padding-top: 40px; padding-bottom: 31px; }
}

.nstage {
  position: relative; z-index: 1; flex: 0 0 auto; width: 100%;
  /* 42vh made the column taller than the screen: text + band + caption came
     to more than 100svh, and since .nhero is a fixed height with overflow
     hidden, the excess was simply CUT off the bottom — which is why adding
     padding under the caption moved nothing, and why the headline ended up
     touching the nav. The band gives the height back instead. */
  height: clamp(260px, 36vh, 400px);      /* carousel band pinned to the bottom */
  perspective: 1700px; perspective-origin: 50% 50%;
  cursor: grab; touch-action: pan-y;
}
.nstage.dragging { cursor: grabbing; }
.ncards { position: absolute; inset: 0; transform-style: preserve-3d; }

.ncard {
  position: absolute; left: 50%; top: 50%;
  /* sized from the stage height in hero.js so it always fits one screen */
  width: var(--ncard-w, 250px); height: var(--ncard-h, 330px);
  border-radius: 28px; overflow: hidden;
  /* No preserve-3d here: the card holds no 3D children, and paired with
     overflow:hidden it makes clipping ambiguous — the picture is scaled up to
     hide the blur's soft edge and must be clipped by the rounded corners. The
     3D itself comes from the perspective on the stage above. */
  backface-visibility: hidden;
  /* Driven per frame: the shadow used to be blurred along with the card, and
     now that only the picture blurs it would stay crisp under a soft card and
     read as pasted on. It fades with distance instead. */
  box-shadow: 0 20px 48px rgba(16,17,20,var(--sh, .22));
  background: #e6e9ef;   /* neutral fill while the image decodes */
  --hue: 210;
}
/* real folder-style render, filling the whole card */
.ncard__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.ncard__glass {
  position: absolute; inset: 0;
  background:
    linear-gradient(165deg, hsla(var(--hue),95%,66%,.62), hsla(var(--hue),85%,48%,.42)),
    hsl(var(--hue), 62%, 88%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.7), inset 0 0 0 1px hsla(var(--hue),55%,62%,.55);
}
.ncard__glass::before {
  content: ""; position: absolute; left: -18%; top: -28%; width: 88%; height: 78%;
  background: radial-gradient(closest-side, rgba(255,255,255,.6), transparent 70%); filter: blur(6px);
}
.ncard__grid {
  position: absolute; inset: 0; z-index: 1;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 9%;
  padding: 15%; align-content: center;
}
.ncard__grid img { width: 100%; aspect-ratio: 1; border-radius: 24%; box-shadow: 0 4px 10px rgba(16,17,20,.18); }
.ncard__label {
  position: absolute; left: 0; right: 0; bottom: 13px; z-index: 2; text-align: center;
  font-weight: 800; font-size: 13px; letter-spacing: -.2px; color: #fff; text-shadow: 0 1px 6px rgba(0,0,0,.35);
}

/* ---- 3 · the Dock ---- */
/* The carousel is pinned to the BOTTOM of the screen — .nhero__text takes all
   the slack, so the band's position is set by how tall this closing block is,
   not by anything above it. Raising the slider therefore means giving the
   caption more room, which it wanted anyway: 20px under the cards had it
   clinging to them, and 52 at the very bottom left the whole scene sitting
   low in the frame. */
.ndockwrap {
  position: relative; z-index: 2; width: 100%;
  display: flex; flex-direction: column; align-items: center; gap: 15px;
  /* Отступы над подписью и под ней равны. Сверху было вдвое меньше, и строка
     висела под лентой, а не стояла между ней и краем экрана. Побочный
     полезный эффект: колонка над лентой (.nhero__text, flex:1) на столько же
     ужимается, то есть вся лента с папками поднимается выше. */
  /* Верх на ~10px больше низа — и получаются РАВНЫЕ видимые просветы.
     Отступ отмеряется от полосы .nstage, а центральная карточка нарочно
     выступает за неё вниз примерно на столько же: при одинаковых значениях
     сверху оставалось 58px против 68 снизу. */
  padding: clamp(32px, 7.6vh, 68px) 12px clamp(27px, 6.5vh, 58px);
}
.nhint { text-align: center; font-weight: 700; font-size: 13px; letter-spacing: -.2px; color: rgba(20,22,26,.42); pointer-events: none; }
.ndock {
  display: flex; align-items: flex-end; gap: 9px; max-width: 100%;
  padding: 9px 13px; border-radius: 26px;
  background: linear-gradient(180deg, rgba(255,255,255,.66), rgba(255,255,255,.44));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.9), 0 10px 30px rgba(16,17,20,.14), 0 0 0 1px rgba(16,17,20,.05);
  backdrop-filter: blur(18px) saturate(1.3); -webkit-backdrop-filter: blur(18px) saturate(1.3);
}
.ndock__ico, .ndock__tile {
  width: clamp(40px, 4vw, 54px); height: clamp(40px, 4vw, 54px); border-radius: 14px;
  transition: transform .18s cubic-bezier(.2,.8,.2,1);
}
.ndock__tile { box-shadow: 0 6px 16px rgba(59,158,255,.4); }
.ndock__ico:hover, .ndock__tile:hover { transform: translateY(-10px) scale(1.14); }
.ndock__sep { width: 1px; height: 44px; align-self: center; background: rgba(16,17,20,.14); margin: 0 3px; }

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

/* ---- closing trust strip (moved here from under the hero) ---- */
.factbar--end {
  margin-top: 0;                 /* was pulled up under the old hero scene */
  padding: 52px 24px;
  border-top: 1px solid rgba(18,18,18,.08);
}

/* more breathing room between the full-screen hero and the first section */
.nhero + .section { margin-top: 96px; }

/* ============ MOBILE ============ */
@media (max-width: 640px) {
  .nhero { height: auto; min-height: 100svh; }
  /* 82 put the headline right under the bar — on a phone the header is a
     full-width panel, not the floating island it becomes on scroll, so the
     words started where it ended and the two read as one block. */
  .nhero__text { padding: 110px 18px 0; max-width: 100%; }
  .nhero__title { font-size: clamp(27px, 7.8vw, 40px); }
  /* Move the TOKEN, not this one element: the sub and the buttons share it,
     and setting a size here alone put them 1px apart — the kind of difference
     that reads as a mistake rather than as a level. */
  .nhero { --nh-body: 15px; }
  .nhero__sub { margin-top: 11px; }
  /* ONE button on a phone (see index.html): a .dmg cannot be opened here, so
     both this and the floating one offer to email the link instead. */
  .nhero__text .hero__actions { margin-top: 22px; flex-wrap: wrap; gap: 10px; }
  .hero__actions-desktop { display: none; }
  .hero__mail { display: inline-flex; width: 100%; }
  .nstage { height: clamp(230px, 44vh, 350px); }
  /* push the strip below the fold (clear of the floating mobile Download button),
     which also gives the carousel → capabilities gap the user asked for */
  .ndockwrap { padding: 58px 14px 108px; }
  .nhero + .section { margin-top: 44px; }
}
