/* ==========================================================================
   Naval Orientation: motion layer
   ==========================================================================

   The site's whole sense of pace lives in this one file, and it is loaded last
   so that it has the final word on timing everywhere.

   Why a separate layer rather than edits scattered through the component
   sheets: the client asked for the entire site to move more slowly, in the
   manner of the large maritime corporate sites. That is a single decision
   about pace, not eighty small ones, and it should be adjustable — or
   removable — in a single place. Every component transition in this theme
   resolves its duration from the tokens redefined below, so slowing the site
   down is a matter of changing seven numbers here, not of hunting through
   eight stylesheets. Each var() carries the previous value as its fallback,
   so if this sheet ever fails to load, nothing loses its transition.

   To make the site faster or slower again, change the token block. To take the
   cinematic pace off entirely, stop enqueuing this file: the theme falls back
   to the shorter timings baked into the component sheets.

   Nothing here changes a colour, a size, a spacing step or a layout. Motion
   only, and all of it stands down under prefers-reduced-motion.
   ========================================================================== */

:root {
  /* ---- The pace dial -----------------------------------------------------
     Interaction timings stay under a second: a hover or a button press has to
     answer immediately, however slow the page's storytelling is. Only the
     scroll-driven storytelling — reveals, wipes, drifts — runs long.
     -------------------------------------------------------------------- */
  --no-dur-tap:   .12s;   /* the press itself                      */
  --no-dur-fast:  .28s;   /* small state flips: focus, tick, caret */
  --no-dur:       .52s;   /* the default hover and colour change   */
  --no-dur-mid:   .72s;   /* arrows, chevrons, panel rows          */
  --no-dur-slow:  .95s;   /* accordions, growth, larger movements  */
  --no-dur-cine: 1.6s;    /* image zooms, video fades              */
  --no-dur-epic: 2.2s;    /* headline lines, the longest travel    */

  /* ---- The curves ------------------------------------------------------
     This is the part that actually decides whether the site feels slow, and
     it matters more than the durations. The theme's stock ease-out is an
     exponential: it covers 83% of the distance in the first quarter of the
     time. Stretch that curve to two seconds and the movement still looks
     finished in half a second — all the extra time goes into a settle nobody
     can see. Measured at a quarter of the way through:

       exponential (was)   83% of the distance   looks finished immediately
       power2.out          60%                   premium, still brisk
       quad.out            45%                   deliberate, visibly slow

     So the whole site's settle becomes power2.out, and the long cinematic
     moves — headline lines, image wipes, the picture landing behind a frame —
     get the slower quad.out, where the duration is genuinely visible as
     movement. Redefining the theme's own ease-out is the point rather than a
     side effect: every transition in every component sheet resolves through
     it.
     ------------------------------------------------------------------ */
  --no-ease-out:  cubic-bezier(.215, .61, .355, 1);
  --no-ease-cine: cubic-bezier(.25, .46, .45, .94);
  --no-ease-soft: cubic-bezier(.33, 1, .68, 1);

  /* Scroll reveals. Roughly 1.6x the previous pace, with a longer travel so
     the extra time is visible as movement instead of as a slow fade. */
  --reveal-dur:    1.7s;
  --reveal-rise:   34px;
  --reveal-wipe:   2s;     /* the frame opening   */
  --reveal-settle: 3.2s;   /* the picture landing */

  /* Group cascade. Set per element in JS; these are the shape of it. */
  --line-stagger:  90ms;
}

/* ---------- Reveal recalibration -----------------------------------------
   The variants in base.css set their own duration so that they read as
   different weights of the same idea. Those relationships are kept; every one
   of them is simply stretched.
   ---------------------------------------------------------------------- */
[data-reveal="rise"]   { --reveal-rise: 52px; --reveal-dur: 2s;   }
[data-reveal="settle"] { --reveal-rise: 18px; --reveal-dur: 1.35s; }
[data-reveal="left"]   { transform: translate3d(-30px, 0, 0); }
[data-reveal="right"]  { transform: translate3d(30px, 0, 0); }

/* The drift on the big photographs travels further, because it now has longer
   to do it in. The pre-scale grows with it so an edge is never exposed. */
