/*
 * Pickle motion. Loads after components.css, which owns structure; this file
 * owns time. Nothing here is required for a page to be usable.
 *
 * THE CONTRACT, and it is the whole reason this file can be as busy as it is:
 *
 *   1. Every rule that hides something lives inside
 *      `@media (prefers-reduced-motion: no-preference)`. A reader who asked for
 *      less motion never matches it, so content is not hidden rather than hidden
 *      and never revealed.
 *   2. Scroll-driven rules additionally sit inside
 *      `@supports (animation-timeline: view())`. A browser without them matches
 *      nothing here at all.
 *   3. No JavaScript. These six UIs have no build step and load their scripts at
 *      the end of <body>; a script-driven reveal flashes on every page of every
 *      one of them, and leaves content invisible for as long as the bundle takes.
 *      Time-based entrances below run from the stylesheet, so they complete even
 *      with scripting disabled entirely.
 *   4. Print undoes all of it (bottom of the file). Paper has no scroll position,
 *      so a scroll-driven rule would otherwise commit half the page at opacity 0.
 *
 * TWO MECHANICS LEARNED BY MEASURING, both invisible in a stylesheet:
 *
 *   - A view() timeline resolves against the subject's nearest ANCESTOR SCROLL
 *     CONTAINER, and `overflow: hidden` makes one. The signature 1px-gap grid
 *     used it to clip its own radius, so timelines on its cells resolved against
 *     a box that never scrolls and sat permanently at their end state. Those
 *     grids now use `overflow: clip`, which clips WITHOUT becoming a scroll
 *     container: verified in a browser, both ways round.
 *   - A grid's cells must never animate their own opacity. The gap trick paints
 *     one --banx-line ground behind 1px gaps, so a faded cell shows that ground
 *     through them and an unrevealed strip renders as a solid grey block. The
 *     frame animates its own colours, and the cells animate their CONTENTS.
 */

/* ============================================================= the two moves */

/* Content arriving: up and in. */
@keyframes ex-in {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}

/* Structure arriving: the hairline frame draws itself, and nothing moves.
 * Deliberately no transform here. A transform on the grid would shift its own
 * cells, which changes their view() progress while they are animating on it: the
 * two feed back into each other and the cascade stutters. */
@keyframes ex-frame {
  from { background-color: transparent; border-color: transparent; }
  to { background-color: var(--banx-line); border-color: var(--banx-line); }
}

