/*
 * home-motion.css
 * Builder 2 — motion + signature moments
 * Lumoro v2 homepage elevation, 2026-06-10.
 *
 * Owns: ambient float, CSS fallback breathing, press bloom,
 *       time-of-day body-class tinting, FAQ icon (if not CSS-transition
 *       already handled in home.css — home.css does handle [open] rotate,
 *       but only at 45deg; we leave that alone and extend via 2.7 note).
 *
 * All animations gate on prefers-reduced-motion: no-preference.
 * The `transform-only` float uses will-change: transform — compositor-only.
 * No layout properties animated. No color properties animated in JS.
 * Box-shadow pulse for press bloom is the one exception: it is on :active
 * pseudo-class (CSS-only), not JS-driven per-frame.
 *
 * File is linked from index_v2.html with ?v=20260610 (mtime-busted separately).
 */

/* ==========================================================================
   2.3a  SMS card float  (ambient life, WebGL path and fallback path both)
   3px translateY yoyo, 4.5s, breath-curve (cubic-bezier ease-in-out).
   transform-only → compositor layer, no layout.
   Reduced-motion guard: @media wrapper; no fallback needed (static is fine).
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  .hero-sms {
    animation: lumoro-float 4.5s cubic-bezier(0.45, 0, 0.55, 1) infinite;
    will-change: transform;
  }

    /* typing indicator dots that JS injects for 2.2 */
  .hero-typing-dots {
    animation: lumoro-float 4.5s cubic-bezier(0.45, 0, 0.55, 1) infinite;
  }

  /* pause float during typing arrival sequence so it doesn't fight the JS settle */
  .hero-sms.hero-sms--arriving {
    animation-play-state: paused;
  }
}

@keyframes lumoro-float {
  0%, 100% { transform: translateY(0); }
  50%       { transform: translateY(-3px); }
}

/* ==========================================================================
   2.3b  CSS fallback breathing radial — only when WebGL canvas is gone.
   Scoped to .hero that does NOT contain a .hero-webgl canvas (the module
   removes it on bail). We use :not(:has(.hero-webgl)) as the gate.
   Falls back gracefully in browsers without :has() — they just don't get
   the breathe (which is fine, they already had no WebGL).

   The "breathe" is a slow opacity pulse on the .hero::after pseudo-element
   that sits on top of the CSS gradient background.
   ========================================================================== */
@supports selector(:has(*)) {
  @media (prefers-reduced-motion: no-preference) {
    .hero:not(:has(.hero-webgl)) {
      overflow: hidden;
    }
    .hero:not(:has(.hero-webgl))::after {
      content: "";
      position: absolute;
      inset: 0;
      z-index: 0;
      pointer-events: none;
      background:
        radial-gradient(ellipse 60% 50% at 78% 55%,
          rgba(255, 199, 107, 0.28) 0%,
          rgba(242, 181, 140, 0.14) 40%,
          transparent 70%);
      animation: lumoro-breathe 8s cubic-bezier(0.45, 0, 0.55, 1) infinite;
    }
  }
}

@keyframes lumoro-breathe {
  0%, 100% { opacity: 0.55; transform: scale(1); }
  50%       { opacity: 1.0;  transform: scale(1.04); }
}

/* ==========================================================================
   2.4  Scroll bloom gain — handled entirely in dawn-hero.js via uniform.
   No CSS needed here. This comment is a breadcrumb.
   ========================================================================== */

/* ==========================================================================
   2.5  Time-of-day body classes — tint the CSS fallback gradient.
   Body class is set by dawn-hero.js (or home.js on fallback path).
   Four slots: lumoro-hour-predawn (0-5h), lumoro-hour-dawn (5-9h),
               lumoro-hour-day (9-17h), lumoro-hour-evening (17-24h).
   Only the CSS fallback path needs these tints; WebGL path uses uniforms.
   Amplitude is restrained — feel it, don't notice it.
   ========================================================================== */

