/* ============================================================
   MODULE - hero_light (.zd-hero--split-full)
   Ported from the design drop 2026-08-25 (hero-light.css).

   NUMBERING: the editor sees V4 (compact) and V5 (full-screen), continuing this
   site's own v1-v3 sequence. The drop calls the same two V4 and V6 — that is the
   design system's numbering, in which V5 is a separate full-screen treatment
   that was never shipped here. Comments below keep the drop's V4/V6 wording so
   they still line up with the source files; only the editor labels differ.
   The drop ships the design system's own `sp-` prefix; this repo is
   normalised to `zd-`, so classes and custom properties were renamed
   1:1 on import. Every token it relies on already exists in
   zd-blocks.css under --zd-, including --zd-header-h and --zd-tint-2.
   Loads AFTER zd-blocks.css. No new design tokens.
   ============================================================ */

/* ============================================================
   Zdorovo — Hero, light split variants (V4 / V6)
   Drop-in stylesheet. Depends only on existing tokens:
   --surface, --surface-page, --zd-line, --zd-tint, --zd-tint-2,
   --zd-accent, --zd-accent-strong, --zd-muted, --zd-text, --ink-500,
   --zd-container, --radius-md, --zd-header-h.
   Nothing here overrides an existing selector — all names are new
   except the three .zd-hero__scroll helpers below, which are additive
   modifiers on the existing scroll hint.
   ============================================================ */

/* light-on-white scroll hint, sitting in its own band rather than over the photo */
.zd-hero__scroll--dark { position: relative; left: auto; bottom: auto; transform: none; color: var(--zd-muted); display: flex; width: fit-content; margin: 0 auto; gap: 8px; font-size: 11px; letter-spacing: .12em; }
.zd-hero__scrollband { background: var(--surface); border-top: 1px solid var(--zd-line); padding: 20px 0 26px; }
.zd-hero__scroll-ring--dark { border-color: var(--zd-line); color: var(--ink-500); }

/* LOCAL ADDITION — the mirror is a switch, not a given.
   The drop mirrors the photo unconditionally, so an editor has to remember to
   upload the subject on the LEFT for it to appear on the right. That is easy to
   get wrong and impossible to correct from the admin, so it is now a field.
   Driven by a custom property rather than an override, because the flip is
   composed into several transforms — including inside @keyframes, where a
   plain override could not reach. Custom properties resolve against the
   animated element, so the keyframes pick this up for free.
   Default -1 keeps the drop's behaviour for anything already set up. */
.zd-hero--split-full { --zd-flip: -1; }
.zd-hero--split-full.is-photo-unflipped { --zd-flip: 1; }

