/* Motion layer — entrance, scroll and hover motion for the public site.
   Loaded after site.css (look) and before any page CSS. Owned separately
   from site.css so motion and visual design can change independently.

   Every hidden state sits behind html.motion-ready, which motion.js sets only
   when it is going to reveal things again. No JS, a failed script or reduced
   motion all leave the page fully visible. Classes are added by motion.js —
   see the key at the top of that file. Individual `translate`/`scale` are
   used throughout so `transform` stays free for site.css hover states.     */

:root{
  --m-ease:cubic-bezier(.16,1,.3,1);          /* expo-out: fast start, long settle */
  --m-ease-io:cubic-bezier(.76,0,.24,1);      /* for masks: a deliberate wipe */
}

/* --- Baseline: readable without JS ---------------------------------------
   site.css hides [data-reveal] until site.js adds .is-in; with JS off that
   would be a blank page. Same specificity, later file — this wins.          */
[data-reveal]{opacity:1;transform:none}
/* Hidden states never transition: they switch on instantly when motion.js
   arms the page, so nothing visibly fades *out* first. Each transition lives
   on the revealed state instead (the after-change style is what counts).   */
.motion-ready [data-reveal]:not(.is-in):not(.m-host){opacity:0;transform:translateY(28px);transition:none}
.motion-ready [data-reveal].is-in:not(.m-host){
  transition:opacity .9s var(--m-ease),transform 1.1s var(--m-ease)}
/* A host's pieces animate on their own, so the wrapper itself stays put. */
.motion-ready [data-reveal].m-host{opacity:1;transform:none;transition:none}
.motion-ready .anim-up.m-host,
.motion-ready .anim-up.m-item,
.motion-ready .anim-up.m-lines,
.motion-ready .anim-up.m-clip{animation:none}

/* --- Page-load: nav ------------------------------------------------------
   `backwards` fill only: a lingering translate on .nav would make it the
   containing block for the fixed mobile menu inside it.                     */
@keyframes mNavIn{from{opacity:0;translate:0 -16px}}
.motion-ready .nav{animation:mNavIn 1s var(--m-ease) .05s backwards}

/* --- Fade + rise (eyebrows, ledes, buttons, cards, tiles) ---------------- */
.motion-ready .m-item:not(.m-in){opacity:0;translate:0 26px;transition:none}
.motion-ready .m-item.m-in:not(.m-done){
  transition:opacity .9s var(--m-ease) var(--d,0ms),translate 1.1s var(--m-ease) var(--d,0ms)}

/* --- Headings: line-by-line rise behind a mask ---------------------------
   Each line clips at its own bottom edge; the sides and top are left open so
   tight tracking and overhangs are never shaved. The heading stays hidden
   until motion.js has measured its lines (after webfonts load).            */
.motion-ready .m-lines:not(.m-split):not(.m-in){opacity:0}
.m-line{display:block;padding-bottom:.14em;margin-bottom:-.14em;
  clip-path:inset(-1em -1em 0 -1em)}
.m-line__in{display:inline-block;max-width:100%}
.motion-ready .m-lines:not(.m-in) .m-line__in{translate:0 112%}
.motion-ready .m-lines.m-in .m-line__in{
  transition:translate 1.15s var(--m-ease) calc(var(--d,0ms) + var(--l,0) * 90ms)}

/* --- Media: frame un-masks bottom-up, image settles from 1.08 ------------
   A plain frame wipes inset(100% 0 0 0) → inset(0). A frame that rests on a
   polygon (site.css's --notch) gets --m-from/--m-to from motion.js: the same
   polygon with every point pushed to the bottom edge, so the two interpolate
   point for point and the notch is there for the whole wipe. On .m-done the
   rule lets go and site.css's own clip-path is back in charge.             */
.motion-ready .m-clip:not(.m-in){clip-path:inset(100% 0 0 0);transition:none}
.motion-ready .m-clip.m-poly:not(.m-in){clip-path:var(--m-from)}
.motion-ready .m-clip.m-in:not(.m-done){clip-path:inset(0 0 0 0);
  transition:clip-path 1.3s var(--m-ease-io) var(--d,0ms)}
.motion-ready .m-clip.m-poly.m-in:not(.m-done){clip-path:var(--m-to)}
.motion-ready .m-media{scale:calc(var(--m-rest,1) * var(--m-hov,1))}
.motion-ready .m-clip:not(.m-in) .m-media{scale:calc(var(--m-rest,1) * 1.08);transition:none}
.motion-ready .m-clip.m-in .m-media:not(.m-done){transition:scale 1.8s var(--m-ease) var(--d,0ms)}
/* Parallax media are held slightly larger so the drift never shows an edge. */
.motion-ready .m-par{--m-rest:1.1}

/* --- Hairlines draw from the left --------------------------------------- */
.motion-ready .m-rule{transform-origin:0 50%}
.motion-ready .m-rule:not(.m-in){scale:0 1;transition:none}
.motion-ready .m-rule.m-in:not(.m-done){transition:scale 1.4s var(--m-ease-io) var(--d,0ms)}

/* --- Counters ----------------------------------------------------------- */
.m-count{font-variant-numeric:tabular-nums}

/* --- Hover micro-interactions --------------------------------------------
   Movement only — colours stay with site.css. Mouse users only, and never
   when reduced motion is asked for.                                         */
@media (hover:hover) and (prefers-reduced-motion:no-preference){
  /* Image cards and image links: a slow push-in on the settled image. */
  .motion-ready .m-media.m-done{transition:scale 1s var(--m-ease)}
  a.m-clip:hover .m-media,a:hover>.m-clip .m-media,
  .card:hover .m-media,.acard:hover .m-media{--m-hov:1.035}

  /* Arrows nudge forward. */
  .btn svg,.btn>span[aria-hidden="true"],.link-more svg,.acard__go svg{
    display:inline-block;transition:translate .45s var(--m-ease)}
  .btn:hover svg,.btn:hover>span[aria-hidden="true"],.link-more:hover svg,
  .acard:hover .acard__go svg{translate:3px 0}

  /* Text links: an underline that draws in from the left, out to the right. */
  .breadcrumb a,.panel li a,.tile__link,.contact-info li a,
  .footer__col a,.article-meta a{
    text-decoration:none;
    background-image:linear-gradient(currentColor,currentColor);
    background-repeat:no-repeat;background-size:0 1px;background-position:100% 100%;
    transition:background-size .5s var(--m-ease),color .2s ease}
  .breadcrumb a:hover,.panel li a:hover,.tile__link:hover,
  .contact-info li a:hover,.footer__col a:hover,.article-meta a:hover{
    text-decoration:none;background-size:100% 1px;background-position:0 100%}
}

/* --- Reduced motion / print: everything in place, nothing moves --------- */
@media (prefers-reduced-motion:reduce){
  [data-reveal]{opacity:1;transform:none;transition:none}
}
@media print{
  .m-item,.m-lines,.m-media,.m-rule,.m-line__in,[data-reveal]{
    opacity:1!important;translate:none!important;scale:none!important;transform:none!important}
  .m-clip:not(.m-done){clip-path:var(--m-to,none)!important}
}
