/* ==========================================================================
   B&A AI Center of Excellence — Motion system
   Source of truth: _loop/design-system.md §Motion · measured: _loop/bar-motion.md
   Loaded after styles.css by components.js (or the page head). Pairs with motion.js.

   Three easings, discrete duration bands, opacity/transform/mask only.
   API (attributes / classes):
     [data-hero]                       hero root; motion.js runs the staged entrance inside it
     [data-anim="mask"]                mask + blur wipe, .8s   (hero headline only)
     [data-anim="fade"]                opacity 0 → 1, .48s      (hero subline / showcase / CTA)
     [data-anim="slide-right"]         panel enters from the right edge, translateX 24px → 0, .7s
     [data-anim="slide-left"]          panel enters from the left edge,  translateX -24px → 0, .7s
     [data-anim-delay="300"]           explicit delay (ms, or a CSS time) → --anim-delay
     [data-stagger]                    children dotIn (opacity 0 + scale .4 → 1, .3s) 16ms × --i apart
     [data-stagger="line"]             children append (fade .16s) 120ms × --i apart
     .is-in                            added by motion.js (IntersectionObserver .35, once) — starts the animation
     .shimmer                          2s linear infinite background-position sweep on a label
     .cursor                           1s steps(2) blinking caret
   Text outside [data-hero] never carries data-anim.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  --ease-ui:    cubic-bezier(.25, .46, .45, .94); /* hover + UI states */
  --ease-enter: cubic-bezier(.22, 1, .36, 1);     /* entrances */
  --ease-move:  cubic-bezier(.32, .72, 0, 1);     /* big panel moves */

  --dur-hover: .1s;
  --dur-ui:    .16s;
  --dur-pop:   .18s;
  --dur-mark:  .3s;   /* dotIn marks/rows — the one mark duration the system specifies */
  --dur-enter: .48s;
  --dur-mask:  .8s;
  --dur-move:  .7s;
  --dur-loop:  2s;

  /* Legacy tokens from styles.css are remapped onto the system so every older
     transition lands in the UI band on the UI curve. */
  --ease: var(--ease-ui);
  --dur:  var(--dur-ui);
}

/* --------------------------------------------------------------------------
   2. Keyframes
   -------------------------------------------------------------------------- */
