/* ============================================================
   TC Coaching : motion
   ------------------------------------------------------------
   Kept in its own file deliberately. Motion is the kind of thing
   that gets judged by feel rather than argued about, so it should
   be easy to see in one place, easy to tune, and easy to remove
   without unpicking it from the layout.

   One idea runs through all of it: movement should be attached to
   the scroll, not played at the reader. A section that rises as
   you scroll to it feels like the page is responding to you. The
   same section fading in on a trigger feels like a slideshow.
   ============================================================ */

/* ---------- The drifting light ----------
   Ollie's site has a soft cloud of colour that moves behind everything, and it
   is most of why the page feels alive before you have scrolled a pixel. Same
   idea here in TC blue.

   Three blobs, different sizes, speeds and directions, so they drift past each
   other and the pattern never visibly repeats. Slow on purpose: at this size
   anything you can consciously follow becomes a distraction from the words.

   Built on body::before so it needs no markup on any of the 72 pages, sits
   behind the content at z-index -1, and shows through every section that does
   not paint its own background. Only transform is animated, which the compositor
   handles on its own thread, so it costs nothing on scroll. */
/* body paints an opaque ground, and a z-index:-1 layer on body sits UNDER that,
   so the first version of this was invisible on every page: what looked like the
   glow was the hero's own gradient. Moving the ground up to html gives the layer
   somewhere to live, above the page colour and below everything else. */
html{background:var(--black)}
body{background-color:transparent}

body::before{
  content:"";position:fixed;inset:-25%;z-index:-1;pointer-events:none;
  background:
    radial-gradient(38% 34% at 22% 26%,rgba(0,164,255,.40),transparent 62%),
    radial-gradient(30% 28% at 78% 18%,rgba(0,164,255,.28),transparent 60%),
    radial-gradient(42% 36% at 62% 82%,rgba(25,152,214,.30),transparent 65%);
  filter:blur(34px);
}
@media (prefers-reduced-motion:no-preference){
  body::before{animation:tc-drift 46s ease-in-out infinite alternate}
  @keyframes tc-drift{
    0%  {transform:translate3d(-3%,-2%,0) scale(1)}
    35% {transform:translate3d(4%,3%,0) scale(1.09)}
    70% {transform:translate3d(-2%,5%,0) scale(1.04)}
    100%{transform:translate3d(3%,-3%,0) scale(1.12)}
  }
}

/* ---------- The reveal ----------
   Two implementations of the same effect.

   The baseline is a transition that JavaScript switches on with
   .is-in when the element enters the viewport. Every browser gets
   this, and it is what js/main.js has always driven.

   Where the browser can run an animation straight off the scroll
   position, it does that instead, and the element rises in step
   with the scroll rather than snapping into a fixed-length
   playback. That is the whole difference in feel. */
.reveal{opacity:0;transform:translateY(42px);
  transition:opacity .7s cubic-bezier(.22,.61,.36,1),transform .7s cubic-bezier(.22,.61,.36,1)}
.reveal.is-in{opacity:1;transform:none}

@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    /* The animation wins over .is-in without needing !important,
       because animations beat ordinary declarations. So the JS
       path quietly becomes a no-op here rather than fighting. */
    .reveal{animation:tc-rise linear both;animation-timeline:view();
      animation-range:entry 0% entry 55%;transition:none}
  }
  @keyframes tc-rise{from{opacity:0;transform:translateY(42px) scale(.985)}to{opacity:1;transform:none}}
}

/* ---------- Stagger ----------
   A row of three cards arriving together reads as one block moving.
   The same three arriving a beat apart reads as a list being dealt
   out, which is more alive and costs nothing.

   Done by moving each child's scroll range rather than by delaying
   a timer, because with a scroll-driven animation there is no clock
   to delay: position is the only currency. */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .rv-stagger>*{animation:tc-rise linear both;animation-timeline:view()}
    .rv-stagger>*:nth-child(1){animation-range:entry 0% entry 52%}
    .rv-stagger>*:nth-child(2){animation-range:entry 8% entry 60%}
    .rv-stagger>*:nth-child(3){animation-range:entry 16% entry 68%}
    .rv-stagger>*:nth-child(4){animation-range:entry 22% entry 74%}
    .rv-stagger>*:nth-child(5){animation-range:entry 28% entry 80%}
    .rv-stagger>*:nth-child(n+6){animation-range:entry 32% entry 84%}
  }
}

/* The application form's fieldsets are also called .step, and they are
   display:none until their turn. A hidden element has no scroll timeline, so a
   reveal on one never resolves and the step stays at opacity 0 when the form
   finally shows it. Nothing in a form should ever be waiting on a scroll. */
.applyform .reveal,.applyform .rv-stagger>*{opacity:1!important;transform:none!important;animation:none!important}

/* ---------- The live dot ----------
   The eyebrow already carries a blue dot that says "open now". It
   sat still, which made it a bullet point. One slow pulse turns it
   back into a status light. Slow on purpose: anything quicker reads
   as a notification badge demanding to be dealt with. */
@media (prefers-reduced-motion:no-preference){
  .eyebrow .dot{animation:tc-pulse 2.6s ease-out infinite}
  @keyframes tc-pulse{
    0%  {box-shadow:0 0 0 0 rgba(0,164,255,.55),0 0 12px var(--blue)}
    70% {box-shadow:0 0 0 9px rgba(0,164,255,0),0 0 12px var(--blue)}
    100%{box-shadow:0 0 0 0 rgba(0,164,255,0),0 0 12px var(--blue)}
  }
}

/* ---------- Underline on the nav ----------
   The links only changed colour on hover. A line that grows from
   the left gives the pointer something to land on. */
@media (hover:hover){
  .nav__links a{position:relative}
  .nav__links a::after{content:"";position:absolute;left:0;right:0;bottom:-5px;height:1.5px;
    background:var(--blue);transform:scaleX(0);transform-origin:left;
    transition:transform .28s cubic-bezier(.22,.61,.36,1)}
  .nav__links a:hover::after,.nav__links a.is-active::after{transform:scaleX(1)}
}

/* ---------- Pillar cards ----------
   The cards already lift on hover. The banner inside them now
   drifts up a touch at the same time, so the card reads as one
   object moving rather than a frame sliding off its picture. */
@media (hover:hover) and (prefers-reduced-motion:no-preference){
  .pillar__banner{transition:transform .45s cubic-bezier(.22,.61,.36,1)}
  .pillar:hover .pillar__banner{transform:scale(1.04)}
}

/* ---------- The one rule that outranks all of it ----------
   Anyone who has asked their system to stop animations gets a
   still page. Not a slower one. */
@media (prefers-reduced-motion:reduce){
  .reveal,.rv-stagger>*{opacity:1!important;transform:none!important;
    animation:none!important;transition:none!important}
  .eyebrow .dot{animation:none}
}
