/* A short arrival for the reading, in the chapter's own composition.
   No pending/hidden rule: these keyframes exist only while an arrival plays.
   Individual translate leaves authored transform geometry with its owner. */
@media screen and (prefers-reduced-motion: no-preference) {
  .is-reading-arriving {
    --reading-x: 0px;
    --reading-y: 10px;
    --reading-from: .25;
    animation: reading-arrive 580ms cubic-bezier(.16, 1, .3, 1) var(--reading-delay, 0ms) backwards;
  }
  /* The controller primes an arrival while its unit is still outside the
     window, so the opening pose is in place before the reader can see it,
     and it plays the arrival when the unit crosses its line. Starting an
     entrance on the crossing itself would hide copy the reader had already
     seen at rest, one frame earlier, and then bring it back as a flash. */
  .is-reading-arriving[data-reading-held] { animation-play-state: paused; }
  [data-reading-motion="chronology"] { --reading-y: 8px; }
  [data-reading-motion="record"] { --reading-x: -10px; --reading-y: 0px; --reading-from: .45; animation-duration: 420ms; }
  :where(.timeline:not(.is-list-view) .record-row[data-side="left"]) [data-reading-motion="record"] { --reading-x: 10px; }
  [data-reading-motion="settle"] { --reading-y: 8px; --reading-from: .4; animation-duration: 620ms; }
  [data-reading-motion="catalogue"] { --reading-x: -6px; --reading-y: 0px; --reading-from: .5; animation-duration: 440ms; }
  [data-reading-motion="closing"] { --reading-y: 12px; animation-duration: 680ms; }

  /* About's own observer uses each vessel as its scroll root. These existing
     hooks introduce the next passage without moving the vessel or portrait. */
  #sec-about.about-ready [data-about-arriving] {
    --reading-x: 0px; --reading-y: 10px; --reading-from: .4;
    animation: reading-arrive 600ms cubic-bezier(.16, 1, .3, 1) backwards;
  }
  #sec-about.about-ready .about-portrait[data-about-arriving] { --reading-y: 0px; }
  .is-reading-arriving:focus-within,
  #sec-about.about-ready [data-about-arriving]:focus-within { animation: none; }
}
@keyframes reading-arrive {
  from { opacity: var(--reading-from, .4); translate: var(--reading-x, 0px) var(--reading-y, 8px); }
  to { opacity: 1; translate: 0 0; }
}

/* ---------------------------------------------------------------------------
   Passage: 01 Frames, 02 Measurement and 03 Claims-makers
   ---------------------------------------------------------------------------
   These three rooms read with the cadence Money's Passage sets, so that a
   reader who moves from Claims-makers into Money meets one motion language
   rather than two. A statement and its copy travel in from the left, the
   evidence that answers them travels in from the right, and each part rises
   from nothing over 620ms on Money's own ease-out, a few frames behind the
   part before it.

   Because a table, a bar and a numeral are not paragraphs, each kind of
   element then takes the gesture that describes what it is. A numeral rises
   out of its own baseline, since its value is printed rather than counted;
   the bars of one comparison grow from zero on a single clock, so that their
   ratio is exact at every frame; a persistence rail runs from its first
   year to its last, and each reference lands as the rail reaches it; a node
   lands as a drop and settles into the square of its grid; a table lays down
   its two axes before its marks arrive at their coordinates.

   Every keyframe below either names only its starting pose, so that the
   part settles onto whatever its own stylesheet says it is, or names both
   ends only for a clip or a pour, which have no resting value to settle
   onto. Nothing here holds a part hidden once its animation is over, and
   the controller removes the class the moment it is. */
