/* ============================================================================
   Knowledge Hub — motion layer (LAYER 4, loaded after knowledge-hub.css)
   London Reporting Academy
   ----------------------------------------------------------------------------
   The landing's "liveliness" collected in one place and applied to the Hub
   tier — hub home, guides home, framework pages, guide indexes, guide pages
   and the Disclosure Library home. Every effect here is a port of something
   the storefront already does; the source is named on each block so the two
   surfaces can be tuned together rather than drifting apart.

     hero entrance          work-with-us.html      fadeUp
     staggered reveal       reveal-drop.css        .reveal-drop / reveal_drop_js
     scroll progress        _dl_motion.html        .lra-progress
     count-up numbers       index.html             .v1-metric[data-target]
     button gradient drift  index.html             v1GradientShift, cfShift
     hover sheen on cards   course-finder.css      cfSheen, .v1-segment-card::before
     image-wave on covers   index.html             .v2-studio-mini-thumb::after
     breathing CTA + shine  index.html             v2-studio-cta-pulse / -shine
     pulse ring / blink     index.html, lra_promos v2-verify-pulse, lra-promo-blink
     dark-scene drift       courses/*.html         cHeroShift, auroraMove, lra-promo-orb
     details reveal         courses/*.html         cFaqReveal
     progress-bar fill      lra_promos.css         lra-promo-bar
     ripple on click        ui_enhancements_css    v2Ripple

   Three rules this file keeps:

   1. NOTHING DEPENDS ON JS TO BE VISIBLE. States that hide an element until
      it scrolls into view are gated by `.kh-motion`, which kh-motion.js adds
      to `.kh-page` only when it is running and motion is not reduced. With
      JS off, the page is simply the page.

   2. NO TRANSFORM SURVIVES AN ANIMATION. Every entrance ends on
      `transform:none`, so no block becomes a containing block for a fixed
      descendant or a stacking context for a dropdown after it has settled.

   3. EVERYTHING IS OFF UNDER prefers-reduced-motion. The block at the end
      switches every animation and transition in this file off; the JS does
      not run its own effects in that case either.
   ========================================================================== */

