.button,
.dialog-close {
  transition:
    background-color 160ms ease,
    color 160ms ease,
    transform 220ms var(--ease),
    box-shadow 220ms ease;
}
.button:active {
  transform: scale(0.98);
}
.faq-list summary .icon {
  transition:
    transform 300ms var(--ease),
    background-color 200ms ease,
    color 200ms ease,
    box-shadow 200ms ease;
}
.contact-dialog[open] {
  animation: dialog-enter 360ms var(--ease);
}
.contact-dialog[open]::backdrop {
  animation: backdrop-enter 260ms ease-out;
}
.cost-segment {
  transition: flex-grow 260ms var(--ease);
}
.mobile-nav:not([hidden]) {
  animation: drop-in 280ms var(--ease);
}

/* Hero entrance: pure CSS, so the first screen still arrives when scripts fail. */
.hero-kicker,
.hero-lead,
.hero-actions,
.hero-meta {
  animation: rise-in 1000ms var(--ease) both;
}
.hero-kicker {
  animation-delay: 60ms;
}
.display .line > span {
  animation: line-up 1100ms var(--ease) both;
}
.display .line:nth-child(1) > span {
  animation-delay: 120ms;
}
.display .line:nth-child(2) > span {
  animation-delay: 200ms;
}
.display .line:nth-child(3) > span {
  animation-delay: 280ms;
}
.strike {
  animation: strike-fade 700ms ease 1250ms both;
}
.strike-mark path {
  animation: strike-draw 760ms var(--ease-io) 1150ms both;
}
.hero-lead {
  animation-delay: 420ms;
}
.hero-actions {
  animation-delay: 500ms;
}
.hero-meta {
  animation-delay: 580ms;
}
.prompt-card {
  animation: prompt-in 1200ms var(--ease) 700ms both;
}
.prompt-card.is-typing .caret {
  opacity: 1;
  animation: caret-blink 900ms steps(1) infinite;
}
.prompt-send {
  transition:
    transform 300ms var(--ease),
    box-shadow 300ms ease;
}
.prompt-card.is-sent .prompt-send {
  animation: send-pulse 700ms var(--ease) 1;
}
.scroll-cue {
  animation: fade-in 800ms ease 1700ms both;
}
.scroll-cue i::after {
  animation: cue-flow 1800ms var(--ease-io) 2200ms 2 both;
}

/* Once the entrance has played, drop the finished animations. Filled ("both") animations stay in
   effect, and over the animated canvas that made the whole first screen repaint on every scroll frame.
   Every end state equals the element's own style, except the scroll cue, which is parked below its line. */
.hero.is-settled :is(.hero-kicker, .hero-lead, .hero-actions, .hero-meta, .display .line > span, .strike, .strike-mark path, .prompt-card, .scroll-cue) {
  animation: none;
}
.hero.is-settled .scroll-cue i::after {
  animation: none;
  transform: translateY(260%);
}

/* Scroll reveals: scripts only hide content that has not been seen yet. A short, plain fade. */
.reveal-pending {
  opacity: 0;
  transform: translateY(16px);
}
.reveal-in {
  transition:
    opacity 600ms ease var(--reveal-delay, 0ms),
    transform 700ms var(--ease) var(--reveal-delay, 0ms);
}

/* Calculator: the receipt prints from the top. */
.receipt-wrap.reveal-pending {
  transform: none;
}
.receipt-wrap.reveal-pending .receipt {
  clip-path: inset(0 0 100% 0);
}
.receipt-wrap .receipt {
  clip-path: inset(-40px -40px -60px -40px);
}
.receipt-wrap.reveal-in .receipt {
  transition: clip-path 1100ms var(--ease-io) 150ms;
}

/* FAQ: answers open smoothly where the browser can animate details content. */
.faq-list details::details-content {
  block-size: 0;
  overflow: clip;
  transition:
    block-size 360ms var(--ease),
    content-visibility 360ms allow-discrete;
}
.faq-list details[open]::details-content {
  block-size: auto;
}

@keyframes rise-in {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes line-up {
  from {
    transform: translateY(110%);
  }
  to {
    transform: none;
  }
}
@keyframes strike-draw {
  from {
    stroke-dashoffset: 1;
  }
  to {
    stroke-dashoffset: 0;
  }
}
@keyframes strike-fade {
  from {
    color: var(--ink);
  }
  to {
    color: var(--ink-4);
  }
}
@keyframes prompt-in {
  from {
    opacity: 0;
    transform: translateY(36px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes caret-blink {
  50% {
    opacity: 0;
  }
}
@keyframes send-pulse {
  40% {
    transform: scale(1.12);
    box-shadow: 0 0 0 8px #1769ff26;
  }
}
@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes cue-flow {
  from {
    transform: translateY(-100%);
  }
  to {
    transform: translateY(260%);
  }
}
@keyframes dialog-enter {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes backdrop-enter {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes drop-in {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Page-to-page navigation cross-fades where the browser supports it; the header stays put. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
  .site-header {
    view-transition-name: site-header;
  }
  ::view-transition-old(root) {
    animation: 260ms ease both vt-out;
  }
  ::view-transition-new(root) {
    animation: 420ms var(--ease) both vt-in;
  }
}
@keyframes vt-out {
  to {
    opacity: 0;
  }
}
@keyframes vt-in {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
}

@media (max-width: 760px) {
  .prompt-card {
    animation-delay: 520ms;
    animation-duration: 900ms;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .faq-list details::details-content {
    transition: none;
  }
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
  .reveal-pending {
    opacity: 1;
    transform: none;
  }
  .receipt-wrap.reveal-pending .receipt {
    clip-path: none;
  }
  .caret {
    display: none;
  }
  .button:hover,
  .button:active,
  .module:hover {
    transform: none;
  }
}
