@keyframes fade-in-up {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes dot-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.35);
  }
  50% {
    box-shadow: 0 0 0 5px rgba(34, 197, 94, 0);
  }
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@keyframes cursor-blink {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}

.fade-in-up {
  animation: fade-in-up 0.5s ease-out both;
}

.fade-in-up--delay-1 {
  animation-delay: 0.1s;
}

.fade-in-up--delay-2 {
  animation-delay: 0.2s;
}

.fade-in-up--delay-3 {
  animation-delay: 0.35s;
}

/* ==========================================================================
   Stagger — drop `.stagger-children` on any parent to cascade its direct
   children in one after another (sidebar nav, table rows, option cards,
   buttons, stat tiles — any repeated list). No per-item markup needed;
   the delay is computed purely from each child's position.
   Example:
     <div class="funnel-steps stagger-children">
       <div class="funnel-step">…</div>
       <div class="funnel-step">…</div>
     </div>
   ========================================================================== */
.stagger-children > * {
  opacity: 0;
  animation: fade-in-up 0.45s ease-out forwards;
}

.stagger-children > *:nth-child(1) {
  animation-delay: 0.02s;
}

.stagger-children > *:nth-child(2) {
  animation-delay: 0.07s;
}

.stagger-children > *:nth-child(3) {
  animation-delay: 0.12s;
}

.stagger-children > *:nth-child(4) {
  animation-delay: 0.17s;
}

.stagger-children > *:nth-child(5) {
  animation-delay: 0.22s;
}

.stagger-children > *:nth-child(6) {
  animation-delay: 0.27s;
}

.stagger-children > *:nth-child(7) {
  animation-delay: 0.32s;
}

.stagger-children > *:nth-child(8) {
  animation-delay: 0.37s;
}

.stagger-children > *:nth-child(9) {
  animation-delay: 0.42s;
}

.stagger-children > *:nth-child(10) {
  animation-delay: 0.47s;
}

.stagger-children > *:nth-child(11) {
  animation-delay: 0.52s;
}

.stagger-children > *:nth-child(12) {
  animation-delay: 0.57s;
}

/* Long lists (e.g. the 24-row billing rate table) cap at the 12th step
   instead of growing forever. */
.stagger-children > *:nth-child(n + 13) {
  animation-delay: 0.6s;
}

/* Typewriter cursor */
.typing-cursor {
  display: inline-block;
  width: 2px;
  height: 1em;
  background: currentColor;
  margin-left: 2px;
  vertical-align: text-bottom;
  animation: cursor-blink 0.8s step-start infinite;
}

/* ==========================================================================
   Typing indicator — three bouncing dots in a pill container.
   Markup (also built by js/typewriter.js):
     <div class="typing-indicator">
       <span class="typing-indicator__dot"></span>
       <span class="typing-indicator__dot"></span>
       <span class="typing-indicator__dot"></span>
     </div>
   ========================================================================== */
@keyframes typing-dot-bounce {
  0%,
  100% {
    transform: scale(1) translateY(0);
  }
  50% {
    transform: scale(1.4) translateY(-4px);
  }
}

.typing-indicator {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  width: fit-content;
  background: #ffffff;
  border: 1px solid #e7ecf3;
  border-radius: 20px;
  padding: 12px 18px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}

.typing-indicator__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #0c1626;
  opacity: 0.5;
  animation: typing-dot-bounce 1s ease-in-out infinite;
}

.typing-indicator__dot:nth-child(1) {
  animation-delay: 0s;
}

.typing-indicator__dot:nth-child(2) {
  animation-delay: 0.16s;
}

.typing-indicator__dot:nth-child(3) {
  animation-delay: 0.32s;
}

/* ==========================================================================
   Chat bubble entrance/exit — Vue <transition name="bubble">-compatible
   class names. Today js/typewriter.js toggles these by hand when it swaps
   the typing indicator for the delivered bubble; wrap that same element
   swap in <transition name="bubble"> later and this CSS needs no changes.
   ========================================================================== */
