/* Site motion, on top of the shared motion.css (whose hash a test locks). Tokens only. design/motion-references.md says where
   each idea came from. The language: words brighten where they stand, objects rise, rules draw, and nothing ever loops.
   Unhurried on arrival (1.1 s), quick under the hand (0.3 s). Everything that moves sits inside no-preference. */
:root {
  --ease-arrive: cubic-bezier(0.32, 0.72, 0, 1);
  --dur-arrive: 1100ms;
  --dur-hand: 320ms;
}

/* Printing an armed page still prints every word. */
@media print {
  [data-reveal] { opacity: 1 !important; translate: none !important; scale: none !important; filter: none !important; }
}

@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }

  html { scroll-behavior: smooth; }

  /* ---- page changes: the old page dims quickly, the new one settles; the header does not move ---- */
  .app-header { view-transition-name: site-header; }
  ::view-transition-group(site-header) { animation: none; z-index: 2; }
  ::view-transition-old(site-header) { display: none; }
  ::view-transition-new(site-header) { animation: none; }
  ::view-transition-old(root) { animation: page-out 220ms ease-out both; }
  ::view-transition-new(root) { animation: page-in 620ms var(--ease-arrive) both; }
  ::view-transition-group(product-plate) { animation-duration: 720ms; animation-timing-function: var(--ease-arrive); z-index: 1; }
  .product-hero-icon { view-transition-name: product-plate; }

  /* a filter chip: only the tiles travel */
  html[data-filtering] .tile { view-transition-name: match-element; view-transition-class: tile; }
  html[data-filtering]::view-transition-old(root),
  html[data-filtering]::view-transition-new(root) { animation: none; }
  ::view-transition-group(.tile) { animation-duration: 560ms; animation-timing-function: var(--ease-arrive); }

  @keyframes page-out { to { opacity: 0; } }
  @keyframes page-in { from { opacity: 0; translate: 0 10px; } }

  /* ---- arrival: words first, then the object ---- */
  main h1 { animation: brighten 1200ms var(--ease-arrive) backwards; }
  main .section-lede,
  .product-headline { animation: brighten 1200ms var(--ease-arrive) 120ms backwards; }
  .home-hero .hero .btn,
  .product-hero-text .cluster { animation: lift-in 1000ms var(--ease-arrive) 240ms backwards; }

  /* words never start invisible: anything catching the page at load can already read them */
  @keyframes brighten { from { opacity: 0.4; filter: blur(2px); } }
  @keyframes lift-in { from { opacity: 0.4; translate: 0 10px; } }
  @keyframes object-in { from { opacity: 0; translate: 0 8%; scale: 0.96; } }
  @keyframes plate-in { from { opacity: 0; translate: 0 14px; scale: 0.9; } }

  .hero-layer img { animation: object-in 1500ms var(--ease-arrive) backwards; }
  .hero-layer-c img { animation-delay: 260ms; }
  .hero-layer-b img { animation-delay: 380ms; }
  .hero-layer-a img { animation-delay: 500ms; }
  .product-hero-icon { animation: plate-in 1300ms var(--ease-arrive) 240ms backwards; }

  /* the rings draw once, nearest first, then stay; the icon's own strokes draw inside its plate */
  .ha-contour circle { animation: ring-draw 1900ms var(--ease-arrive) backwards; }
  .ha-contour circle:nth-child(2) { animation-delay: 80ms; }
  .ha-contour circle:nth-child(3) { animation-delay: 160ms; }
  .ha-contour circle:nth-child(4) { animation-delay: 240ms; }
  .ha-contour circle:nth-child(5) { animation-delay: 320ms; }
  .ha-contour circle:nth-child(6) { animation-delay: 400ms; }
  .ha-contour circle:nth-child(7) { animation-delay: 480ms; }
  .ha-contour circle:nth-child(8) { animation-delay: 560ms; }
  .product-hero-icon .icon > * { animation: stroke-draw 1400ms var(--ease-arrive) 520ms backwards; }

  @keyframes ring-draw { from { stroke-dasharray: 1; stroke-dashoffset: 1; opacity: 0; } to { stroke-dasharray: 1; stroke-dashoffset: 0; } }
  @keyframes stroke-draw { from { stroke-dasharray: 1; stroke-dashoffset: 1; } to { stroke-dasharray: 1; stroke-dashoffset: 0; } }

  /* what the first screen shows arrives in the same language as what scrolling reveals */
  .tile, .pricing-plan { animation: rise-in var(--dur-arrive) var(--ease-arrive) 200ms backwards; }
  .post-list > li { animation: lift-in 900ms var(--ease-arrive) 160ms backwards; }
  .tile:nth-child(2), .pricing-plan:nth-child(2), .post-list > li:nth-child(2) { animation-delay: 280ms; }
  .tile:nth-child(3), .pricing-plan:nth-child(3), .post-list > li:nth-child(3) { animation-delay: 360ms; }
  html[data-filtered] .tile { animation: none; }
  .tile:nth-child(n+4), .pricing-plan:nth-child(n+4), .post-list > li:nth-child(n+4) { animation-delay: 440ms; }
  .pro .pricing-plan { animation: none; }

  @keyframes rise-in { from { opacity: 0.4; translate: 0 18px; scale: 0.985; } }

  /* ---- reveals (assets/js/motion.js): armed is only ever set offscreen, and shown is final ---- */
  [data-reveal-as] {
    transition: opacity var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms),
      translate var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms),
      scale var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms),
      filter var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms);
  }
  [data-reveal="armed"][data-reveal-as="rise"] { opacity: 0; translate: 0 22px; scale: 0.98; }
  [data-reveal="armed"][data-reveal-as="bright"] { opacity: 0.08; filter: blur(5px); }
  [data-reveal="armed"][data-reveal-as="line"] { opacity: 0; translate: 0 10px; }
  [data-reveal="armed"][data-reveal-as="rule"] { scale: 0 1; }
  [data-reveal-as="rule"] { transform-origin: left; }
  [data-reveal="armed"]:focus-within { opacity: 1; translate: none; scale: none; filter: none; }
  [data-reveal="armed"][data-reveal-as] { transition: none; } /* hiding is instant and offscreen; only the arrival plays */

  /* a tile's icon draws as its tile arrives */
  [data-arrived].tile .icon > * { animation: stroke-draw 1300ms var(--ease-arrive) calc(var(--reveal-delay, 0ms) + 260ms) backwards; }

  /* ---- under the hand: responds at once, settles softly ---- */
  .tile {
    transition: opacity var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms),
      translate var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms),
      scale var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms),
      transform var(--dur-hand) var(--ease-arrive),
      box-shadow var(--dur-hand) var(--ease-arrive),
      border-color var(--dur-hand) var(--ease-arrive);
  }
  .tile-stage .icon { transition: scale 520ms var(--ease-arrive); }
  .btn {
    transition: transform var(--dur-feedback) var(--ease), translate var(--dur-hand) var(--ease-arrive),
      background-color var(--dur-hand) var(--ease-arrive), border-color var(--dur-hand) var(--ease-arrive),
      color var(--dur-hand) var(--ease-arrive), box-shadow var(--dur-hand) var(--ease-arrive);
  }
  .chip { transition: background-color var(--dur-hand) var(--ease-arrive), color var(--dur-hand) var(--ease-arrive), border-color var(--dur-hand) var(--ease-arrive), scale var(--dur-feedback) var(--ease); }
  .chip:active { scale: 0.96; }
  .nav-link { transition: background-color var(--dur-hand) var(--ease-arrive), color var(--dur-hand) var(--ease-arrive), scale var(--dur-feedback) var(--ease); }
  .nav-link:active { scale: 0.97; }
  .site-footer a, .post-list a, .faq-item summary { transition: color var(--dur-hand) var(--ease-arrive); }
  .pricing-plan { transition: opacity var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms),
      translate var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms),
      scale var(--dur-arrive) var(--ease-arrive) var(--reveal-delay, 0ms),
      border-color var(--dur-hand) var(--ease-arrive),
      box-shadow var(--dur-hand) var(--ease-arrive); }

  @media (hover: hover) {
    .tile:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); }
    .tile:hover .tile-stage .icon { scale: 1.1; }
    .tile:active { transform: translateY(-1px); }
    .btn-primary:hover:not(:disabled), .btn-secondary:hover:not(:disabled) { translate: 0 -1px; box-shadow: var(--shadow-1); }
    .pricing-plan:hover { border-color: var(--color-border-strong); box-shadow: var(--shadow-1); }
  }

  /* ---- pointer depth: the nearer the layer, the further it moves; --px and --py come from motion.js ---- */
  .hero-layer { transform: translate3d(calc(var(--px, 0) * var(--depth) * 1px), calc(var(--py, 0) * var(--depth) * 0.6px), 0); }
  .hero-layer-a { --depth: 16; }
  .hero-layer-b { --depth: 9; }
  .hero-layer-c { --depth: 5; }
  .product-hero-icon { transform: perspective(36rem) rotateX(calc(var(--py, 0) * -9deg)) rotateY(calc(var(--px, 0) * 12deg)); }

  /* ---- the FAQ opens at a walking pace, where the browser can animate to height: auto ---- */
  @supports (interpolate-size: allow-keywords) {
    .faq-item { interpolate-size: allow-keywords; }
    .faq-item::details-content {
      height: 0;
      opacity: 0;
      overflow: clip;
      transition: height 480ms var(--ease-arrive), opacity 360ms ease, content-visibility 480ms allow-discrete;
    }
    .faq-item[open]::details-content { height: auto; opacity: 1; }
  }
  .faq-item summary::after { transition: rotate 420ms var(--ease-arrive); }

  /* ---- tied to the scrollbar, so it holds still when you do; native, and simply absent where unsupported ---- */
  @supports (animation-timeline: scroll()) {
    /* the object opens up as the hero leaves */
    .hero-layer { animation: linear both; animation-timeline: scroll(root); animation-range: 0 90vh; }
    .hero-layer-a { animation-name: open-a; }
    .hero-layer-b { animation-name: open-b; }
    .hero-layer-c { animation-name: open-c; }
    .home-hero .ha-contour { transform-box: fill-box; transform-origin: center; animation: rings-open linear both; animation-timeline: scroll(root); animation-range: 0 90vh; }

    @keyframes open-a { to { translate: 0 -5%; scale: 1.05; } }
    @keyframes open-b { to { translate: 4% -9%; scale: 0.98; } }
    @keyframes open-c { to { translate: -5% -12%; scale: 0.95; } }
    @keyframes rings-open { to { transform: scale(1.22); } }

    /* the header settles onto the page once there is something under it */
    .app-header { animation: header-settle linear both; animation-timeline: scroll(root); animation-range: 0 72px; }
    @keyframes header-settle { from { border-bottom-color: transparent; } }

    /* the closing band opens to full width as you reach it; only scale, so its words are readable at any point */
    .product-close { animation: band-open linear both; animation-timeline: view(); animation-range: entry 0% entry 80%; }
    @keyframes band-open { from { scale: 0.94; } }

    /* reading progress on long text; a page too short to scroll has no timeline, so the bar stays at zero */
    body:has(.prose)::before {
      content: "";
      position: fixed;
      inset: 0 0 auto;
      z-index: 30;
      height: 2px;
      background: var(--color-accent);
      transform: scaleX(0);
      transform-origin: left;
      pointer-events: none;
      animation: read-on linear both;
      animation-timeline: scroll(root);
    }
    @keyframes read-on { to { transform: scaleX(1); } }
  }
}