[data-parallax] > img,
[data-parallax] > video,
img[data-parallax] { transform: translate3d(0, var(--parallax, 0px), 0) scale(1.16); }

/* ---------- Headline lines ------------------------------------------------
   A heading rises a line at a time, each line a beat behind the one above.
   main.js wraps every line in .no-line > .no-line__i and writes the delay; if
   that script never runs, the heading is simply visible, which is why the
   parent is fully painted here rather than faded in.

   The line box is what hides the type before it arrives, so the reveal cannot
   deadlock the way a clip-path on an observed element does (see the invariant
   in base.css). overflow: hidden clips descenders, so each line carries a
   little bottom padding and pulls it straight back out of the layout.
   ---------------------------------------------------------------------- */
[data-reveal="lines"] { opacity: 1; transform: none; clip-path: none; }

/*
 * flow-root, not block, and for a specific reason: each line carries a little
 * bottom padding so that overflow: hidden cannot shave a descender, and pulls
 * the same amount straight back with a negative margin so the heading keeps
 * exactly the height it had as ordinary wrapped text. Without a block
 * formatting context here, that negative margin collapses out through the
 * heading instead of being taken off it, and every split heading grows by a
 * few pixels — a layout shift, on every heading on the site.
 */
.no-lines { display: flow-root; }
.no-lines .no-line {
  display: block;
  overflow: hidden;
  padding-bottom: .14em;
  margin-bottom: -.14em;
}
.no-lines .no-line__i {
  display: block;
  transform: translate3d(0, 112%, 0);
  transition: transform var(--no-dur-epic, 2.2s) var(--no-ease-cine, cubic-bezier(.25, .46, .45, .94));
  transition-delay: var(--line-delay, 0ms);
  will-change: transform;
}

/* A heading either reveals on its own or on the block that contains it. Both
   routes end here. Which one applies is decided in main.js: a heading sitting
   inside a section head that already reveals is driven by that block, so the
   two motions cannot start at different moments and read as a stutter. */
.no-lines.is-visible .no-line__i,
[data-reveal].is-visible .no-lines .no-line__i { transform: none; }

/* And in that case the block itself only fades: the lines carry the movement,
   and a block that rises while its lines rise inside it reads as mush. */
[data-reveal].no-has-lines { transform: none; }

/* Once it has arrived, drop the compositing hint and the clipping: a heading
   that keeps an overflow context can trim a focus ring or a text shadow. */
.no-lines.is-settled .no-line { overflow: visible; }
.no-lines.is-settled .no-line__i { will-change: auto; }

/* ---------- Hero footage -------------------------------------------------
   A very slow push on the hero, half a percent of scale every few seconds.
   It is deliberately below the threshold at which you would call it an
   animation; it just stops the frame feeling like a still. 40 seconds one
   way, 40 back, so there is no jump at the loop point.

   Only the hero's own video and poster: the section backgrounds that carry
   data-parallax are driven from JS and must keep their transform.
   ---------------------------------------------------------------------- */
@keyframes no-drift {
  from { transform: scale(1.015) translate3d(0, 0, 0); }
  to   { transform: scale(1.075) translate3d(0, -1.1%, 0); }
}
.no-hero__media > video,
.no-hero__media > img,
.no-hero__media > picture > img {
  animation: no-drift 40s var(--no-ease-in-out) infinite alternate;
  animation-play-state: paused;      /* main.js runs it while the hero is on screen */
  will-change: transform;
}
.no-hero__media.is-drifting > video,
.no-hero__media.is-drifting > img,
.no-hero__media.is-drifting > picture > img { animation-play-state: running; }

/* With scripting off nothing toggles the class, so it simply runs. */
.no-no-js .no-hero__media > video,
.no-no-js .no-hero__media > img,
.no-no-js .no-hero__media > picture > img { animation-play-state: running; }

/* ---------- Weighted scroll ----------------------------------------------
   main.js adds .no-inertia to <html> when it takes the wheel over, and drives
   the scroll position itself a frame at a time. Native smooth scrolling has
   to be off while that happens or the two fight each other; explicit
   behavior: 'smooth' calls in script are unaffected by this.
   ---------------------------------------------------------------------- */