/* A shorter rise for things already on screen at load. */
@keyframes ex-in-sm {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: no-preference) {

  /* ======================================================== 1. load entrance
   * The first screen cannot use a scroll timeline: it is already in view, so a
   * view() animation is complete before the reader arrives. This is the one
   * time-based entrance in the system, and it is why rule 3 above matters -
   * a stylesheet animation runs whether or not any script does.
   *
   * The explorer and .pkl names render their heads into #view on every route
   * change, so the same rules double as a page transition there.
   */
  .ex-wrap .ex-crumb,
  .ex-wrap .ex-kicker,
  .ex-wrap .ex-h,
  .ex-wrap h1,
  .ex-wrap .ex-lede {
    animation: ex-in 620ms var(--banx-ease) both;
  }

  /* Read in order: eyebrow, headline, standfirst. 90ms is enough to be felt as
   * sequence and short enough that the whole head has landed in under half a
   * second. */
  .ex-wrap .ex-crumb { animation-delay: 0ms; }
  .ex-wrap .ex-kicker { animation-delay: 40ms; }
  .ex-wrap .ex-h,
  .ex-wrap h1 { animation-delay: 130ms; }
  .ex-wrap .ex-lede { animation-delay: 220ms; }

  /* A hero opens the same way, one step larger.
   *
   * .ex-hero is used by exactly one page, web/pages/testnet.jsx, and that page
   * mounts no GSAP at all: mountReveals runs only on the home page, so the
   * testnet page had no motion of any kind until this stylesheet reached it.
   * Structure-agnostic on purpose - the hero's column holds a pill, a headline,
   * a standfirst, a pair of actions and a status line, and nth-child means the
   * order comes from the markup rather than from a list here that would drift. */
  .ex-hero > div:first-child > * {
    animation: ex-in 660ms var(--banx-ease) both;
  }

  .ex-hero > div:first-child > :nth-child(1) { animation-delay: 60ms; }
  .ex-hero > div:first-child > :nth-child(2) { animation-delay: 140ms; }
  .ex-hero > div:first-child > :nth-child(3) { animation-delay: 220ms; }
  .ex-hero > div:first-child > :nth-child(4) { animation-delay: 300ms; }
  .ex-hero > div:first-child > :nth-child(5) { animation-delay: 360ms; }

  /* The panel beside it arrives last, as ONE block.
   *
   * :first-child on the rule above matters: without it this selector also caught
   * the panel's own children, so the panel faded from 260ms while its contents
   * had already finished fading at 220ms. Two fades over the same pixels, the
   * inner one wasted. The column staggers; the panel does not. */
  .ex-hero > div + div { animation: ex-in 700ms var(--banx-ease) 260ms both; }

  /* The bar slides down over the page rather than appearing on it. shell.js
   * injects it, so on four of the six apps there is no bar at all without
   * scripting and this animation has nothing to hide. */
  .ex-nav {
    animation: ex-nav-in 520ms var(--banx-ease) both;
  }

  @keyframes ex-nav-in {
    from { opacity: 0; transform: translateY(-100%); }
    to { opacity: 1; transform: none; }
  }

  /* The explorer's live strip follows the bar it sits under. */
  .ex-livebar {
    animation: ex-in-sm 560ms var(--banx-ease) 160ms both;
  }

  /* ====================================================== 2. state entrances
   * Not scroll, not load: a panel becoming the active one. `display: none` to
   * `block` restarts an animation, so adding .on is all the trigger needed.
   */
  .ex-tabpanes > .ex-panel.on,
  .ex-step.on {
    animation: ex-in-sm 380ms var(--banx-ease) both;
  }

  /* A freshly rendered result, wherever a site adds the class after writing
   * innerHTML. Cheap for app.js to opt into and harmless where it does not. */
  .ex-fresh {
    animation: ex-in-sm 420ms var(--banx-ease) both;
  }

  /* A value that just changed. components.css flashes the colour; this adds the
   * smallest possible lift, which is what makes a live figure read as arriving
   * rather than as being overwritten. */
  .flash {
    animation: banx-flash .55s var(--banx-ease), ex-tick .42s var(--banx-ease);
  }

  @keyframes ex-tick {
    0% { transform: translateY(4px); }
    100% { transform: none; }
  }

  /* ==================================================== 3. scroll arrival */
  @supports (animation-timeline: view()) {

    /* The section heads. Short blocks, safe to move as a whole. */
    .ex-sechead,
    .ex-pagehead,
    .ex-list-head,
    [data-arrive] {
      /* Longhands, not the `animation` shorthand: the shorthand resets
       * animation-timeline to auto, which silently turns this back into an
       * ordinary time-based animation that plays once on load. */
      animation-name: ex-in-sm;
      animation-duration: auto;
      animation-fill-mode: both;
      animation-timeline: view(block);
      /* Finish before the block has fully entered, so one cut off by the fold on
       * a barely-scrollable page is not left part-faded. */
      animation-range: entry 0% entry 70%;
    }

    /* The frame of every 1px-gap grid draws itself as the grid arrives. */
    .ex-stats,
    .ex-cells,
    .ex-apps,
    .ex-wlist {
      animation-name: ex-frame;
      animation-duration: auto;
      animation-fill-mode: both;
      animation-timeline: view(block);
      animation-range: entry 0% entry 40%;
    }

    /* Then the contents cascade into it.
     *
     * The CONTENTS, never the cell: see the note at the top of this file. And no
     * animation-delay, because a delay does nothing on a progress timeline. The
     * cascade comes from giving each cell a later range END, so cells sharing a
     * row share an entry phase but finish at different points along it.
     *
     * The cycle is four because CSS cannot know a grid's column count: .c2, .c3,
     * .c4, `dense`, `app` and a bare auto-fit strip all land here. Four reads as
     * a cascade at every one of those widths, which a per-column rule per variant
     * would only match exactly at one of them.
     */
    .ex-stat > *,
    .ex-cell > *,
    .ex-appcard > * {
      animation-name: ex-in-sm;
      animation-duration: auto;
      animation-fill-mode: both;
      animation-timeline: view(block);
      animation-range: entry 8% entry 58%;
    }

    .ex-stats > :nth-child(4n + 2) > *,
    .ex-cells > :nth-child(4n + 2) > *,
    .ex-apps > :nth-child(4n + 2) > * { animation-range: entry 8% entry 68%; }

    .ex-stats > :nth-child(4n + 3) > *,
    .ex-cells > :nth-child(4n + 3) > *,
    .ex-apps > :nth-child(4n + 3) > * { animation-range: entry 8% entry 78%; }

    .ex-stats > :nth-child(4n + 4) > *,
    .ex-cells > :nth-child(4n + 4) > *,
    .ex-apps > :nth-child(4n + 4) > * { animation-range: entry 8% entry 88%; }

    /* Rows of a list, each on its own timeline. Only the ROW moves: these are
     * not gap-grid cells, they carry their own border-top, so fading one cannot
     * expose a container ground. */
    .ex-block-item,
    .ex-nft-card {
      animation-name: ex-in-sm;
      animation-duration: auto;
      animation-fill-mode: both;
      animation-timeline: view(block);
      animation-range: entry 0% entry 55%;
    }
  }
}

