/* Vector family — motion layer.
 *
 * Personality: Corporate / rigid material. This design language is
 * neobrutalist: 2px ink borders and hard offset block shadows with no blur.
 * Motion is therefore decisive and lands flat — zero overshoot. Elastic or
 * bouncy easing would read as a softer material than the borders imply.
 *
 * Three layers:
 *   primary   — the element rises and fades into place.
 *   secondary — the block shadow lifts on hover and presses in on click.
 *               That is physically coherent with a hard offset shadow: the
 *               surface is moving over the page, so its shadow moves too.
 *   ambient   — deliberately absent. A data cockpit should not shimmer;
 *               ambient motion would compete with the numbers.
 *
 * Colour, type and layout are untouched by this file.
 *
 * Of the family this app had the least motion: no `transition`, no
 * `@keyframes` and no `prefers-reduced-motion` anywhere in the shell. The
 * `.btn:active` press in unified.css had the right geometry but no timing,
 * so it snapped between states.
 *
 * Load order note: this must come after unified.css, which is where the
 * --ink / --shadow-block tokens are defined.
 */

:root{
  /* Signature curves. One standard, one emphasized, one exit. */
  --ease-standard:   cubic-bezier(.2, 0, 0, 1);   /* interaction, on-screen */
  --ease-emphasized: cubic-bezier(.16, 1, .3, 1); /* expo.out — entrances */
  --ease-exit:       cubic-bezier(.3, 0, 1, 1);   /* accelerate — dismissal */

  /* Duration palette. */
  --dur-quick: 90ms;   /* hover + press, under the 100ms feedback floor */
  --dur-base:  260ms;  /* cards and panels */
  --dur-slow:  420ms;  /* modals and page-level reveals */

  /* Choreography. */
  --vx-stagger: 50ms;  /* 6 steps = 300ms, inside the 500ms budget */
  --vx-rise:    12px;  /* entrance travel */
  --vx-lift:     2px;  /* hover displacement */
}

/* ---------- primary: entrance ----------
 * Opacity is never the only channel; position carries the change too. */
@keyframes vx-rise{
  from{ opacity:0; transform:translateY(var(--vx-rise)); }
  to  { opacity:1; transform:none; }
}

.vx-rise{ animation: vx-rise var(--dur-base) var(--ease-emphasized) both; }

/* Cascade. Capped at six steps so the tail never outruns the budget. */
[data-vx-stagger] > *{
  animation: vx-rise var(--dur-base) var(--ease-emphasized) both;
}
[data-vx-stagger] > :nth-child(1){ animation-delay: 0ms; }
[data-vx-stagger] > :nth-child(2){ animation-delay: calc(var(--vx-stagger) * 1); }
[data-vx-stagger] > :nth-child(3){ animation-delay: calc(var(--vx-stagger) * 2); }
[data-vx-stagger] > :nth-child(4){ animation-delay: calc(var(--vx-stagger) * 3); }
[data-vx-stagger] > :nth-child(5){ animation-delay: calc(var(--vx-stagger) * 4); }
[data-vx-stagger] > :nth-child(n+6){ animation-delay: calc(var(--vx-stagger) * 5); }

/* ---------- secondary: lift and press ----------
 * .btn already presses to translate(1px,1px) with the shadow dropping
 * 3px -> 1px. The hover here is the matching lift, scaled to that same
 * 3px base shadow rather than the family's 4px so the button keeps its
 * own proportions. */
.btn{
  transition: transform  var(--dur-quick) var(--ease-standard),
              box-shadow var(--dur-quick) var(--ease-standard);
}
.btn:hover{
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 var(--ink);
}
/* :active is restated here on purpose. unified.css declares .btn:active
 * earlier in the cascade, and a held click matches :hover and :active at
 * once — both at the same specificity, so the later rule wins. Without this
 * the hover lift above would swallow the press. */
.btn:active{
  transform: translate(1px, 1px);
  box-shadow: 1px 1px 0 var(--ink);
}

/* .card is a surface, not a control, and its resting shadow comes from
 * var(--shadow) rather than the block tokens — so it gets timing for any
 * state change but no hover lift of its own. */
.card{
  transition: transform  var(--dur-quick) var(--ease-standard),
              box-shadow var(--dur-quick) var(--ease-standard);
}

/* Focus rings must not ease in — a keyboard user needs the ring immediately. */
a:focus-visible,
button:focus-visible{ transition: none; }

/* ---------- reduced motion ----------
 * This shell previously had no gate at any level. It covers the rules above
 * and any animation added later without a gate of its own. */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .vx-rise,
  [data-vx-stagger] > *{ opacity:1; transform:none; }
}
