/* ORBINTU global motion system — ONE language for route changes and scroll reveals (behaviour: motion.js).

   Motion means something here:  dim → on = context / capability activated · line draw = work progressing ·
   orange = human authority, selected or verified · lock = verified. Typography never animates with a moving line or mask:
   text simply resolves (fade + a few px rise from below).
   Reveals run once. Nothing loops except real live status (the ORBI / LIVE dock); the orange O moves once per real state change, then settles.

   Safety: every hidden start state is gated by html.ob-motion, which the <head> script sets only when motion is allowed
   (not prefers-reduced-motion) and removes again (html.ob-motion-off) if motion.js never starts. Without JS, or with
   reduced motion, all content is simply visible. The shell (header, page background) never animates. */
:root {
  /* tokens */
  --motion-fast: 160ms;        /* micro UI: hover, focus, state flips */
  --motion-ui: 220ms;          /* small interface transitions */
  --motion-text: 380ms;        /* paragraph / small content reveal */
  --motion-section: 520ms;     /* panels, large blocks */
  --motion-line: 600ms;        /* a system line drawing */
  --motion-diagram: 900ms;     /* the whole of a diagram sequence — never longer */
  --motion-rise: 10px;         /* how far text travels as it settles */
  --ease-orbi: cubic-bezier(.2, .7, .2, 1);     /* the one ORBINTU curve: quick start, precise settle */
  --ease-enter: cubic-bezier(.16, 1, .3, 1);
  --ease-exit: cubic-bezier(.4, 0, 1, 1);
  --ease-system: cubic-bezier(.4, 0, .2, 1);

  /* route change: fast — navigation should feel instantaneous */
  --motion-route-exit: 140ms;
  --motion-route-enter: 200ms;
  --motion-route-overlap: 60ms;
  --motion-shift: 6px;         /* route entry rises this far from BELOW its place; never from above */
  --motion-bg: lab(2.75381 0 0);     /* == page background: nothing ever shows a different colour */
}
@media (max-width: 767px) { :root { --motion-rise: 6px; --motion-shift: 4px; --motion-line: 480ms; } }
html { background-color: var(--motion-bg); }

/* ───────── RouteTransition (cross-document View Transitions) ───────── */
@view-transition { navigation: auto; }
body > header { view-transition-name: ob-shell; }
::view-transition { background: var(--motion-bg); }
::view-transition-group(root), ::view-transition-group(ob-shell) { animation: none; }
::view-transition-image-pair(root) { isolation: auto; }
::view-transition-old(ob-shell) { display: none; }
::view-transition-new(ob-shell) { animation: none; }
::view-transition-old(root), ::view-transition-new(root) { mix-blend-mode: normal; }
::view-transition-old(root) { animation: ob-route-out var(--motion-route-exit) var(--ease-exit) both; }
::view-transition-new(root) { animation: ob-route-in var(--motion-route-enter) var(--ease-orbi) var(--motion-route-overlap) both; }
@keyframes ob-route-out { to { opacity: 0; } }   /* leaving: fade only — content never moves up toward the header */
@keyframes ob-route-in { from { opacity: 0; transform: translateY(var(--motion-shift)); } }
/* browsers without cross-document view transitions (motion.js adds .ob-vt-fallback / .ob-leaving): same motion on the content layer */
.ob-vt-fallback main, .ob-vt-fallback footer { animation: ob-route-in var(--motion-route-enter) var(--ease-orbi) both; }
.ob-vt-fallback.ob-leaving main, .ob-vt-fallback.ob-leaving footer { animation: ob-route-out var(--motion-route-exit) var(--ease-exit) forwards; }

/* click feedback: the nav item answers immediately, before the page has changed */
header a[data-leaving] > div:first-child, header a[data-leaving] { color: var(--copper-500); }
header a[data-leaving] > div:first-child { box-shadow: inset 0 -3px 0 var(--copper-500); transition: box-shadow var(--motion-fast) steps(3), color var(--motion-fast) steps(3); }

/* ───────── Reveal: shared start states (only while html.ob-motion) ─────────
   motion.js tags elements with data-reveal="text|label|pixel|line|panel|icon|chain" from ONE selector map and adds .is-in
   when ~15% of the element is in view (once). Elements already passed or in view on a deep link get .is-now (no motion).
   --rd = extra delay inside a composed sequence. */
.ob-motion [data-reveal] { transition-delay: var(--rd, 0ms); }
.ob-motion [data-reveal].is-now, .ob-motion [data-reveal].is-now * { transition: none !important; animation-delay: 0s !important; animation-duration: 0s !important; }
.ob-rv-init [data-reveal], .ob-rv-init [data-reveal] *, .ob-rv-init [data-reveal]::before, .ob-rv-init [data-reveal] *::before, .ob-rv-init [data-reveal]::after, .ob-rv-init [data-reveal] *::after { transition: none !important; }

