@keyframes flashing { 0%, 100% { opacity: 0; } 50% { opacity: 1; } } @mixin progress-dot { content: "\25CF"; font-family: Söhne Circle, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif; line-height: normal; margin-left: 0.25rem; vertical-align: baseline; animation: flashing 1.5s 3s infinite; display: inline-block; font-size: 1rem; color: var(--tertiary-medium); } .streamable-content.streaming .cooked p:last-child::after { @include progress-dot; } article.streaming .cooked { .progress-dot::after { @include progress-dot; } > .progress-dot:only-child::after { // if the progress dot is the only content // we are likely waiting longer for a response // so it can start animating instantly animation: flashing 1.5s infinite; } } @keyframes ai-indicator-wave { 0%, 60%, 100% { transform: initial; } 30% { transform: translateY(-0.2em); } } .ai-indicator-wave { flex: 0 0 auto; display: inline-flex; &__dot { display: inline-block; @media (prefers-reduced-motion: no-preference) { animation: ai-indicator-wave 1.8s linear infinite; } &:nth-child(2) { animation-delay: -1.6s; } &:nth-child(3) { animation-delay: -1.4s; } } }