/* =========================================================
   WhisperBud — Landing page
   Faithful implementation of "WhisperBud - Landing.dc.html"
   (Cadence "Warm Signal" language). Layout is inline-styled
   in index.html to match the design 1:1; this file holds the
   keyframes, scroll-reveal, hover states and responsive rules.
   ========================================================= */

* { box-sizing: border-box; }
body { margin: 0; background: #F4F0E7; }
::selection { background: rgba(79,123,94,0.22); }

/* ---------- ambient / demo animations ---------- */
@keyframes orbFloat   { 0%,100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-14px) scale(1.05); } }
@keyframes orbDrift   { 0%,100% { transform: translate(0,0); } 33% { transform: translate(30px,-20px); } 66% { transform: translate(-20px,16px); } }
@keyframes barBounce  { 0%,100% { transform: scaleY(0.4); } 50% { transform: scaleY(1); } }
@keyframes ribbon     { 0%,100% { transform: scaleY(0.35); } 50% { transform: scaleY(1); } }
@keyframes shimmerMove{ 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } }
@keyframes spin       { to { transform: rotate(360deg); } }
@keyframes blink      { 0%,49% { opacity: 1; } 50%,100% { opacity: 0; } }
@keyframes recPulse   { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: .4; transform: scale(.85); } }

/* ---------- scroll reveal — degrades to visible where view() timelines are unsupported ---------- */
@keyframes revealUp { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }
/* Range is entry-based so it ALWAYS completes once the element has scrolled
   into view — including the last section on the page (a cover-based range
   can't finish for elements that never reach viewport center). */
.reveal { animation: revealUp .01s linear both; animation-timeline: view(); animation-range: entry 6% entry 55%; }

/* ===== Hero demo state machine (single 9s loop) ===== */
@keyframes showIdle      { 0%{opacity:1}7%{opacity:1}10%{opacity:0}90%{opacity:0}95%{opacity:1}100%{opacity:1} }
@keyframes showListening { 0%{opacity:0}8%{opacity:0}13%{opacity:1}40%{opacity:1}44%{opacity:0}100%{opacity:0} }
@keyframes showFormatting{ 0%{opacity:0}42%{opacity:0}47%{opacity:1}58%{opacity:1}62%{opacity:0}100%{opacity:0} }
@keyframes showDone      { 0%{opacity:0}60%{opacity:0}65%{opacity:1}90%{opacity:1}95%{opacity:0}100%{opacity:0} }
@keyframes pillMorph {
  0%{ width:200px; height:54px; } 7%{ width:200px; height:54px; }
  14%{ width:380px; height:96px; } 41%{ width:380px; height:96px; }
  48%{ width:300px; height:64px; } 59%{ width:300px; height:64px; }
  66%{ width:320px; height:64px; } 90%{ width:320px; height:64px; }
  96%{ width:200px; height:54px; } 100%{ width:200px; height:54px; }
}
@keyframes docCaret  { 0%{opacity:0}9%{opacity:0}12%{opacity:1}62%{opacity:1}65%{opacity:0}100%{opacity:0} }
@keyframes docReveal { 0%{opacity:0;transform:translateY(8px)}62%{opacity:0;transform:translateY(8px)}67%{opacity:1;transform:none}90%{opacity:1;transform:none}96%{opacity:0}100%{opacity:0} }
.demo-el { animation-duration: 9s; animation-iteration-count: infinite; animation-timing-function: ease-in-out; }

/* ---------- ambient scroll-reactive background ----------
   Soft sage + lavender washes that drift on their own and
   parallax as the page scrolls (scroll-driven timeline).
   Degrades to a gentle static drift where scroll() is absent. */
.bg-fx { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.bg-fx .blob { position: absolute; border-radius: 50%; filter: blur(72px); will-change: transform, translate; }
.bg-fx .blob-1 {
  width: 560px; height: 560px; top: -8%; left: -6%;
  background: radial-gradient(circle at 35% 30%, rgba(79,123,94,0.22), transparent 70%);
  animation: bfDrift1 28s ease-in-out infinite, bfPar1 linear both;
  animation-timeline: auto, scroll(root);
}
.bg-fx .blob-2 {
  width: 480px; height: 480px; top: 34%; right: -9%;
  background: radial-gradient(circle at 50% 50%, rgba(157,146,199,0.18), transparent 70%);
  animation: bfDrift2 34s ease-in-out infinite, bfPar2 linear both;
  animation-timeline: auto, scroll(root);
}
.bg-fx .blob-3 {
  width: 440px; height: 440px; bottom: -8%; left: 32%;
  background: radial-gradient(circle at 40% 40%, rgba(79,123,94,0.15), transparent 70%);
  animation: bfDrift3 31s ease-in-out infinite, bfPar3 linear both;
  animation-timeline: auto, scroll(root);
}
@keyframes bfDrift1 { 0%,100% { translate: 0 0; } 50% { translate: 40px 30px; } }
@keyframes bfDrift2 { 0%,100% { translate: 0 0; } 50% { translate: -36px 26px; } }
@keyframes bfDrift3 { 0%,100% { translate: 0 0; } 50% { translate: 28px -30px; } }
@keyframes bfPar1 { from { transform: translateY(-70px); } to { transform: translateY(240px); } }
@keyframes bfPar2 { from { transform: translateY(140px); } to { transform: translateY(-200px); } }
@keyframes bfPar3 { from { transform: translateY(-50px); } to { transform: translateY(180px); } }

/* ---------- hover states (translated from the design's style-hover) ---------- */
.lnk-sage:hover    { background: #436B50 !important; }
.lnk-outline:hover { background: rgba(33,30,26,0.04) !important; }

/* ---------- responsive ---------- */
@media (max-width: 880px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr !important; }
  .hero-demo { width: 100% !important; }
  h1.hero-title { font-size: 46px !important; }
}

/* ---------- accessibility: stop motion when asked ---------- */
@media (prefers-reduced-motion: reduce) {
  .reveal { animation: none !important; opacity: 1 !important; transform: none !important; }
  .demo-el, [style*="animation"], .bg-fx .blob { animation: none !important; }
}
