/* APEX site · the hero character: the low-poly lion and the Telegram bubble he speaks in.
   Layout and type for the hero live in base.css; this file is only the cast. */

/* ---- the lion ---- */
/* A VP9 WebM with a real alpha channel, with an h264 mp4 fallback whose
   background is keyed to the page ink. Alpha is what fixed the green shade:
   the browser decodes YUV with a levels shift, so the clip painted #0e1717
   against a #0b1312 page whatever hex was stored - masking it never worked
   because the mismatch was in the decode, not the file. With no background at
   all there is nothing left to mismatch, and the two mask-image fades that
   used to hide that rectangle are gone with it. */
.lion-stage { position: absolute; left: 2%; bottom: 0; width: 96%; }
.lion { display: block; width: 100%; height: auto; }

/* ---- the stage light (js/herofx.js) ----
   The canvas draws him as well as the light, so once it has taken over the video
   is only its source: still playing, never seen. JS sizes the canvas round the
   stage; it sits under the copy and the bubble. */
.hero__gl { position: absolute; top: 0; height: 100%; pointer-events: none; }
.hero__visual { z-index: 1; }
.hero.has-gl .lion { opacity: 0; }

/* ---- the bubble ---- */
/* The wrapper and the bubble stay separate elements so GSAP's intro tween and
   the CSS fade never own the same property. (The pointer parallax that
   originally forced this split is gone - APEX already waves.) */
/* Up and to the left of him: sitting square on top of the stage put the bubble
   over his head. There is empty gutter between the copy and the stage, so it can
   hang outside the stage box without crowding the text. */
/* The overhang has to shrink with the viewport: a flat -18% cleared the copy at
   1440 but collided with it around 1100. -4.5vw keeps a real margin instead of
   the 1px one -6vw happened to leave. */
.bubble-wrap { position: absolute; left: max(-18%, -4.5vw); top: -9%; width: min(122%, 332px); z-index: 2; }
.bubble {
  position: relative;
  padding: 13px 16px 10px;
  background: linear-gradient(170deg, #1a2723, #0f1917);
  border: 1px solid var(--line-2); border-radius: 18px;
  box-shadow: 0 26px 70px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(236, 229, 214, .06);
  /* CSS owns the fade, GSAP owns the movement. A GSAP autoAlpha here strands the
     bubble at opacity:0 / visibility:hidden and nothing ever throws. */
  opacity: 0; transition: opacity .42s var(--ease), border-color .7s, box-shadow .7s;
}
/* the spark from his core has just landed on it */
.bubble.is-lit {
  border-color: rgba(233, 173, 79, .7); transition-duration: .42s, .08s, .08s;
  box-shadow: 0 26px 70px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(236, 229, 214, .06), 0 0 0 1px rgba(233, 173, 79, .25), 0 0 34px rgba(233, 173, 79, .28);
}
.bubble.is-live { opacity: 1; }
.bubble.is-live.is-out { opacity: 0; }
/* Sits just left of his head rather than dead centre on it. The value was
   originally chosen to dodge an orbiting agent that no longer exists; it still
   reads well, so it stayed. ~83% would point straight at him if ever wanted.
   Mobile re-aims it below. */
.bubble__tail {
  position: absolute; left: 64%; bottom: -8px; width: 18px; height: 18px;
  background: #0f1917; border-right: 1px solid var(--line-2); border-bottom: 1px solid var(--line-2);
  border-bottom-right-radius: 3px; transform: rotate(45deg);
}

.bubble__from { display: flex; align-items: center; gap: 7px; margin-bottom: 7px; }
.bubble__from img { width: 19px; height: 19px; border-radius: 50%; }
.bubble__from b { font-size: .8rem; font-weight: 600; color: var(--mint); }
/* the message is unmistakably a Telegram message, not a generic speech bubble */
.bubble__from .tg { width: 14px; height: 14px; flex: none; margin-left: -1px; }
.bubble__from span {
  font-family: var(--mono); font-size: .52rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--dim); border: 1px solid var(--line-2); border-radius: 4px; padding: 1px 5px;
}

/* min-height holds the box still while the line types itself in */
.bubble__text { margin: 0; font-size: .87rem; line-height: 1.5; color: var(--cream); min-height: 4.5em; }
.bubble__dots { position: absolute; left: 17px; top: 47px; display: flex; gap: 5px; opacity: 0; transition: opacity .25s; }
.bubble.is-typing .bubble__dots { opacity: 1; }
.bubble__dots i { width: 7px; height: 7px; border-radius: 50%; background: var(--dim); animation: bdot 1.1s infinite; }
.bubble__dots i:nth-child(2) { animation-delay: .15s; }
.bubble__dots i:nth-child(3) { animation-delay: .3s; }
@keyframes bdot { 0%, 60%, 100% { transform: translateY(0); opacity: .4; } 30% { transform: translateY(-5px); opacity: 1; } }

.bubble__meta { display: flex; align-items: center; gap: 7px; margin-top: 8px; font-family: var(--mono); font-size: .58rem; color: var(--dim); }
.bubble__rail { display: flex; gap: 5px; margin-right: auto; }
.bubble__rail i { width: 5px; height: 5px; border-radius: 50%; background: var(--line-2); transition: background .35s, transform .35s; }
.bubble__rail i.is-on { background: var(--mint); transform: scale(1.3); }
.tick { width: 17px; height: 9px; fill: none; stroke: var(--dim); stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round; transition: stroke .35s; }
.tick__2 { opacity: 0; transition: opacity .35s; }
.bubble.is-read .tick { stroke: var(--gold); }
.bubble.is-read .tick__2 { opacity: 1; }

@media (max-width: 900px) {
  /* the desktop offsets would push the bubble off screen here: sit it square again */
  .bubble-wrap { width: min(100%, 300px); left: 0; top: 0; }
  .bubble { padding: 12px 14px 9px; }
  .bubble__text { font-size: .82rem; min-height: 5em; }
  /* a slightly smaller lion drops his head clear of the bubble above him */
  .lion-stage { left: 8%; width: 84%; }
  .bubble__tail { left: 57%; }
}

@media (prefers-reduced-motion: reduce) {
  .bubble__dots { display: none; }
}
