/**
 * Motion — the Neopoet motion layer.
 *
 * DESIGN.md's principle stands: motion confirms what the user did; the
 * interface does not perform for you. This layer names the three verbs
 * the system is allowed to speak and gives each one a home:
 *
 *   1. CONFIRM — 120/160ms feedback tied to a user action: hover tints
 *      (already living in each component's own CSS), the button press,
 *      the like-heart pop. Allowed everywhere, including calm pages,
 *      because it is a response, not a performance.
 *
 *   2. ARRIVE — one orchestrated entrance on entrance pages only
 *      (dashboard home, contest index, anthology landing, onboarding
 *      completion — exactly the surfaces DESIGN.md marks expressive).
 *      The structural persimmon rule draws itself down, then the
 *      headline and meta line rise in a short stagger. The brand mark
 *      performs arrival once; nothing else on the page moves. Poem
 *      detail, critique threads, and composition forms never arrive —
 *      they are simply there ("calm page").
 *
 *   3. SETTLE — content that streams in after first paint (BigPipe
 *      placeholders, AJAX inserts) fades in over 240ms instead of
 *      popping. This is functional motion: it masks a mechanical
 *      artifact the reader currently experiences as a flicker.
 *      Applied via .np-settle by js/motion-settle.js, which only
 *      marks content attached after the initial document — server-
 *      rendered pages never replay it. Opacity only, no transform:
 *      streamed fragments may contain fixed/sticky descendants, and a
 *      persisting ancestor transform would re-parent them.
 *
 * Every duration and distance is a token; all of it collapses under
 * prefers-reduced-motion via the guards in tokens.css.
 */

/* -----------------------------------------------------------------------
 * 2. ARRIVE — entrance-header sequence.
 *    Timeline: rule draws 0→400ms; headline rises at 90ms; meta at 180ms.
 *    fill: both — elements hold their hidden from-state during their
 *    stagger delay, so the sequence reads as one composition, not a race.
 * --------------------------------------------------------------------- */
@keyframes np-rule-draw {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

@keyframes np-rise-in {
  from { opacity: 0; transform: translateY(var(--np-motion-rise)); }
  to   { opacity: 1; transform: translateY(0); }
}

.np-entrance-header__rule {
  transform-origin: top;
  animation: np-rule-draw var(--np-duration-gentle) var(--np-ease-emphasis) both;
}

.np-entrance-header__headline {
  animation: np-rise-in var(--np-duration-gentle) var(--np-ease-emphasis) both;
  animation-delay: var(--np-stagger);
}

.np-entrance-header__meta {
  animation: np-rise-in var(--np-duration-gentle) var(--np-ease-emphasis) both;
  animation-delay: calc(var(--np-stagger) * 2);
}

/* The dashboard hero is today's live arrival surface (the entrance-header
 * partial above is the specced pattern, not yet wired into any page).
 * Same sequence, same beats: greeting rises, the featured-contest line
 * follows one stagger later. The greeting's per-user text still streams
 * in via BigPipe and settles independently — shell and content each do
 * their own small move. */
.np-hero__greeting {
  animation: np-rise-in var(--np-duration-gentle) var(--np-ease-emphasis) both;
}

.np-hero__sub {
  animation: np-rise-in var(--np-duration-gentle) var(--np-ease-emphasis) both;
  animation-delay: var(--np-stagger);
}

/* New-member welcome — onboarding is an expressive_allowed_in surface and
 * is the top of the page for exactly the readers meeting the site for the
 * first time. Title and lede take the same two beats; the three action
 * cards stay still (they are the work, not the welcome). */
.np-welcome__title {
  animation: np-rise-in var(--np-duration-gentle) var(--np-ease-emphasis) both;
}

.np-welcome__lede {
  animation: np-rise-in var(--np-duration-gentle) var(--np-ease-emphasis) both;
  animation-delay: var(--np-stagger);
}

/* -----------------------------------------------------------------------
 * 3. SETTLE — streamed content fades in rather than popping.
 *    No forwards fill and no transform: nothing persists after the
 *    animation, and fixed/sticky descendants are never re-parented.
 * --------------------------------------------------------------------- */
@keyframes np-settle-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.np-settle {
  animation: np-settle-in var(--np-duration-slow) var(--np-ease-standard);
}

/* Toggle confirmations pop rather than fade: when the like/follow heart
 * is swapped by flag's AJAX response, the fresh link lands with a small
 * press-and-release. CONFIRM, not SETTLE — it answers a click. */
@keyframes np-pop {
  0%   { transform: scale(0.85); }
  65%  { transform: scale(1.06); }
  100% { transform: scale(1); }
}

.np-settle.flag {
  animation: np-pop var(--np-duration-base) var(--np-ease-emphasis);
}

/* -----------------------------------------------------------------------
 * 1. CONFIRM — the tactile press.
 *    Buttons compress by 1px while held. Instant down (a press is a
 *    press), the existing hover transitions carry the release. :where()
 *    keeps specificity at zero so component CSS always wins if it
 *    disagrees.
 * --------------------------------------------------------------------- */
:where(button,
       .button,
       input[type="submit"],
       input[type="button"]):active:not(:disabled) {
  transform: translateY(1px);
}