.bubble-enter-active {
  transition:
    opacity 220ms cubic-bezier(0.34, 1.56, 0.64, 1),
    transform 220ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.bubble-leave-active {
  transition:
    opacity 120ms ease-in,
    transform 120ms ease-in;
}

.bubble-enter-from {
  opacity: 0;
  transform: scale(0.95) translateY(6px);
}

.bubble-leave-to {
  opacity: 0;
  transform: scale(0.96);
}

/* ==========================================================================
   Button hover — site-wide language.
   Filled/primary buttons: opacity fade only (no transform, no shadow change).
   Outline/ghost buttons: border-color + color fade toward brand blue.
   This file is linked LAST on every page (after css/components/*.css) so
   these rules win the cascade over older per-component :hover declarations
   without needing !important. Reusable utility classes (.btn-hover-fade /
   .btn-hover-outline) are included below for any new button you add.
   ========================================================================== */
.btn-hover-fade {
  transition: opacity 0.15s ease;
}

.btn-hover-fade:hover {
  opacity: 0.88;
}

.btn-hover-outline {
  transition:
    border-color 0.15s ease,
    color 0.15s ease;
}

.btn-hover-outline:hover {
  border-color: #0e9fe0;
  color: #0e9fe0;
}

/* Filled buttons already in the codebase */
.cta-button,
.step-footer__continue,
.field-action__button,
.final-launch-btn,
.launch-cta__button,
.payment-approve-btn,
.pill-button--filled,
.setup-task__field-btn,
.setup-task__processor-btn--filled,
.sku-submit,
.assign-subscription,
.add-variation__button,
.brand-list-item__select,
.url-import__button,
.whats-next__btn,
.celebrate-banner__btn,
.funnel-info__copy,
.revenue-network__enabled,
.logo-generator__button,
.logo-generator__use,
.logo-generator__regenerate {
  transition: opacity 0.15s ease;
}

.cta-button:hover,
.step-footer__continue:hover,
.field-action__button:hover,
.final-launch-btn:hover,
.launch-cta__button:hover,
.payment-approve-btn:hover,
.pill-button--filled:hover,
.setup-task__field-btn:hover,
.setup-task__processor-btn--filled:hover,
.sku-submit:hover,
.assign-subscription:hover,
.add-variation__button:hover,
.brand-list-item__select:hover,
.url-import__button:hover,
.whats-next__btn:hover,
.celebrate-banner__btn:hover,
.funnel-info__copy:hover,
.revenue-network__enabled:hover,
.logo-generator__button:hover,
.logo-generator__use:hover,
.logo-generator__regenerate:hover {
  opacity: 0.88;
  transform: none;
  filter: none;
}

.cta-button:hover i {
  transform: none;
}

/* Outline/ghost buttons already in the codebase */
.step-footer__back,
.pill-button--outline,
.setup-task__processor-btn--outline,
.payment-method-add,
.monetize-row__method,
.funnel-step__delete {
  transition:
    border-color 0.15s ease,
    color 0.15s ease;
}

.step-footer__back:hover,
.pill-button--outline:hover,
.setup-task__processor-btn--outline:hover,
.payment-method-add:hover,
.monetize-row__method:hover,
.funnel-step__delete:hover {
  border-color: #0e9fe0;
  color: #0e9fe0;
  transform: none;
}

/* ==========================================================================
   Step/page entrance — fade the main content out before navigating to the
   next page, then fade it back in on load. Toggled by js/page-transition.js.
   ========================================================================== */
.app-main__content {
  transition: opacity 0.2s ease;
}

.app-main__content.fade {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .fade-in-up,
  .bot-avatar,
  .companion-badge__dot,
  .status-pill__dot,
  .typing-cursor,
  .typing-indicator__dot,
  .stagger-children > * {
    animation: none !important;
    opacity: 1 !important;
  }

  .bubble-enter-active,
  .bubble-leave-active,
  .app-main__content {
    transition: none !important;
  }
}