/* ==================================================== 4. interaction, always
 * Hover and press are not entrances: they hide nothing, need no scroll and have
 * nothing to degrade, so they sit outside the reduced-motion gate. base.css
 * already collapses every transition duration under that preference.
 */

/* A cell that navigates rises very slightly. Two pixels, because a cell in a
 * 1px-gap grid that moves any further opens a visible seam in the frame. */
a.ex-cell,
.ex-cell.hov,
.ex-appcard {
  transition:
    background var(--banx-fast) var(--banx-ease),
    transform var(--banx-base) var(--banx-ease);
}

a.ex-cell:hover,
.ex-cell.hov:hover,
.ex-appcard:hover { transform: translateY(-2px); }

/* The icon on a green hairline leans in with it. */
.ex-cell .ex-ico,
.ex-appcard .ex-ico {
  transition: transform var(--banx-base) var(--banx-ease);
}

a.ex-cell:hover .ex-ico,
.ex-cell.hov:hover .ex-ico,
.ex-appcard:hover .ex-ico { transform: scale(1.12); }

/* Buttons acknowledge the press. */
.ex-btn,
.ex-iconbtn {
  transition:
    background var(--banx-fast) var(--banx-ease),
    border-color var(--banx-fast) var(--banx-ease),
    color var(--banx-fast) var(--banx-ease),
    transform 90ms var(--banx-ease);
}

.ex-btn:active,
.ex-iconbtn:active { transform: scale(.97); }

/* Tabs slide their active marker rather than snapping it. */
.ex-tabs button { transition: color var(--banx-fast) var(--banx-ease), border-color var(--banx-base) var(--banx-ease); }

/* Table rows and list rows warm on hover. */
.ex-table tbody tr,
.ex-block-item,
.ex-nft-card { transition: background var(--banx-fast) var(--banx-ease); }

/* An NFT card's art fills its frame a little on hover. The card clips it. */
.ex-nft-card { overflow: clip; }
.ex-nft-card img { transition: transform var(--banx-slow) var(--banx-ease); }
.ex-nft-card:hover img { transform: scale(1.04); }

/* ============================================================== 5. on paper
 * Every animation off, and every animated property pinned to its end state.
 * `animation: none` rather than `animation-name: none` so the timeline and the
 * range go with it and nothing is left half-applied.
 *
 * Found by taking a full-page screenshot and noticing three panels had lost
 * their headings: a full-page capture, like a sheet of paper, has no scroll
 * position, so every scroll-driven block below the first fold was still at
 * opacity 0.
 */
@media print {
  .ex-nav,
  .ex-livebar,
  .ex-crumb,
  .ex-kicker,
  .ex-h,
  h1,
  .ex-lede,
  .ex-sechead,
  .ex-pagehead,
  .ex-list-head,
  .ex-stats,
  .ex-cells,
  .ex-apps,
  .ex-wlist,
  .ex-stat > *,
  .ex-cell > *,
  .ex-appcard > *,
  .ex-block-item,
  .ex-nft-card,
  .ex-hero > div:first-child > *,
  .ex-hero > div + div,
  .ex-tabpanes > .ex-panel.on,
  .ex-step.on,
  .ex-fresh,
  .flash,
  [data-arrive] {
    animation: none;
    opacity: 1;
    transform: none;
  }

  .ex-stats,
  .ex-cells,
  .ex-apps,
  .ex-wlist {
    background-color: var(--banx-line);
    border-color: var(--banx-line);
  }
}