/* pre-dawn: deeper indigo shift, dimmer warm accent */
.lumoro-hour-predawn .hero:not(:has(.hero-webgl)) {
  background:
    radial-gradient(ellipse 60% 55% at 78% 60%,
      rgba(200, 155, 90, 0.22) 0%,
      rgba(200, 155, 90, 0.08) 45%,
      transparent 70%),
    linear-gradient(160deg,
      #0D0B14 0%,
      #1A1224 35%,
      #241730 55%,
      #1E142A 80%,
      #120D18 100%);
}

/* dawn: current full warmth +5% — keep close to default */
.lumoro-hour-dawn .hero:not(:has(.hero-webgl)) {
  background:
    radial-gradient(ellipse 60% 55% at 78% 60%,
      rgba(255, 210, 120, 0.42) 0%,
      rgba(242, 181, 140, 0.28) 45%,
      transparent 70%),
    linear-gradient(160deg,
      #15111B 0%,
      #261530 35%,
      #3C2240 55%,
      #2A1A30 80%,
      #15111B 100%);
}

/* day: neutral as-is — no extra rules needed (default gradient handles it) */

/* evening: plum-shifted, softer warm accent */
.lumoro-hour-evening .hero:not(:has(.hero-webgl)) {
  background:
    radial-gradient(ellipse 55% 50% at 70% 60%,
      rgba(180, 130, 160, 0.30) 0%,
      rgba(140, 100, 130, 0.14) 45%,
      transparent 70%),
    linear-gradient(160deg,
      #15111B 0%,
      #2A1A35 35%,
      #38203C 55%,
      #2C1A32 80%,
      #15111B 100%);
}

/* ==========================================================================
   2.6  Press bloom — touchstart scale + amber box-shadow pulse on primary CTAs.
   :active handles iOS if we pair it with touch-action: manipulation so the
   300ms click delay is eliminated (iOS fires :active immediately with that set).
   We cannot use JS for this without adding per-element listeners; :active +
   touch-action is the right approach and avoids scroll interference.
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  .button.primary,
  .btn-primary,
  a[data-cta].button,
  a[data-cta].btn {
    touch-action: manipulation;
    transition:
      transform 120ms cubic-bezier(0.25, 0, 0.5, 1),
      box-shadow 120ms cubic-bezier(0.25, 0, 0.5, 1);
  }

  .button.primary:active,
  .btn-primary:active,
  a[data-cta].button:active,
  a[data-cta].btn:active {
    transform: scale(0.97);
    box-shadow:
      0 0 0 0px rgba(255, 199, 107, 0),
      0 0 24px 6px rgba(255, 199, 107, 0.32),
      0 4px 16px rgba(21, 17, 27, 0.3);
  }
}

/* ==========================================================================
   2.7  FAQ icon rotation — home.css already has:
        .faq-list summary::after { content: "+"; transition: transform var(--dur) var(--ease); }
        .faq-list details[open] summary::after { transform: rotate(45deg); }
   That is 45deg which reads as ×. The spec says 45deg to read as ×. Already done.
   We honour the 200ms duration by ensuring var(--dur) resolves to at most 200ms.
   If --dur is longer, override for this element only.
   ========================================================================== */
.faq-list summary::after {
  transition: transform 200ms cubic-bezier(0.25, 0, 0.5, 1) !important;
}

/* ==========================================================================
   2.2  Typing indicator dots — injected by home.js.
   The dots container replaces the hero SMS text content temporarily.
   ========================================================================== */
.hero-typing-indicator {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 2px 0;
  height: 1.4em; /* match hero-sms-line line-height so no CLS */
  margin: 0 0 var(--space-2);
}

.hero-typing-indicator .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(21, 17, 27, 0.40);
  flex: none;
}

@media (prefers-reduced-motion: no-preference) {
  .hero-typing-indicator .dot {
    animation: lumoro-dot-pulse 900ms cubic-bezier(0.45, 0, 0.55, 1) infinite;
  }
  .hero-typing-indicator .dot:nth-child(2) { animation-delay: 160ms; }
  .hero-typing-indicator .dot:nth-child(3) { animation-delay: 320ms; }
}

@keyframes lumoro-dot-pulse {
  0%, 80%, 100% { transform: scale(1);    opacity: 0.4; }
  40%           { transform: scale(1.35); opacity: 1;   }
}

/* Fade-in for the settled message text after dots complete */
@keyframes lumoro-msg-settle {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.hero-sms-line--settling {
  animation: lumoro-msg-settle 300ms cubic-bezier(0.25, 0, 0.5, 1) both;
}
.hero-sms-meta--settling {
  animation: lumoro-msg-settle 300ms cubic-bezier(0.25, 0, 0.5, 1) 300ms both;
}

/* ============ Section atmosphere (2026-06-10 beauty pass) ============
   The dark sections carry a faint warm ember whisper so the page is never
   flat type on a flat wall. Amplitude raised slightly in Round C (was 0.05). */
#problem { position: relative; }
#problem::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(90% 60% at 50% 110%, rgba(255, 199, 107, 0.075), transparent 70%);
  animation: lumoro-ember 9s ease-in-out infinite alternate;
}
#proof { position: relative; }
#proof::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(70% 50% at 50% -10%, rgba(176, 168, 191, 0.075), transparent 70%);
  animation: lumoro-ember 11s ease-in-out infinite alternate;
}
@keyframes lumoro-ember {
  from { opacity: 0.6; }
  to { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  #problem::before, #proof::before { animation: none; }
}

/* ============ Round C: the sections breathe ============
   1. Sky drift: each band's .section-sky layer drifts laterally on the
      compositor (transform on an isolated, aria-hidden layer; the packet's
      transform-free rule was about not fighting content transforms - this
      layer has none and repaint-free beats background-position here).
      Desktop only, sub-perceptual amplitude, long offset cycles.
   2. The reset dial takes one slow breath (scale on the img). */
@media (min-width: 1024px) and (prefers-reduced-motion: no-preference) {
  .section-sky {
    animation: lumoro-sky-drift var(--sky-dur, 84s) cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
    will-change: transform;
  }
  #problem .section-sky { --sky-dur: 88s; }
  #product .section-sky { --sky-dur: 74s; animation-delay: -22s; }
  #proof .section-sky   { --sky-dur: 82s; animation-delay: -11s; }
  #faq .section-sky     { --sky-dur: 90s; animation-delay: -33s; }
}
@keyframes lumoro-sky-drift {
  from { transform: translateX(-1.4%) scale(1.045); }
  to   { transform: translateX(1.4%)  scale(1.045); }
}
/* Battery: home.js toggles this class on visibilitychange so the five
   promoted drift layers stop costing GPU while the tab is hidden. */
html.lumoro-tab-hidden .section-sky {
  animation-play-state: paused;
}

/* (lumoro-dial-inhale retired in round G3: the glimpse is now a live
   CSS/SVG breathing dial with its own cycle in home-modules.css.) */