/* ── Keyframes ───────────────────────────────────────────────────────────── */
@keyframes khm-fade-up{from{opacity:0;transform:translate3d(0,14px,0)}to{opacity:1;transform:none}}
@keyframes khm-shift{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}
@keyframes khm-orb{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(-22px,16px) scale(1.12)}}
@keyframes khm-sheen{0%{left:-130%}60%,100%{left:130%}}
@keyframes khm-shine{0%{left:-90%}35%,100%{left:140%}}
@keyframes khm-ring{0%{box-shadow:0 0 0 0 rgba(232,199,102,.6)}70%{box-shadow:0 0 0 10px rgba(232,199,102,0)}100%{box-shadow:0 0 0 0 rgba(232,199,102,0)}}
@keyframes khm-cta-pulse{0%,100%{box-shadow:0 0 0 0 rgba(98,181,225,.45)}50%{box-shadow:0 0 0 8px rgba(98,181,225,0)}}
@keyframes khm-dot{0%,100%{box-shadow:0 0 0 0 rgba(0,144,167,.4)}50%{box-shadow:0 0 0 5px rgba(0,144,167,0)}}
@keyframes khm-blink{0%,55%{opacity:1}65%,100%{opacity:.2}}
@keyframes khm-details{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
@keyframes khm-ripple{to{transform:scale(1);opacity:0}}

/* ── 1 · Hero entrance (CSS only — runs on load, no JS needed) ─────────────
   work-with-us.html: label → h1 → standfirst → actions, each a beat later.
   `both` keeps the element hidden through its delay; the keyframe ends on
   transform:none (rule 2). */
.kh-page .khh2-hero__inner>*,
.kh-page .khh-hero__grid>div:first-child>*,
.kh-page .kh-hero .kh-grid>div:first-child>*{animation:khm-fade-up .55s cubic-bezier(.16,.84,.25,1) both}
.kh-page .khh2-hero__inner>:nth-child(1),
.kh-page .khh-hero__grid>div:first-child>:nth-child(1),
.kh-page .kh-hero .kh-grid>div:first-child>:nth-child(1){animation-delay:.04s}
.kh-page .khh2-hero__inner>:nth-child(2),
.kh-page .khh-hero__grid>div:first-child>:nth-child(2),
.kh-page .kh-hero .kh-grid>div:first-child>:nth-child(2){animation-delay:.12s}
.kh-page .khh2-hero__inner>:nth-child(3),
.kh-page .khh-hero__grid>div:first-child>:nth-child(3),
.kh-page .kh-hero .kh-grid>div:first-child>:nth-child(3){animation-delay:.2s}
.kh-page .khh2-hero__inner>:nth-child(4),
.kh-page .khh-hero__grid>div:first-child>:nth-child(4),
.kh-page .kh-hero .kh-grid>div:first-child>:nth-child(4){animation-delay:.28s}
.kh-page .khh2-hero__inner>:nth-child(5),
.kh-page .khh-hero__grid>div:first-child>:nth-child(5),
.kh-page .kh-hero .kh-grid>div:first-child>:nth-child(5){animation-delay:.36s}
.kh-page .khh2-hero__inner>:nth-child(n+6),
.kh-page .khh-hero__grid>div:first-child>:nth-child(n+6),
.kh-page .kh-hero .kh-grid>div:first-child>:nth-child(n+6){animation-delay:.44s}
/* the second column of a two-column hero, and the trust strip under it */
.kh-page .khh-hero__grid>.khh-ask,
.kh-page .kh-hero .kh-grid>.kh-hero__aside{animation:khm-fade-up .55s cubic-bezier(.16,.84,.25,1) .3s both}
.kh-page .kh-hero .kh-grid>.kh-passport,
.kh-page .khh-trust{animation:khm-fade-up .55s cubic-bezier(.16,.84,.25,1) .42s both}

/* ── 2 · Staggered scroll reveal (JS-gated) ───────────────────────────────
   reveal-drop.css: a 14px drop with a hair of scale, staggered per row by a
   custom property the script sets. The script removes `.khm-rise` once the
   transition has ended, so the element's own transitions come back. */
.kh-motion .khm-rise{opacity:0;transform:translate3d(0,-14px,0) scale(.992);transition:opacity .72s cubic-bezier(.16,.84,.25,1),transform .72s cubic-bezier(.16,.84,.25,1);transition-delay:var(--khm-delay,0ms);will-change:opacity,transform}
.kh-motion .khm-rise.is-in{opacity:1;transform:none}

/* ── 3 · Scroll progress (JS creates the node) ────────────────────────────
   _dl_motion.html: a 3px brand gradient that tracks the read. Sits just
   under the fixed site header rather than behind it. */
.khm-progress{position:fixed;top:var(--lra-header-height-live,var(--lra-header-height,76px));left:0;height:3px;width:0;z-index:104;background:linear-gradient(90deg,#0d3068,#0090a7,#e8c766);box-shadow:0 0 8px rgba(0,144,167,.45);transition:width .08s linear;pointer-events:none}

/* ── 4 · Numbers count up (JS drives; CSS only stops the width jittering) ── */
.kh-page .khh2-nums dt{font-variant-numeric:tabular-nums}

/* ── 5 · Primary buttons: gradient drift + lift ───────────────────────────
   index.html v1GradientShift on the hero CTAs; course-finder.css cfShift.
   Allow-listed rather than blanket, because the tier also has white
   (.kh-take), gold (.khh2-btn--gold, .kh-bridge) and ghost buttons that
   must keep their own fill. */
.kh-page .kh-btn{position:relative;overflow:hidden;transition:transform .22s ease,box-shadow .22s ease,background-color .2s ease,border-color .2s ease,color .2s ease,filter .22s ease}
.kh-page .kh-btn:hover{transform:translateY(-1px)}
.kh-page .khh2-door__cta .kh-btn:not(.kh-btn--ghost),
.kh-page .khg-search .kh-btn,
.kh-page .khg-empty__cta .kh-btn:not(.kh-btn--ghost),
.kh-page .khg-door a.khg-door__all{background-image:linear-gradient(135deg,var(--lra-color-primary) 0%,var(--lra-color-primary-light) 45%,var(--lra-color-teal) 100%);background-size:220% 220%;background-position:0% 50%;border-color:transparent;box-shadow:0 8px 20px rgba(13,48,104,.18);animation:khm-shift 8s ease infinite}
.kh-page .khh2-door__cta .kh-btn:not(.kh-btn--ghost):hover,
.kh-page .khg-search .kh-btn:hover,
.kh-page .khg-empty__cta .kh-btn:not(.kh-btn--ghost):hover,
.kh-page .khg-door a.khg-door__all:hover{background-image:linear-gradient(135deg,var(--lra-color-primary-light) 0%,var(--lra-color-teal) 100%);transform:translateY(-2px);box-shadow:0 12px 26px rgba(13,48,104,.26)}
/* the Disclosure Library home's own bridge button already carries a
   blue→teal gradient — it only needs the drift */
.kh-page .hb-bridge a{background-size:220% 220%;animation:khm-shift 8s ease infinite;transition:transform .22s ease,box-shadow .22s ease}
.kh-page .hb-bridge a:hover{transform:translateY(-2px);box-shadow:0 12px 26px rgba(13,48,104,.22)}

/* ── 6 · The one CTA per page breathes, with a light sweep ────────────────
   index.html v2-studio-cta-pulse / v2-studio-cta-shine on the Studio CTA.
   Applied to the course-bridge button, the gold corpus-search button and the
   assistant's send button. Pauses on hover so the lift reads cleanly. */
.kh-page .kh-bridge .kh-btn:not(.kh-btn--ghost),
.kh-page .khh2-btn--gold,
.kh-page .kh-ask__send{position:relative;overflow:hidden;animation:khm-cta-pulse 3.6s ease-in-out infinite;transition:transform .25s ease,box-shadow .25s ease,background-color .2s ease}
.kh-page .kh-bridge .kh-btn:not(.kh-btn--ghost)::after,
.kh-page .khh2-btn--gold::after{content:"";position:absolute;top:0;left:-90%;width:55%;height:100%;background:linear-gradient(110deg,transparent 0%,rgba(255,255,255,.38) 50%,transparent 100%);transform:skewX(-22deg);pointer-events:none;animation:khm-shine 6s ease-in-out 1.6s infinite}
.kh-page .kh-bridge .kh-btn:not(.kh-btn--ghost):hover,
.kh-page .khh2-btn--gold:hover,
.kh-page .kh-ask__send:hover{transform:translateY(-2px);animation-play-state:paused}
.kh-page .kh-ask__send:disabled{animation:none;transform:none}

/* ── 7 · The assistant is live: pulse ring on the avatar, blinking dot on
        the free-answers chip ───────────────────────────────────────────────
   index.html v2-verify-pulse (diploma badge) and lra_promos lra-promo-blink
   (the promo eyebrow dot). Gold, because gold is the Ask panel's accent. */
.kh-page .kh-ask__head img{animation:khm-ring 2.4s ease-out infinite}
.kh-page .kh-ask__free::before{content:"";display:inline-block;width:6px;height:6px;margin-inline-end:6px;border-radius:50%;background:currentColor;vertical-align:middle;animation:khm-blink 1.4s infinite}

/* ── 8 · Dark scenes drift ────────────────────────────────────────────────
   courses/*.html cHeroShift on the navy hero; work-with-us auroraMove and
   lra_promos lra-promo-orb on the glow. The intelligence band and the two
   navy assistants already carry a radial glow — it now moves. */
.kh-page .khh2-intel,
.kh-page .khh-assist{background-size:220% 220%;animation:khm-shift 16s ease infinite}
.kh-page .khh2-intel::after{animation:khm-orb 13s ease-in-out infinite}
.kh-page .kh-ask::before{animation:khm-orb 11s ease-in-out infinite}
.kh-page .kh-bridge::before{animation:khm-orb 14s ease-in-out infinite reverse}

/* ── 9 · Hover: sheen sweep + lift on the tier's card-like links ──────────
   course-finder.css cfSheen on the finder options; index.html's segment
   cards run the same sweep. Light band on white cards, white band on the
   dark citation rows. The answer card (.khg-answer) is deliberately left
   out — it is not a link, and the stylesheet says so. */
.kh-page :is(.khh2-door,.khh-fw,.khh-topic,.khg-task,.khg-pillar,.khh-route,.khh2-prog__row,.kh-cards a,.khh-latest>a,.kh-list a,.khh2-intel__rows a:not(.khh2-intel__rows-more)){position:relative;overflow:hidden}
.kh-page :is(.khh2-door,.khh-fw,.khh-topic,.khg-task,.khg-pillar,.khh-route,.khh2-prog__row,.kh-cards a,.khh-latest>a,.kh-list a)::after{content:"";position:absolute;top:0;bottom:0;left:-130%;width:55%;pointer-events:none;z-index:1;background:linear-gradient(100deg,transparent,rgba(13,48,104,.07),transparent);transform:skewX(-18deg)}
.kh-page .khh2-intel__rows a:not(.khh2-intel__rows-more)::after{content:"";position:absolute;top:0;bottom:0;left:-130%;width:55%;pointer-events:none;z-index:1;background:linear-gradient(100deg,transparent,rgba(255,255,255,.14),transparent);transform:skewX(-18deg)}
.kh-page :is(.khh2-door,.khh-fw,.khh-topic,.khg-task,.khg-pillar,.khh-route,.khh2-prog__row,.kh-cards a,.khh-latest>a,.kh-list a,.khh2-intel__rows a:not(.khh2-intel__rows-more)):hover::after{animation:khm-sheen 1.1s ease}
.kh-page :is(.khh-fw,.khg-pillar,.kh-cards a,.khh2-intel__rows a:not(.khh2-intel__rows-more)){transition:transform .2s ease,box-shadow .2s ease,border-color .2s ease,background-color .2s ease,color .2s ease}
.kh-page :is(.khh-fw,.khg-pillar,.kh-cards a):hover{transform:translateY(-2px);box-shadow:0 10px 24px rgba(13,48,104,.12)}
.kh-page .khh2-intel__rows a:not(.khh2-intel__rows-more):hover{transform:translateY(-1px)}
/* the arrow inside a card slides on hover — course-finder .cf-opt-arrow */
.kh-page :is(.khh-topic i,.khg-task__f i,.khg-pillar em){display:inline-block;transition:transform .2s ease,color .18s ease}
.kh-page :is(.khh-topic:hover i,.khg-task:hover .khg-task__f i,.khg-pillar:hover em){transform:translateX(4px)}
.rtl .kh-page :is(.khh-topic:hover i,.khg-task:hover .khg-task__f i,.khg-pillar:hover em){transform:translateX(-4px)}

/* ── 10 · Report covers: image-wave on hover ──────────────────────────────
   index.html .v2-studio-mini-thumb::after. Drawn as a moving background on
   a full-cover pseudo-element rather than an overflowing band, so the
   cover's drop shadow is not clipped. */
.kh-page .khh2-covers__row a{position:relative}
.kh-page .khh2-covers__row a::after{content:"";position:absolute;inset:0;border-radius:6px;pointer-events:none;background:linear-gradient(100deg,transparent 35%,rgba(255,255,255,.28) 50%,transparent 65%);background-size:250% 100%;background-position:130% 0;transition:background-position 1.4s cubic-bezier(.22,1,.36,1)}
.kh-page .khh2-covers__row a:hover::after{background-position:-60% 0}

/* ── 11 · Trust dots breathe ──────────────────────────────────────────────
   courses/*.html c-pulse on the badge dot, one beat apart along the row. */
.kh-page :is(.khh2-marks,.khh-trust)>li::before{animation:khm-dot 2.6s ease-in-out infinite}
.kh-page :is(.khh2-marks,.khh-trust)>li:nth-child(2)::before{animation-delay:.45s}
.kh-page :is(.khh2-marks,.khh-trust)>li:nth-child(3)::before{animation-delay:.9s}
.kh-page :is(.khh2-marks,.khh-trust)>li:nth-child(4)::before{animation-delay:1.35s}
.kh-page :is(.khh2-marks,.khh-trust)>li:nth-child(n+5)::before{animation-delay:1.8s}

/* ── 12 · Disclosure toggles open with a settle ───────────────────────────
   courses/*.html cFaqReveal. Covers the passport, "Coming next", guide FAQ
   items, the catalogue's standard tiles and every other <details> here. */
.kh-page details[open]>:not(summary){animation:khm-details .38s cubic-bezier(.16,.84,.44,1) both}

/* ── 13 · Programme bars fill when they scroll into view (JS-gated) ──────
   lra_promos.css lra-promo-bar. The inline width stays the truth; the fill
   scales from the start edge once the row is revealed. */
.kh-motion .khh2-prog__row.khm-bar .khh2-prog__bar i{transform:scaleX(0);transform-origin:left center;transition:transform 1.1s cubic-bezier(.22,.8,.25,1) var(--khm-delay,0ms)}
.rtl .kh-motion .khh2-prog__row.khm-bar .khh2-prog__bar i{transform-origin:right center}
.kh-motion .khh2-prog__row.khm-bar.is-in .khh2-prog__bar i{transform:scaleX(1)}

/* ── 14 · Ripple on click (JS inserts the span) ───────────────────────────
   shared/ui_enhancements_css.html v2Ripple on .btn — the Hub's buttons are
   .kh-btn and the assistant's chips, which that layer does not reach. */
.kh-page .kh-ask__chip{position:relative;overflow:hidden}
.kh-page .khm-ripple{position:absolute;border-radius:50%;background:rgba(255,255,255,.35);transform:scale(0);pointer-events:none;animation:khm-ripple .6s ease-out forwards}
.kh-page .kh-btn--ghost .khm-ripple,
.kh-page .kh-take .khm-ripple{background:rgba(13,48,104,.12)}

/* ── Off switches ────────────────────────────────────────────────────────── */
@media print{
  .kh-motion .khm-rise{opacity:1!important;transform:none!important;transition:none!important}
  .khm-progress{display:none}
}
@media (prefers-reduced-motion:reduce){
  .kh-page .khh2-hero__inner>*,
  .kh-page .khh-hero__grid>div:first-child>*,
  .kh-page .kh-hero .kh-grid>div:first-child>*,
  .kh-page .khh-hero__grid>.khh-ask,
  .kh-page .kh-hero .kh-grid>.kh-hero__aside,
  .kh-page .kh-hero .kh-grid>.kh-passport,
  .kh-page .khh-trust,
  .kh-page .khh2-door__cta .kh-btn,
  .kh-page .khg-search .kh-btn,
  .kh-page .khg-empty__cta .kh-btn,
  .kh-page .khg-door a.khg-door__all,
  .kh-page .hb-bridge a,
  .kh-page .kh-bridge .kh-btn,
  .kh-page .khh2-btn--gold,
  .kh-page .kh-ask__send,
  .kh-page .kh-ask__head img,
  .kh-page .kh-ask__free::before,
  .kh-page .khh2-intel,
  .kh-page .khh-assist,
  .kh-page .khh2-intel::after,
  .kh-page .kh-ask::before,
  .kh-page .kh-bridge::before,
  .kh-page :is(.khh2-marks,.khh-trust)>li::before,
  .kh-page details[open]>:not(summary),
  .kh-page .khm-ripple{animation:none!important}
  .kh-page .kh-bridge .kh-btn::after,
  .kh-page .khh2-btn--gold::after,
  .kh-page :is(.khh2-door,.khh-fw,.khh-topic,.khg-task,.khg-pillar,.khh-route,.khh2-prog__row,.kh-cards a,.khh-latest>a,.kh-list a,.khh2-intel__rows a)::after,
  .kh-page .khh2-covers__row a::after{display:none}
  .kh-page .kh-btn:hover,
  .kh-page .hb-bridge a:hover,
  .kh-page :is(.khh-fw,.khg-pillar,.kh-cards a,.khh2-intel__rows a):hover,
  .kh-page :is(.khh-topic:hover i,.khg-task:hover .khg-task__f i,.khg-pillar:hover em){transform:none}
  .kh-motion .khm-rise,.kh-motion .khm-rise.is-in{opacity:1;transform:none;transition:none}
  .kh-motion .khh2-prog__row.khm-bar .khh2-prog__bar i{transform:none;transition:none}
  .khm-progress{display:none}
}