@media screen and (prefers-reduced-motion: no-preference) {
  .is-reading-arriving[data-reading-motion^="passage-"] {
    animation-duration: 620ms;
    animation-timing-function: cubic-bezier(.33, 1, .68, 1);
    animation-delay: var(--reading-delay, 0ms);
    animation-fill-mode: backwards;
    animation-iteration-count: 1;
  }
  .is-reading-arriving[data-reading-motion="passage-statement"],
  .is-reading-arriving[data-reading-motion="passage-left"] { animation-name: reading-passage-left; }
  .is-reading-arriving[data-reading-motion="passage-right"] { animation-name: reading-passage-right; }
  .is-reading-arriving[data-reading-motion="passage-rise"] { animation-name: reading-passage-rise; animation-duration: 600ms; }
  .is-reading-arriving[data-reading-motion="passage-fade"] { animation-name: reading-passage-fade; animation-duration: 520ms; }
  .is-reading-arriving[data-reading-motion="passage-row"] { animation-name: reading-passage-row; animation-duration: 560ms; }
  .is-reading-arriving[data-reading-motion="passage-deal"] { animation-name: reading-passage-deal; animation-duration: 680ms; }
  .is-reading-arriving[data-reading-motion="passage-closing"] { animation-name: reading-passage-closing; animation-duration: 760ms; }
  .is-reading-arriving[data-reading-motion="passage-numeral"] { animation-name: reading-passage-numeral; animation-duration: 760ms; }
  .is-reading-arriving[data-reading-motion="passage-name"] { animation-name: reading-passage-name; animation-duration: 480ms; }
  .is-reading-arriving[data-reading-motion="passage-tick"] { animation-name: reading-passage-tick; animation-duration: 420ms; }

  /* Marks and nodes land on the softer curve Money uses for its dots. */
  .is-reading-arriving:is([data-reading-motion="passage-bloom"], [data-reading-motion="passage-dot"], [data-reading-motion="passage-node"], [data-reading-motion="passage-node-split"]) {
    animation-timing-function: cubic-bezier(.16, 1, .3, 1);
  }
  .is-reading-arriving[data-reading-motion="passage-bloom"] { animation-name: reading-passage-bloom; animation-duration: 480ms; }
  .is-reading-arriving[data-reading-motion="passage-node"] { animation-name: reading-passage-node; animation-duration: 640ms; }
  /* A split mark carries a second frame. Its ring lands first, and the half
     it carries pours in from the left edge once the ring has settled. The
     table sets its fill with the background shorthand, which would tile the
     pour into stripes, so the arrival alone insists on a single image. */
  .is-reading-arriving[data-reading-motion="passage-node-split"] {
    animation-name: reading-passage-node-split;
    animation-duration: 760ms;
    background-repeat: no-repeat !important;
  }

  /* Geometry that grows keeps its start edge fixed, which is where a bar's
     zero and a rail's first year are. */
  .is-reading-arriving[data-reading-motion="passage-grow"] {
    animation-name: reading-passage-grow;
    animation-duration: 900ms;
    transform-origin: 0 50%;
  }
  .is-reading-arriving[data-reading-motion="passage-lay"] { animation-name: reading-passage-lay; animation-duration: 560ms; }
  .is-reading-arriving[data-reading-motion="passage-wipe"] { animation-name: reading-passage-wipe; animation-duration: 720ms; }
  .is-reading-arriving[data-reading-motion="passage-unroll"] { animation-name: reading-passage-unroll; animation-duration: 820ms; }
  .is-reading-arriving[data-reading-motion="passage-plate"] { animation-name: reading-passage-plate; animation-duration: 640ms; }

  /* A chart draws in its own coordinates: rules lengthen from the axis, the
     series line is traced, and each observation lands on the drawn line. */
  .is-reading-arriving:is([data-reading-motion="passage-grid"], [data-reading-motion="passage-dot"]) { transform-box: fill-box; }
  .is-reading-arriving[data-reading-motion="passage-grid"] {
    animation-name: reading-passage-grow;
    animation-duration: 700ms;
    transform-origin: 0 50%;
  }
  .is-reading-arriving[data-reading-motion="passage-dot"] {
    animation-name: reading-passage-bloom;
    animation-duration: 420ms;
    transform-origin: 50% 50%;
  }
  .is-reading-arriving[data-reading-motion="passage-draw"] {
    animation-name: reading-passage-draw;
    animation-duration: var(--reading-run, 1200ms);
    stroke-dasharray: var(--reading-length, 0);
  }
}

/* Money turns its copy and its evidence into rises once a room is too narrow
   to hold them side by side, and keeps the statement traveling from the
   left. These rooms make the same turn at the same width. */
@media screen and (max-width: 900px) and (prefers-reduced-motion: no-preference) {
  .is-reading-arriving:is([data-reading-motion="passage-left"], [data-reading-motion="passage-right"]) { animation-name: reading-passage-rise; }
}

@keyframes reading-passage-left { from { opacity: 0; translate: -26px 0; } }
@keyframes reading-passage-right { from { opacity: 0; translate: 26px 0; } }
@keyframes reading-passage-rise { from { opacity: 0; translate: 0 18px; } }
@keyframes reading-passage-fade { from { opacity: 0; } }
@keyframes reading-passage-row { from { opacity: 0; translate: -20px 0; } }
@keyframes reading-passage-deal { from { opacity: 0; translate: 0 28px; scale: .965; } }
@keyframes reading-passage-closing { from { opacity: 0; translate: -34px 0; } }
@keyframes reading-passage-name { from { opacity: 0; translate: 0 10px; } }
@keyframes reading-passage-tick { from { opacity: 0; translate: 0 -8px; } }
@keyframes reading-passage-plate { from { opacity: 0; translate: 0 16px; } }
@keyframes reading-passage-bloom { from { opacity: 0; scale: .25; } }
@keyframes reading-passage-grow { from { scale: 0 1; } }
@keyframes reading-passage-draw { from { stroke-dashoffset: var(--reading-length, 0); } }
@keyframes reading-passage-node { from { opacity: 0; scale: .2; border-radius: 50%; } }
@keyframes reading-passage-node-split {
  0% { opacity: 0; scale: .2; border-radius: 50%; background-size: 0% 100%; }
  42% { background-size: 0% 100%; }
  100% { background-size: 100% 100%; }
}
/* The clip travels with the numeral, so the edge it rises past stays on the
   numeral's own baseline for the whole of the rise. */
@keyframes reading-passage-numeral {
  from { translate: 0 100%; clip-path: inset(-40% -12% 100% -12%); }
  to { clip-path: inset(-40% -12% 0 -12%); }
}
@keyframes reading-passage-lay {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}
/* The margins keep a plate's own shadow inside the clip, so the shadow is
   drawn with the plate rather than appearing once the clip is released. */
@keyframes reading-passage-wipe {
  from { clip-path: inset(-24px 100% -40px -24px); }
  to { clip-path: inset(-24px -24px -40px -24px); }
}
@keyframes reading-passage-unroll {
  from { clip-path: inset(-40px -48px 100% -48px); }
  to { clip-path: inset(-40px -48px -72px -48px); }
}

@media screen and (max-width: 700px) and (prefers-reduced-motion: no-preference) {
  .is-reading-arriving[data-reading-motion]:not([data-reading-motion^="passage-"]),
  #sec-about.about-ready [data-about-arriving] {
    --reading-x: 0px; --reading-y: 6px;
    animation-duration: 420ms;
    animation-delay: 0ms;
  }
}
@media print, (prefers-reduced-motion: reduce) {
  .is-reading-arriving,
  #sec-about.about-ready [data-about-arriving] {
    animation: none !important;
    translate: none !important;
    opacity: 1 !important;
  }
}