/* ---- V4 — light full-screen split: copy left, full-bleed photo right, stat rail + scroll hint ---- */
.zd-hero--split-full { display: block; background: var(--surface-page); overflow: visible; }
.zd-hero__split-top { position: relative; display: grid; grid-template-columns: 1fr; min-height: clamp(340px, 32vw, 640px); overflow: hidden; background: var(--surface-page); }
.zd-hero__split-scrim { position: absolute; top: 0; bottom: 0; left: max(24px, calc((100vw - var(--zd-container, 1180px)) / 2 + 24px)); right: max(24px, calc((100vw - var(--zd-container, 1180px)) / 2 + 24px)); z-index: 1; background: linear-gradient(90deg, var(--surface-page) 0%, var(--surface-page) 26%, rgba(247,248,249,.82) 42%, rgba(247,248,249,.35) 58%, rgba(247,248,249,0) 74%); pointer-events: none; }
/* soften the photo behind the copy: a masked blur layer under the light scrim, fading out to the right */
.zd-hero__split-blur { position: absolute; top: 0; bottom: 0; left: max(24px, calc((100vw - var(--zd-container, 1180px)) / 2 + 24px)); right: max(24px, calc((100vw - var(--zd-container, 1180px)) / 2 + 24px)); z-index: 1; backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); mask-image: linear-gradient(90deg, #000 0, #000 26%, rgba(0,0,0,.45) 42%, transparent 58%); -webkit-mask-image: linear-gradient(90deg, #000 0, #000 26%, rgba(0,0,0,.45) 42%, transparent 58%); pointer-events: none; }
.zd-hero--split-vh .zd-hero__split-blur { left: 0; right: 0; }
.zd-hero__split-copy { position: relative; z-index: 2; display: flex; align-items: center; padding: 44px 0 52px; }
.zd-hero__split-copy .zd-hero__h1 { max-width: 540px; }
.zd-hero__split-copy > .zd-container { max-width: var(--zd-container); }
.zd-hero__split-copy .zd-hero__lead { margin-top: 14px; }
.zd-hero__reassure { list-style: none; margin: 24px 0 0; padding: 0; display: flex; flex-direction: column; gap: 11px; max-width: 520px; }
.zd-hero__reassure-item { display: flex; align-items: flex-start; gap: 12px; }
.zd-hero__reassure-ico { flex: none; width: 26px; height: 26px; border-radius: 50%; background: var(--zd-tint-2); color: var(--zd-ok, var(--zd-accent-strong)); display: inline-flex; align-items: center; justify-content: center; }
.zd-hero__reassure-ico svg { width: 15px; height: 15px; }
.zd-hero__reassure p { margin: 0; font-size: 15px; line-height: 1.5; color: var(--zd-text); }
.zd-hero__split-media { position: absolute; top: 0; bottom: 0; left: max(24px, calc((100vw - var(--zd-container, 1180px)) / 2 + 24px)); right: max(24px, calc((100vw - var(--zd-container, 1180px)) / 2 + 24px)); z-index: 0; margin: 0; overflow: hidden; mask-image: linear-gradient(90deg, #000 0, #000 76%, rgba(0,0,0,.55) 90%, transparent 100%); -webkit-mask-image: linear-gradient(90deg, #000 0, #000 76%, rgba(0,0,0,.55) 90%, transparent 100%); }
/* full-screen variant (V6): photo spans the whole viewport width */
.zd-hero--split-vh .zd-hero__split-media, .zd-hero--split-vh .zd-hero__split-scrim { left: 0; right: 0; }
.zd-hero--split-vh .zd-hero__split-media { mask-image: none; -webkit-mask-image: none; }
/* nudge the crop upward a touch in the taller V6 frame */
.zd-hero--split-vh .zd-hero__split-media img { object-position: 58% 28%; transform: scaleX(var(--zd-flip, -1)) scaleY(.94); transform-origin: top center; }
/* the vertical zoom-out leaves a sliver at the bottom only — fade the photo out into the page there */
.zd-hero--split-vh .zd-hero__split-media { mask-image: linear-gradient(180deg, #000 0, #000 82%, transparent 100%); -webkit-mask-image: linear-gradient(180deg, #000 0, #000 82%, transparent 100%); }
@media (max-width: 919px) {
  /* phones: full-bleed, no shrink and no fade (outranks the .zd-hero--split-vh rules above) */
  .zd-hero--split-vh .zd-hero__split-media { mask-image: none; -webkit-mask-image: none; }
  .zd-hero--split-vh .zd-hero__split-media img { transform: scaleX(var(--zd-flip, -1)); }
  .is-anim-b.zd-hero--split-vh .zd-hero__split-media img { --zd-rest: scaleX(var(--zd-flip, -1)); }
}
.zd-hero__split-media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 58% center; transform: scaleX(var(--zd-flip, -1)); }

/* LOCAL ADDITION — how strongly the photo is veiled, as a field.
   The drop fixes the mobile veil at .9 → .74 → .42, which is tuned for a busy
   photo; a calm one ends up washed out with no way to say so from the admin.
   Scaling the whole layer keeps the gradient's SHAPE — strongest at the top
   where the headline sits, lightest at the bottom — so turning it down reveals
   more photo without ever putting text over the busiest part of it. The blur
   scales with it, or a 4px backdrop-filter at full strength under a faded veil
   would read as a mistake rather than a lighter touch.

   --zd-scrim-eff is the value everything actually uses. It is 1 here and only
   picks up the configured setting inside the mobile query below, so the inline
   property on the header cannot leak the mobile value onto desktop. Declared
   BEFORE that query: same specificity, so source order decides.
   Default 1 is exactly the drop's look — nothing already set up moves. */
.zd-hero--split-full { --zd-scrim-eff: 1; }
.zd-hero__split-scrim,
.zd-hero__split-blur { opacity: var(--zd-scrim-eff, 1); }

@media (max-width: 919px) {
  .zd-hero__split-scrim { background: linear-gradient(180deg, rgba(247,248,249,.9) 0%, rgba(247,248,249,.74) 52%, rgba(247,248,249,.42) 100%); }
  .zd-hero__split-copy .zd-hero__h1 { max-width: none; }
  .zd-hero__reassure { max-width: none; }
  /* full-bleed photo on phones — the container inset would leave white strips down both edges */
  .zd-hero__split-media, .zd-hero__split-scrim, .zd-hero__split-blur { left: 0; right: 0; }
  .zd-hero__split-media { mask-image: none; -webkit-mask-image: none; }
  .zd-statrail__row { row-gap: 18px; }
  .is-stats-rules .zd-statrail__item:nth-child(odd) { border-left: 0; padding-left: 0; }

  /* the only place the configured veil takes effect */
  .zd-hero--split-full { --zd-scrim-eff: var(--zd-scrim-mobile, 1); }

  /* LOCAL ADDITION — no scroll hint on phones. Scrolling is the obvious gesture
     on a touch screen, so the band was spending a bordered, padded strip of a
     small viewport telling people something they already know.
     The whole band goes, not just the button, so its padding and top border go
     with it rather than leaving an empty rule. */
  .zd-hero__scrollband { display: none; }
}
.zd-hero--split-vh { display: flex; flex-direction: column; min-height: calc(100vh - var(--zd-header-h, 0px)); }
.zd-hero--split-vh .zd-hero__split-top { flex: 1 1 auto; min-height: 0; }
.zd-hero__statrail { border-top: 1px solid var(--zd-line); background: linear-gradient(90deg, var(--zd-tint) 0%, var(--surface-page) 60%); }
.zd-statrail__row { display: grid; grid-template-columns: repeat(2, 1fr); padding: 22px 0; }
.zd-statrail__item { position: relative; padding: 2px 20px 2px 18px; }
/* A · bars — green accent bar at the left of each stat (default) */
.is-stats-bars .zd-statrail__item::before { content: ""; position: absolute; left: 0; top: 2px; bottom: 4px; width: 3px; border-radius: 2px; background: var(--zd-accent); }
/* B · rules — hairline dividers between stats, no bar */
.is-stats-rules .zd-statrail__item { padding: 2px 20px; border-left: 1px solid var(--zd-line); }
.is-stats-rules .zd-statrail__item:first-child { border-left: 0; padding-left: 0; }
/* C · cards — each stat in its own light card */
/* DEAD RULE, kept verbatim from the drop. It targets a bare `.zd-statrail`, but
   neither the drop's own reference markup nor this repo's partial ever emits
   that class — the rail wrapper is `.zd-hero__statrail`. So the intended effect
   (flatten the rail's green-tinted gradient to plain page grey behind the cards
   and chips, which carry their own surfaces) never applied — not in the mockup
   that was reviewed either. Left inert rather than silently corrected, because
   fixing the selector would change the approved appearance. To enable it,
   change `.zd-statrail` to `.zd-hero__statrail` on this line and line 83+. */
.is-stats-cards .zd-statrail { background: var(--surface-page); }
.is-stats-cards .zd-statrail__row { gap: 12px; padding: 18px 0 22px; }
.is-stats-cards .zd-statrail__item { padding: 14px 16px; background: var(--surface); border: 1px solid var(--zd-line); border-radius: var(--radius-md, 12px); box-shadow: 0 1px 2px rgba(16,24,40,.04); }
/* D · chips — compact inline pills, left-aligned rather than a 4-up grid */
.is-stats-chips .zd-statrail { background: var(--surface-page); }
.is-stats-chips .zd-statrail__row { display: flex; flex-wrap: wrap; gap: 10px; padding: 18px 0 22px; }
.is-stats-chips .zd-statrail__item { display: flex; align-items: baseline; gap: 7px; padding: 9px 14px; background: var(--zd-tint); border: 1px solid var(--zd-line); border-radius: 999px; }
.is-stats-chips .zd-statrail__num { font-size: 17px; }
.is-stats-chips .zd-statrail__label { margin-top: 0; font-size: 12.5px; }
.zd-statrail__num { display: flex; align-items: center; gap: 4px; font-weight: 900; font-size: 26px; line-height: 1; color: var(--zd-accent-strong); letter-spacing: -.02em; }
.zd-statrail__label { margin-top: 6px; font-size: 13px; line-height: 1.35; color: var(--zd-muted); }
@media (min-width: 720px) {
  .zd-statrail__row { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 920px) {
  .zd-hero__split-top { grid-template-columns: 1fr; }
  .zd-hero__split-copy { padding: 0; }
  /* keep the copy flush with the page container's left edge even though it lives in a grid column */
  .zd-hero__split-copy > .zd-container { max-width: none; padding-left: max(24px, calc((100vw - var(--zd-container, 1180px)) / 2 + 24px)); padding-right: 56px; }
}
/* NOTE: the drop also carried a @media (min-width: 920px) block styling
   .zd-hero--bg / .zd-hero__chip b / .zd-badge-promo. It was a verbatim copy of
   zd-blocks.css:887-891 - rules belonging to the OTHER hero variants, not this
   one - so it is deliberately not duplicated here. */

/* ---- V4 / V6 hero animations (three preview options; replayed on variant switch) ---- */
@keyframes zd-h-rise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes zd-h-fade { from { opacity: 0; } to { opacity: 1; } }
/* Same fade, but landing on the configured veil rather than a fixed 1. Used for
   the scrim and blur only — everything else genuinely does end fully opaque. */
@keyframes zd-h-fade-scrim { from { opacity: 0; } to { opacity: var(--zd-scrim-eff, 1); } }
@keyframes zd-h-wipe { from { clip-path: inset(0 0 0 100%); } to { clip-path: inset(0 0 0 0); } }
@keyframes zd-h-kenburns { from { transform: scaleX(var(--zd-flip, -1)) scale(1.12); } to { transform: none; } }
@keyframes zd-h-clipup { from { opacity: 0; clip-path: inset(105% 0 0 0); transform: translateY(10px); } to { opacity: 1; clip-path: inset(-20% 0 0 0); transform: none; } }
@keyframes zd-h-bargrow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
.zd-hero--split-full [data-anim-el] { will-change: opacity, transform; }
/* 1 · Підйом — copy and stats rise in sequence */
.is-anim-a.is-playing .zd-hero__h1 { animation: zd-h-rise .62s cubic-bezier(.22,.7,.24,1) both; }
.is-anim-a.is-playing .zd-hero__lead { animation: zd-h-rise .62s cubic-bezier(.22,.7,.24,1) .09s both; }
.is-anim-a.is-playing .zd-hero__reassure-item { animation: zd-h-rise .58s cubic-bezier(.22,.7,.24,1) both; }
.is-anim-a.is-playing .zd-hero__reassure-item:nth-child(1) { animation-delay: .18s; }
.is-anim-a.is-playing .zd-hero__reassure-item:nth-child(2) { animation-delay: .25s; }
.is-anim-a.is-playing .zd-hero__reassure-item:nth-child(3) { animation-delay: .32s; }
.is-anim-a.is-playing .zd-hero__reassure-item:nth-child(4) { animation-delay: .39s; }
.is-anim-a.is-playing .zd-hero__split-media { animation: zd-h-fade .9s ease both; }
.is-anim-a.is-playing .zd-statrail__item { animation: zd-h-rise .5s cubic-bezier(.22,.7,.24,1) both; }
.is-anim-a.is-playing .zd-statrail__item:nth-child(1) { animation-delay: .26s; }
.is-anim-a.is-playing .zd-statrail__item:nth-child(2) { animation-delay: .34s; }
.is-anim-a.is-playing .zd-statrail__item:nth-child(3) { animation-delay: .42s; }
.is-anim-a.is-playing .zd-statrail__item:nth-child(4) { animation-delay: .5s; }
.is-anim-a.is-playing .zd-hero__scrollband { animation: zd-h-fade .6s ease .62s both; }
/* 2 · Наплив фото — photo wipes in from the right and settles out of a slow zoom, copy follows */
.is-anim-b.is-playing .zd-hero__split-media { animation: zd-h-wipe 1.05s cubic-bezier(.16,.84,.24,1) both; }
.is-anim-b.is-playing .zd-hero__split-media img { animation: zd-h-kenburns 2.6s cubic-bezier(.2,.6,.2,1) both; }
/* keep the ken-burns landing on each variant's own resting transform */
.is-anim-b .zd-hero__split-media img { --zd-rest: scaleX(var(--zd-flip, -1)); }
.is-anim-b.is-playing .zd-hero__split-media img { animation-name: zd-h-kenburns-rest; }
@keyframes zd-h-kenburns-rest { from { transform: scaleX(var(--zd-flip, -1)) scale(1.12); } to { transform: var(--zd-rest); } }
.is-anim-b.zd-hero--split-vh .zd-hero__split-media img { --zd-rest: scaleX(var(--zd-flip, -1)) scaleY(.94); }
/* zd-h-fade-scrim, not zd-h-fade: a `both` fill keeps the animation's final value
   applied for good, and animated values outrank normal declarations — so ending
   on a hard-coded opacity: 1 would permanently override the veil setting. This
   was exactly why the mobile veil field appeared to do nothing in mode B. */
.is-anim-b.is-playing .zd-hero__split-scrim, .is-anim-b.is-playing .zd-hero__split-blur { animation: zd-h-fade-scrim .8s ease .35s both; }
.is-anim-b.is-playing .zd-hero__h1 { animation: zd-h-rise .7s cubic-bezier(.22,.7,.24,1) .2s both; }
.is-anim-b.is-playing .zd-hero__lead { animation: zd-h-rise .7s cubic-bezier(.22,.7,.24,1) .32s both; }
.is-anim-b.is-playing .zd-hero__reassure { animation: zd-h-rise .7s cubic-bezier(.22,.7,.24,1) .44s both; }
.is-anim-b.is-playing .zd-statrail__row { animation: zd-h-fade .7s ease .6s both; }
.is-anim-b.is-playing .zd-hero__scrollband { animation: zd-h-fade .6s ease .8s both; }
/* 3 · Розкриття — headline unmasks upward, accent bars draw, numbers count in */
.is-anim-c.is-playing .zd-hero__h1 { animation: zd-h-clipup .8s cubic-bezier(.16,.84,.24,1) both; }
.is-anim-c.is-playing .zd-hero__lead { animation: zd-h-clipup .8s cubic-bezier(.16,.84,.24,1) .12s both; }
.is-anim-c.is-playing .zd-hero__reassure { animation: zd-h-fade .7s ease .34s both; }
.is-anim-c.is-playing .zd-hero__split-media { animation: zd-h-fade 1.1s ease both; }
.is-anim-c.is-playing .zd-statrail__item::before { transform-origin: top; animation: zd-h-bargrow .42s cubic-bezier(.22,.7,.24,1) both; }
.is-anim-c.is-playing .zd-statrail__item:nth-child(1)::before { animation-delay: .3s; }
.is-anim-c.is-playing .zd-statrail__item:nth-child(2)::before { animation-delay: .38s; }
.is-anim-c.is-playing .zd-statrail__item:nth-child(3)::before { animation-delay: .46s; }
.is-anim-c.is-playing .zd-statrail__item:nth-child(4)::before { animation-delay: .54s; }
.is-anim-c.is-playing .zd-statrail__num { animation: zd-h-clipup .55s cubic-bezier(.16,.84,.24,1) both; }
.is-anim-c.is-playing .zd-statrail__item:nth-child(1) .zd-statrail__num { animation-delay: .32s; }
.is-anim-c.is-playing .zd-statrail__item:nth-child(2) .zd-statrail__num { animation-delay: .4s; }
.is-anim-c.is-playing .zd-statrail__item:nth-child(3) .zd-statrail__num { animation-delay: .48s; }
.is-anim-c.is-playing .zd-statrail__item:nth-child(4) .zd-statrail__num { animation-delay: .56s; }
.is-anim-c.is-playing .zd-statrail__label { animation: zd-h-fade .6s ease .5s both; }
.is-anim-c.is-playing .zd-hero__scrollband { animation: zd-h-fade .6s ease .82s both; }
/* LOCAL ADDITION — holding state before the animation runs.
   Without it the browser paints the finished hero, and only then does the footer
   script add .is-playing and restart everything from opacity 0 — so the hero is
   seen twice. Worst in mode B, which animates the photo itself.
   The prototype has the same gap but never shows it: its hero sits at the top of
   an almost-empty page, so the observer fires within a frame. Here the script
   waits behind Astra's CSS and JS, and the gap becomes visible.
   The 2s delay with `both` does double duty: the backwards fill holds opacity 0
   until then, AND the animation reveals the content anyway if the script never
   runs — so a JS failure cannot leave the hero blank. */
.zd-hero--split-full.is-anim-pending .zd-hero__h1,
.zd-hero--split-full.is-anim-pending .zd-hero__lead,
.zd-hero--split-full.is-anim-pending .zd-hero__reassure,
.zd-hero--split-full.is-anim-pending .zd-hero__actions,
.zd-hero--split-full.is-anim-pending .zd-hero__split-media,
.zd-hero--split-full.is-anim-pending .zd-statrail__row,
.zd-hero--split-full.is-anim-pending .zd-hero__scrollband {
  animation: zd-h-fade .3s ease 2s both;
}
/* The scrim and blur take the veil-aware fade for the same reason mode B does:
   if the script never runs, this animation's `both` fill is what the element is
   left with, and a fixed opacity: 1 would override the configured veil for good. */
.zd-hero--split-full.is-anim-pending .zd-hero__split-scrim,
.zd-hero--split-full.is-anim-pending .zd-hero__split-blur {
  animation: zd-h-fade-scrim .3s ease 2s both;
}

/* LOCAL ADDITION — the CTA buttons. The drop's hero had none, so its animations
   never covered them; without these the buttons would sit there fully visible
   while everything around them animated in. Each delay slots the buttons after
   the reassurance list and before the stat rail finishes, matching the order
   they read in.
   No layout rules needed — .zd-hero__actions already has them in zd-blocks.css.
   The reduced-motion guard below is a wildcard, so it covers these too. */
.is-anim-a.is-playing .zd-hero__actions { animation: zd-h-rise .58s cubic-bezier(.22,.7,.24,1) .45s both; }
.is-anim-b.is-playing .zd-hero__actions { animation: zd-h-rise .7s cubic-bezier(.22,.7,.24,1) .52s both; }
.is-anim-c.is-playing .zd-hero__actions { animation: zd-h-fade .6s ease .46s both; }

@media (prefers-reduced-motion: reduce) {
  /* .is-anim-pending is listed too, or the holding state's backwards fill would
     leave the hero blank for its full 2s delay for exactly the people who asked
     for less motion. Killing the animation drops the fill with it, so the
     content is simply visible. */
  .zd-hero--split-full.is-playing *,
  .zd-hero--split-full.is-anim-pending * { animation: none !important; }
}