/* text: almost below conscious attention */
.ob-motion [data-reveal="text"]:not(.is-in) { opacity: 0; transform: translateY(var(--motion-rise)); }
.ob-motion [data-reveal="text"] { transition-property: opacity, transform; transition-duration: var(--motion-text); transition-timing-function: var(--ease-orbi); }

/* panel: a large block settles */
.ob-motion [data-reveal="panel"]:not(.is-in) { opacity: 0; transform: translateY(calc(var(--motion-rise) + 4px)); }
.ob-motion [data-reveal="panel"] { transition-property: opacity, transform; transition-duration: var(--motion-section); transition-timing-function: var(--ease-orbi); }

/* label: a small system label simply appears — fade + a 5 px rise (no line, no wipe) */
.ob-motion [data-reveal="label"]:not(.is-in) { opacity: 0; transform: translateY(5px); }
.ob-motion [data-reveal="label"] { transition: opacity 300ms var(--ease-orbi), transform 300ms var(--ease-orbi); }

/* pixel display heading: the DOM text exists from the start; the heading resolves in place — fade + an 8 px rise from
   below (no scan line, no moving mask edge) */
.ob-motion [data-reveal="pixel"]:not(.is-in) { opacity: 0; transform: translateY(8px); }
.ob-motion [data-reveal="pixel"] { transition: opacity 420ms var(--ease-orbi), transform 420ms var(--ease-orbi); }

/* line: a system line draws in the direction of the work */
.ob-motion [data-reveal="line"]:not(.is-in) { transform: scaleX(0); }
.ob-motion [data-reveal="line"] { transform-origin: left center; transition: transform var(--motion-line) var(--ease-orbi); }

/* icon: resolves with a 3 px rise and one short highlight */
.ob-motion [data-reveal="icon"]:not(.is-in) { opacity: 0; transform: translateY(3px); }
.ob-motion [data-reveal="icon"] { transition: opacity var(--motion-ui) var(--ease-orbi), transform var(--motion-ui) var(--ease-orbi); }

/* chain: a process — each step activates in order and the connector to the next step draws.
   motion.js sets --ri (step index) and --rstep (gap, so the whole chain fits in --motion-diagram). */
.ob-motion [data-reveal="chain"] > [data-rs] { transition: opacity var(--motion-ui) var(--ease-orbi), transform var(--motion-ui) var(--ease-orbi);
  transition-delay: calc(var(--rd, 0ms) + var(--ri, 0) * var(--rstep, 120ms)); }
.ob-motion [data-reveal="chain"]:not(.is-in) > [data-rs] { opacity: .18; transform: translateY(2px); }
.ob-motion [data-reveal="chain"] > [data-rc] { transform-origin: left center; transition: transform var(--motion-ui) var(--ease-orbi);
  transition-delay: calc(var(--rd, 0ms) + var(--ri, 0) * var(--rstep, 120ms) + 60ms); }
.ob-motion [data-reveal="chain"]:not(.is-in) > [data-rc] { transform: scaleX(0); }

/* ───────── PageEnter: inner-page heroes (crumb → heading → lead → actions) ───────── */
.ob-motion .ob-phero__in > * { animation: ob-settle var(--motion-text) var(--ease-orbi) both; animation-delay: calc(var(--motion-route-overlap) + var(--st, 0ms)); }
.ob-phero__in > .ob-crumb { --st: 0ms; } .ob-phero__in > .ob-h1 { --st: 60ms; } .ob-phero__in > .ob-lead { --st: 120ms; } .ob-phero__in > .ob-ctas, .ob-phero__in > .ob-phero__cube { --st: 160ms; }
@keyframes ob-settle { from { opacity: 0; transform: translateY(var(--motion-rise)); } }

/* ───────── micro interactions (all screens; not motion-gated because they are state feedback) ───────── */
/* an arrow inside a link moves 3 px toward where the link goes */
a:is(:hover, :focus-visible) > i[aria-hidden="true"]:not([class]) { transform: translateX(3px); }
a > i[aria-hidden="true"]:not([class]) { display: inline-block; transition: transform var(--motion-fast) steps(3); }

/* ───────── reduced motion: everything is simply there; route change is a short crossfade ───────── */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root) { animation: ob-fade-out 120ms linear both; }
  ::view-transition-new(root) { animation: ob-fade-in 160ms linear both; }
  @keyframes ob-fade-out { to { opacity: 0; } } @keyframes ob-fade-in { from { opacity: 0; } }
  .ob-vt-fallback main, .ob-vt-fallback footer { animation: ob-fade-in 160ms linear both; } .ob-vt-fallback.ob-leaving main, .ob-vt-fallback.ob-leaving footer { animation: ob-fade-out 120ms linear forwards; }
  .ob-phero__in > * { animation: none !important; }
  a > i[aria-hidden="true"]:not([class]) { transition: none; }
}
/* failsafe: if motion.js never started, the head script adds .ob-motion-off and every start state is released */
.ob-motion-off [data-reveal], .ob-motion-off [data-reveal] * { opacity: 1 !important; transform: none !important; clip-path: none !important; }
