/* Background and motion layer (loaded after style.css, so it can refine it). Everything here is decoration:
   it respects "reduce motion", never blocks a tap, and uses only transform and opacity so it stays smooth on a phone. */
:root { --dot: rgba(255, 255, 255, .075); --blobA: rgba(var(--glow), .22); --blobB: rgba(124, 92, 255, .17); --blobC: rgba(232, 184, 75, .11); }
@media (prefers-color-scheme: light) { :root { --dot: rgba(14, 27, 26, .09); --blobA: rgba(var(--glow), .16); --blobB: rgba(91, 63, 224, .09); --blobC: rgba(154, 106, 18, .10); } }

/* ---------- living background ---------- */
body { background: var(--bg); }
.ambient { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.ambient i { position: absolute; width: 95vmax; height: 95vmax; border-radius: 50%; will-change: transform; }
.ambient i:nth-child(1) { left: -42vmax; top: -52vmax; background: radial-gradient(circle, var(--blobA), transparent 62%); animation: driftA 28s ease-in-out infinite alternate; }
.ambient i:nth-child(2) { right: -55vmax; bottom: -45vmax; background: radial-gradient(circle, var(--blobB), transparent 62%); animation: driftB 36s ease-in-out infinite alternate; }
.ambient i:nth-child(3) { left: -5vmax; bottom: -70vmax; background: radial-gradient(circle, var(--blobC), transparent 62%); animation: driftC 44s ease-in-out infinite alternate; }
.ambient::after { content: ''; position: absolute; inset: 0; background-image: radial-gradient(var(--dot) 1px, transparent 1.3px); background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(75% 46% at 50% 14%, #000 0%, transparent 78%); mask-image: radial-gradient(75% 46% at 50% 14%, #000 0%, transparent 78%); }
#login, #shell { position: relative; z-index: 1; }
@keyframes driftA { to { transform: translate3d(14vmax, 10vmax, 0) scale(1.08); } }
@keyframes driftB { to { transform: translate3d(-16vmax, -9vmax, 0) scale(1.1); } }
@keyframes driftC { to { transform: translate3d(12vmax, -12vmax, 0) scale(.94); } }

/* ---------- the orb gets a slow orbit with two lights that speed up with his mood ---------- */
.orbit { position: absolute; inset: -4%; border-radius: 50%; border: 1px dashed rgba(var(--glow), .34); pointer-events: none; animation: spin 52s linear infinite; transition: border-color .4s; }
.orbit i { position: absolute; top: -4px; left: 50%; width: 7px; height: 7px; margin-left: -3.5px; border-radius: 50%; background: var(--gold); box-shadow: 0 0 12px var(--gold), 0 0 24px rgba(232, 184, 75, .5); }
.orbit::after { content: ''; position: absolute; bottom: -3px; left: 50%; width: 5px; height: 5px; margin-left: -2.5px; border-radius: 50%; background: var(--teal2); box-shadow: 0 0 10px var(--teal); }
.orb[data-state="listening"] .orbit { animation-duration: 9s; border-color: rgba(var(--glow), .7); }
.orb[data-state="thinking"] .orbit { animation-duration: 2.8s; border-color: rgba(var(--glow), .55); }
.orb[data-state="speaking"] .orbit { animation-duration: 16s; border-color: rgba(var(--glow), .6); }
.orbwrap::after { content: ''; position: absolute; left: 12%; right: 12%; bottom: -14%; height: 16%; border-radius: 50%; background: radial-gradient(closest-side, rgba(var(--glow), .35), transparent); filter: blur(6px); opacity: .7; pointer-events: none; animation: floorGlow 5s ease-in-out infinite; }
@keyframes floorGlow { 50% { opacity: .35; transform: scaleX(.88); } }
.talk.active .orbwrap::after { display: none; }

/* ---------- movement that helps: screens slide in, new things rise once, taps feel physical ---------- */
.view { animation: viewIn .34s cubic-bezier(.2, .8, .2, 1) both; }
@keyframes viewIn { from { opacity: 0; transform: translateY(12px); } }
/* The lists are redrawn whenever data refreshes, so per-item entrance animations would replay and flicker: only the newest chat item animates. */
.card, .logrow, .tile, .pipe { animation: none; }
.msg, .cardmsg, .srcrow { animation: none; }
.feed > :last-child { animation: rise .3s cubic-bezier(.2, .8, .2, 1) both; }
.chip:active, .tab:active, .iconbtn:active { transform: scale(.94); }
.chip, .tab, .iconbtn { transition: transform .12s, background .15s, border-color .15s, color .15s; }
.card { transition: border-color .25s, box-shadow .25s; }
.bar .mark { animation: logoGlow 5s ease-in-out infinite; }
@keyframes logoGlow { 50% { filter: drop-shadow(0 0 16px rgba(var(--glow), .6)); } }
.login-card .mark { animation: floatY 6s ease-in-out infinite; }
@keyframes floatY { 50% { transform: translateY(-6px); } }
.greet h2 { animation: rise .7s cubic-bezier(.2, .8, .2, 1) both; }
.greet p, .greet .eyebrow { animation: rise .7s .12s cubic-bezier(.2, .8, .2, 1) both; }
.tab[aria-selected="true"] svg { animation: pop .3s cubic-bezier(.3, 1.5, .5, 1); }
@keyframes pop { from { transform: scale(.8); } }
.btn { position: relative; overflow: hidden; }
.btn::after { content: ''; position: absolute; inset: 0; background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, .35) 50%, transparent 70%); transform: translateX(-120%); }
.btn:not(.ghost):active::after { transform: translateX(120%); transition: transform .45s ease; }

@media (prefers-reduced-motion: reduce) {
  .ambient i, .orbit, .orbwrap::after, .bar .mark, .login-card .mark, .view, .feed > :last-child, .greet *, .tab svg { animation: none !important; }
}

/* While David is speaking the phone has enough to do: freeze the decorative loops so nothing competes with the voice and the orb. */
body.talking .ambient i, body.talking .bar .mark, body.talking .orbwrap::after, body.talking .orbit, body.talking .greet * { animation-play-state: paused; }
