/* Cellar Dash — the assistant's glass, and only that.
 *
 * Its own file because two pages draw it: the app, where it is the assistant's
 * face and the button in the corner, and the marketing homepage, where the
 * same glass fronts the written FAQ. Duplicating it into home.css was the
 * alternative, and a duplicated animation drifts.
 *
 * Needs tokens.css for --cd-orb-*, --cd-value and the shadow. The silhouette
 * and the liquid colour are set inline per glass by Orb.html() in orb.js.
 */

/* ══ The glass ═════════════════════════════════════════════════════════════
   The assistant's mark. A dark well — like the globe wells, it stays dark in
   every theme — holding a body of liquid clipped to a glass silhouette. The
   silhouette and the liquid colour are set inline per glass by Orb.html(); what
   lives here is everything that does not change between them.

   Size comes in as --orb-sz so one rule serves 26px in the thread, 34px in the
   header and the rail, and 46px floating. */
.orb {
  position: relative; display: block; flex: none;
  width: var(--orb-sz, 34px); height: var(--orb-sz, 34px);
  border-radius: 50%; overflow: hidden;
  background: radial-gradient(circle at 34% 26%, var(--cd-orb-1) 0%, var(--cd-orb-2) 62%, var(--cd-orb-3) 100%);
  border: 1px solid var(--cd-value);
  box-shadow: var(--cd-shadow-card);
}
/* A slow orbit, well outside the glass — the only thing in here that reads as
   machinery rather than drink. */
.orb-ring {
  position: absolute; inset: -30%; border-radius: 50%;
  border: 1px dashed color-mix(in srgb, var(--cd-value) 30%, transparent);
  animation: orbRing 26s linear infinite;
}
.orb-glass {
  position: absolute; left: 28%; top: 14%; width: 44%; height: 72%;
  transition: clip-path 1150ms cubic-bezier(0.62, 0.03, 0.35, 1);
}
/* The empty part of the glass, so the silhouette is legible before the liquid
   reaches it. */
.orb-ghost {
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--cd-value) 20%, transparent);
}
.orb-liquid {
  position: absolute; left: 0; right: 0; bottom: 0; overflow: hidden;
  transition: height 900ms cubic-bezier(0.3, 0, 0.2, 1);
}
.orb-swirl {
  position: absolute; left: -50%; top: -50%; width: 200%; height: 200%;
  border-radius: 44%; filter: blur(1.5px);
  transition: background 1100ms ease;
  animation-name: orbSwirl; animation-timing-function: linear; animation-iteration-count: infinite;
}
.orb-sheen {
  position: absolute; left: 8%; right: 8%; top: 4%; height: 22%;
  border-radius: 50%; background: rgba(255,255,255,0.28);
  animation: orbSheen 4.4s ease-in-out infinite;
}
/* Something to say. Shown only in the unread state. */
.orb-mark {
  position: absolute; top: 12%; right: 13%; width: 8px; height: 8px; border-radius: 50%;
  background: var(--cd-value); box-shadow: 0 0 0 3px color-mix(in srgb, var(--cd-value) 22%, transparent);
  animation: orbMark 1.8s ease-in-out infinite;
  display: none;
}
.orb[data-state="unread"] .orb-mark { display: block; }
/* Small enough that the mark would be a smudge. */
.orb[style*="--orb-sz:26px"] .orb-mark { width: 6px; height: 6px; }

@keyframes orbSwirl { 0% { transform: rotate(0deg) scale(1); } 50% { transform: rotate(180deg) scale(1.16); } 100% { transform: rotate(360deg) scale(1); } }
@keyframes orbSheen { 0%, 100% { transform: translateY(0) scaleX(1); opacity: 0.5; } 50% { transform: translateY(-6%) scaleX(1.1); opacity: 0.85; } }
@keyframes orbRing { to { transform: rotate(360deg); } }
@keyframes orbMark { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
/* The swirl, the orbit and the sheen go; the morph stays, because it is slow
   enough to read as a change of state rather than motion. */
@media (prefers-reduced-motion: reduce) {
  .orb-swirl, .orb-ring, .orb-sheen, .orb-mark { animation: none; }
}

/* Illustrated portraits, when they land, sit in the same box. */
.cast-art { display: block; border-radius: 50%; object-fit: contain; }
