#app-wrapper *,
    #app-wrapper *::before,
    #app-wrapper *::after {
      box-sizing: border-box;
      border-width: 0;
      border-style: solid;
      border-color: #e5e7eb;
    }

    #app-wrapper {
      font-family: 'Inter', 'Manrope', 'Plus Jakarta Sans', sans-serif;
      background-color: #F8FAFC;
      background-image: radial-gradient(circle at 50% 0%, #FFFFFF 0%, #F1F5F9 100%);
      margin: 0;
      padding: 0;
      overflow-x: hidden;
    }

    #app-wrapper {
      width: 100%;
      overflow-x: hidden;
    }

    #app {
      width: 100%;
      max-width: 1440px;
      margin: 0 auto;
      display: flex;
      flex-direction: column;
      align-items: center;
      padding: 20px 0;
    }

    .carousel-card {
      /* Promote to its own GPU layer so transform/opacity animate on the compositor thread.
               Dropped width/height from the transition list — animating layout props triggers reflow every frame. */
      transition: transform 0.65s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.5s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.5s ease;
      will-change: transform, opacity;
      backface-visibility: hidden;
      -webkit-backface-visibility: hidden;
      transform: translateZ(0);
      contain: layout paint;
    }

    .dash-card {
      /* Was opacity 0 -> 1: with a dozen white cards on a white dashboard background,
         fading them all in at once (even staggered by 90ms) reads as the whole panel
         flashing white. Keep opacity high so there's still motion but no luminance pop. */
      opacity: 0.85;
      transform: translate3d(0, 14px, 0) scale(0.98);
      transition: opacity 0.75s cubic-bezier(0.22, 1, 0.36, 1), transform 0.75s cubic-bezier(0.22, 1, 0.36, 1);
      will-change: opacity, transform;
      backface-visibility: hidden;
    }

    .dash-card.dash-card-in {
      opacity: 1;
      transform: translate3d(0, 0, 0) scale(1);
    }

    .dash-card.dash-done {
      /* Release the compositor layer once the intro finishes to free GPU memory. */
      will-change: auto;
    }

    /* Everyday hover/interaction transitions (node hover-scale, card shadow-on-hover) run smoother
           than the Tailwind default. Deliberately excludes .dash-card / .group / broad hover selectors,
           which previously out-specificity'd the intro fade timing and caused visible flicker. */
    .dashboard-inner .wf-node {
      transition-duration: 450ms;
      transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
    }

    .tab-btn.active {
      background-color: white;
      font-weight: 700;
    }

    .tab-btn.active .tab-underline {
      opacity: 1;
    }

    .dash-container {
      perspective: 1500px;
    }

    .transform-style-3d {
      transform-style: preserve-3d;
    }

    .nav-btn {
      transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    }

    /* Matches the H value updateCarousel() computes in JS (560px at
       every width now — see the comment there for why mobile needed
       the same room as desktop) so the outer wrapper never leaves dead
       space or clips the active card. */
    .carousel-outer {
      height: 580px;
    }

    .nav-btn:hover {
      transform: scale(1.1) translateY(-50%);
      box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
    }

    .nav-btn:active {
      transform: scale(0.95) translateY(-50%);
    }

    .wf-glow {
      filter: drop-shadow(0 0 5px rgba(249, 115, 22, 0.6));
    }

    .ai-pulse-circle {
      animation: pulse-ring 4s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
    }

    .animation-delay-2000 {
      animation-delay: 2s;
    }

    @keyframes pulse-ring {
      0% {
        transform: translate(-50%, -50%) scale(0.8);
        opacity: 0.5;
      }

      100% {
        transform: translate(-50%, -50%) scale(1.5);
        opacity: 0;
      }
    }

    /* Composite hint for the pulsing ring so it doesn't repaint the whole card each frame. */
    .ai-pulse-circle {
      will-change: transform, opacity;
    }

    /* Keep the dashboard frame on its own layer while the intro animation runs. */
    .dashboard-inner {
      will-change: transform;
      transform: translateZ(0);
    }

    @media (prefers-reduced-motion: reduce) {

      *,
      *::before,
      *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
      }
    }