html.no-inertia { scroll-behavior: auto; }

/* ---------- Interaction ---------------------------------------------------
   The image inside a card was already the slowest part of a hover. It gets
   slower still, and a shade more travel, because the picture moving under a
   stationary frame is the single most effective piece of slow motion on a
   page full of cards.
   ---------------------------------------------------------------------- */
.no-svccard:hover .no-svccard__media img,
.no-post:hover .no-post__media img,
.no-pcard:hover .no-pcard__media img,
.no-vcard:hover .no-vcard__media img,
.no-core:hover .no-core__media img { transform: scale(1.075); }

/* ---------- Standing down -------------------------------------------------
   base.css already neutralises the reveal system and the parallax under
   prefers-reduced-motion. These are the pieces this layer adds.
   ---------------------------------------------------------------------- */
.no-no-js .no-lines .no-line { overflow: visible; }
.no-no-js .no-lines .no-line__i { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .no-lines .no-line { overflow: visible; }
  .no-lines .no-line__i { transform: none !important; transition: none !important; }
  .no-hero__media > video,
  .no-hero__media > img,
  .no-hero__media > picture > img { animation: none !important; }
}

/* ---------- Two declarations that live in pristine sheets -----------------
   tokens.css is still byte-identical to the file the client handed over, and
   there is value in keeping it that way: it is the sheet most likely to be
   replaced wholesale. The drawer and the mobile accordion are the only motion
   in layout.css, and they were already slowed from here before layout.css was
   touched for the mobile touch-target work, so they have stayed here rather
   than being moved for the sake of it.
   ---------------------------------------------------------------------- */
.no-drawer { transition: transform var(--no-dur-mid, .72s) var(--no-ease-out), visibility var(--no-dur-mid, .72s); }
.no-macc__panel { transition: grid-template-rows var(--no-dur-slow, .95s) var(--no-ease-out); }

/* The block reveal now has further to travel, in proportion to the extra time
   it has been given. Anything shorter than this reads as a plain fade once
   the duration is this long. */
[data-reveal="text"] { transform: translate3d(0, 22px, 0); }

/* ---------- The hero entrance --------------------------------------------
   The one piece of motion nobody scrolls to: it plays while the visitor is
   still deciding whether to stay, so it is worth more time than anything
   below it. The same rise the theme already uses, drawn out and spread
   further apart, so the kicker, the headline lines, the lead and the buttons
   arrive as four separate beats rather than one.

   The headline itself is line-split by main.js and reveals through the .ln
   rule below only when scripting is off, which is why both routes are slowed.
   ---------------------------------------------------------------------- */
.no-hero__kicker      { animation-duration: 1.5s; animation-delay: .12s; }
.no-hero__title .ln   { animation-duration: 1.6s; }
.no-hero__title .ln:nth-child(1) { animation-delay: .3s; }
.no-hero__title .ln:nth-child(2) { animation-delay: .52s; }
.no-hero__lead        { animation-duration: 1.6s; animation-delay: .78s; }
.no-hero__actions     { animation-duration: 1.6s; animation-delay: 1.02s; }
.no-hero__kicker,
.no-hero__title .ln,
.no-hero__lead,
.no-hero__actions { animation-timing-function: var(--no-ease-cine, cubic-bezier(.25, .46, .45, .94)); }

/* The scroll cue and the sonar rings keep their own rhythm, just calmer. */
.no-hero__cue i      { animation-duration: 3.6s; }
.no-hero__sonar span { animation-duration: 8s; }
.no-hero__sonar span:nth-child(2) { animation-delay: 2.66s; }
.no-hero__sonar span:nth-child(3) { animation-delay: 5.32s; }
.no-marquee__track   { animation-duration: 96s; }

/* A continuously scaling full-bleed video is the most expensive thing on the
   page, and on a phone it buys the least: the hero is short, it is scrolled
   past in one flick, and the cost is paid in battery. Above tablet width only. */
@media (max-width: 900px) {
  .no-hero__media > video,
  .no-hero__media > img,
  .no-hero__media > picture > img { animation: none; }
}