@keyframes mask {
  from { opacity: 0; filter: blur(6px); -webkit-mask-position: 120% 0; mask-position: 120% 0; }
  to   { opacity: 1; filter: none;      -webkit-mask-position: 0 0;    mask-position: 0 0; }
}
@keyframes fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes slideRight {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes slideLeft {
  from { opacity: 0; transform: translateX(-24px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes dotIn {
  from { opacity: 0; transform: scale(.4); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes scaleIn {
  from { opacity: 0; transform: scale(.98); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes shimmer {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}
@keyframes cursorBlink {
  from { opacity: 1; }
  to   { opacity: 0; }
}

/* --------------------------------------------------------------------------
   3. Entrance primitives — hidden until motion.js adds .is-in
   Scoped to html.js so a page without scripts renders everything opaque.
   -------------------------------------------------------------------------- */
html.js [data-anim] { opacity: 0; }

html.js [data-anim="mask"].is-in {
  --mask-grad: linear-gradient(to right, #000 25%, rgba(0, 0, 0, .9) 50%, rgba(0, 0, 0, 0) 100%);
  -webkit-mask-image: var(--mask-grad);
          mask-image: var(--mask-grad);
  -webkit-mask-size: 400% 100%;
          mask-size: 400% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  animation: mask var(--dur-mask) var(--ease-enter) var(--anim-delay, 0s) both;
}
html.js [data-anim="fade"].is-in {
  animation: fade var(--dur-enter) var(--ease-enter) var(--anim-delay, 0s) both;
}
html.js [data-anim="slide-right"].is-in {
  animation: slideRight var(--dur-move) var(--ease-move) var(--anim-delay, 0s) both;
}
html.js [data-anim="slide-left"].is-in {
  animation: slideLeft var(--dur-move) var(--ease-move) var(--anim-delay, 0s) both;
}

/* Stagger — children populate 16ms apart; --i is set per child by motion.js.
   Rows/cells/text children FADE (rowIn, opacity only — text never scales);
   only marks (SVG circles/rects/paths, bar <i>s) get dotIn's .4 → 1 scale. */
@keyframes rowIn { from { opacity: 0; } to { opacity: 1; } }
html.js [data-stagger] > * { opacity: 0; }
html.js [data-stagger].is-in > * {
  animation: rowIn var(--dur-mark) var(--ease-ui) calc(var(--anim-delay, 0s) + var(--i, 0) * 16ms) both;
}
html.js [data-stagger].is-in > circle,
html.js [data-stagger].is-in > rect,
html.js [data-stagger].is-in > path,
html.js .ui-bars[data-stagger].is-in > i { animation-name: dotIn; }
/* SVG marks scale about their own centre; bars grow from their baseline */
[data-stagger] > circle,
[data-stagger] > rect,
[data-stagger] > path { transform-box: fill-box; transform-origin: center; }
.ui-bars[data-stagger] > i { transform-origin: 50% 100%; }

/* Log lines append 120ms apart */
html.js [data-stagger="line"].is-in > * {
  animation: fade var(--dur-ui) var(--ease-ui) calc(var(--anim-delay, 0s) + var(--i, 0) * 120ms) both;
}

/* Popovers / menus */
.pop { animation: scaleIn var(--dur-pop) var(--ease-ui) both; }
/* The shell's one menu: the ≤900px nav opened by .nav-toggle (components.js toggles .is-open) */
html.js .site-header.is-open .nav-links {
  transform-origin: top right;
  animation: scaleIn var(--dur-pop) var(--ease-ui) both;
}
@media (prefers-reduced-motion: reduce) {
  html.js .site-header.is-open .nav-links { animation: none; }
}

/* --------------------------------------------------------------------------
   4. Ambient loops — small, low-contrast, never on headings / body / nav
   -------------------------------------------------------------------------- */
.shimmer {
  display: inline-block;
  color: transparent;
  background-image: linear-gradient(90deg,
    var(--shimmer-base, var(--fog)) 0%,
    var(--shimmer-base, var(--fog)) 35%,
    var(--shimmer-hi,   var(--mist)) 50%,
    var(--shimmer-base, var(--fog)) 65%,
    var(--shimmer-base, var(--fog)) 100%);
  background-size: 300% 100%;
  background-position: 0 0;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
          background-clip: text;
  animation: shimmer var(--dur-loop) linear infinite;
}
.cursor {
  display: inline-block;
  width: 7px;
  height: 1em;
  vertical-align: text-bottom;
  background: var(--mist);
  animation: cursorBlink 1s steps(2, jump-none) infinite;
}

/* --------------------------------------------------------------------------
   5. Hover — every interactive element in the shell, three signatures:
      text/links       color .1s  --ease-ui
      buttons/pills    filter, transform, background .16s --ease-ui
      surface tints    background .4s ease-out
   -------------------------------------------------------------------------- */

/* Text + links */
.nav-link,
.nav-brand,
.link-arrow,
.footer-col a,
.footer-bottom a,
.ui-tab,
.ui-source,
.ui-source-title {
  transition: color var(--dur-hover) var(--ease-ui);
}
.link-arrow::after { transition: transform var(--dur-ui) var(--ease-ui); }

/* Buttons / pills / icons */
.btn-primary,
.nav-cta,
.ui-btn-white {
  transition: filter var(--dur-ui) var(--ease-ui),
              transform var(--dur-ui) var(--ease-ui),
              background var(--dur-ui) var(--ease-ui);
}
.btn-primary:hover  { filter: brightness(1.08); }
.nav-cta:hover      { filter: brightness(1.08); transform: translateY(-1px); }
.ui-btn-white:hover { filter: brightness(1.08); }
.btn-ghost {
  transition: color var(--dur-hover) var(--ease-ui),
              box-shadow var(--dur-ui) var(--ease-ui),
              filter var(--dur-ui) var(--ease-ui),
              transform var(--dur-ui) var(--ease-ui),
              background var(--dur-ui) var(--ease-ui);
}
.logo-strip img { transition: filter var(--dur-ui) var(--ease-ui); }
.input { transition: border-color var(--dur-ui) var(--ease-ui); }
.ui-tab:hover { color: var(--mist); }

/* Surface tints — rows, nav items, clauses */
.ui-tr,
.ui-nav-item,
.ui-clause {
  transition: background .4s ease-out;
}
.ui-tr:not(.ui-tr--head):not(.is-selected):hover { background: rgba(255, 255, 255, .02); }
.ui-nav-item:not(.is-active):hover { background: rgba(255, 255, 255, .03); }
.ui-clause:not(.is-active):hover   { background: rgba(255, 255, 255, .03); }

/* --------------------------------------------------------------------------
   6. Reduced motion — every duration 0, final states, loops stop
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-hover: 0s; --dur-ui: 0s; --dur-pop: 0s; --dur-mark: 0s;
    --dur-enter: 0s; --dur-mask: 0s; --dur-move: 0s; --dur-loop: 0s;
  }
  *, *::before, *::after {
    transition-duration: 0s !important;
    animation-duration: 0s !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
  }
  html.js [data-anim],
  html.js [data-stagger] > *,
  .pop {
    opacity: 1 !important;
    transform: none !important;
    -webkit-mask-image: none !important;
            mask-image: none !important;
    animation: none !important;
  }
  /* Only the mask wipe uses a filter (blur). Everything else keeps its own filter —
     greyscale figures, portraits and mono frames must not leak colour under reduced motion. */
  html.js [data-anim="mask"] { filter: none !important; }
  .shimmer { animation: none !important; background-position: 0 0 !important; }
  .cursor  { animation: none !important; opacity: 1 !important; }
}
