/* ============================================================
 * Titaness — Theia animations
 *
 * Extracted from .claude/design/GRT-586/logo_concepts_theia/animation.html
 * during GRT-590.  Tokens come from tokens.css (--tan, --teal, etc.).
 *
 * Variant classes:
 *   .theia-anim                root container shared rules
 *   .theia-anim-full           7-beat full sequence (login surface)
 *   .theia-anim-compact        condensed variant (active-run surface)
 *   .nav-mark                  inline G30 SVG used as the per-page logo
 *
 * Choreography (full variant):
 *   Beat 1   0.00 - 1.30   Θεία types in
 *   Hold     1.30 - 1.70   viewer reads the word
 *   Beat 2   1.70 - 2.45   ONE motion: εία + Θ fade out, geo-Θ appears,
 *                          brow lift + circle-to-leaf morph CONCURRENT
 *   Hold     2.45 - 2.55   brow-above-empty-cell frame
 *   Beat 3   2.55 - 3.20   blink (lid morph open->closed->open via JS
 *                          d-attribute morph; no scaleY squash)
 *   Beat 4   3.45 - 4.30   captions stack in
 *   Hold     4.30 - ...    endpoint mark
 *
 * The JS path (theia-anim.js + anime.min.js) adds the `.js-enabled`
 * class to each `.theia-anim` container and drives the d-attribute
 * morphs in a single anime() timeline per element (combining the
 * circle's morph + blink stages into one call avoids the second-call-
 * overrides-first-call bug we hit with separate anime() calls).
 *
 * Browser floor: transform-box: fill-box requires Safari 11.1 /
 * iOS 11.3.  Internal staff browsers are well above this.
 * ============================================================ */

/* ---- Shared container & SVG sizing ---- */

.theia-anim {
  --speed: 1;
  position: relative;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 16px 40px rgba(0,0,0,0.45), 0 4px 12px rgba(0,0,0,0.3);
  overflow: hidden;
}
.theia-anim svg {
  width: 100%;
  height: 100%;
  display: block;
}
.theia-anim-full {
  width: 480px;
  height: 480px;
  max-width: 90vw;
  max-height: 80vh;
  margin: 0 auto 32px;
}
.theia-anim-compact {
  width: 240px;
  height: 240px;
  margin: 0 auto 16px;
}

.theia-anim svg .geo-circle,
.theia-anim svg .geo-bar,
.theia-anim svg .eye-leaf,
.theia-anim svg .iris {
  transform-box: fill-box;
  transform-origin: center;
  will-change: transform, opacity;
}

/* ---- Visually-hidden utility for the accessible name span ---- */

.theia-anim .visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* ---- Nav-mark wrapper (per-page header logo) ----
   No CSS animation on the outer SVG; the blink is driven by
   theia-anim.js animating .nav-leaf's d-attribute and .nav-iris's
   opacity.  The previous version applied scaleY to the whole SVG
   which squashed the entire badge flat — not a blink. */
.nav-mark {
  display: inline-block;
}

/* ============================================================
 *  Keyframes
 * ============================================================ */

@keyframes theia-fade-in   { from { opacity: 0; } to { opacity: 1; } }
@keyframes theia-fade-out  { from { opacity: 1; } to { opacity: 0; } }

/* No-JS fallback only.  Lifts the bar from the theta-centre to a
   position above the leaf top so the bar visually sits as a brow
   even without the JS path's curved-d-morph.  JS path suppresses
   this animation via the .js-enabled override below. */
@keyframes theia-bar-journey {
  0%   { transform: translateY(0); }
  100% { transform: translateY(-132px); }
}

@keyframes theia-circle-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes theia-leaf-in    { from { opacity: 0; } to { opacity: 1; } }

/* CSS-only fallback blink (no-JS path).  scaleY aliases badly at
   extreme compressions — at scaleY(0.04) the stroked curves
   disintegrate into a patchy dashed line.  Bottom-out at 0.12 so
   the closed state is a clean thin ellipse rather than an aliased
   smear.  The JS path (which is what 99.9% of users get) uses a
   d-attribute morph instead — see theia-anim.js. */
@keyframes theia-blink {
  0%   { transform: scaleY(1);    animation-timing-function: ease-in; }
  45%  { transform: scaleY(0.12); animation-timing-function: linear; }
  55%  { transform: scaleY(0.12); animation-timing-function: ease-out; }
  80%  { transform: scaleY(1.025); }
  100% { transform: scaleY(1); }
}

@keyframes theia-iris-reveal {
  0%, 40%   { opacity: 0; }
  50%, 100% { opacity: 1; }
}

@keyframes theia-caption-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes theia-caption-rise-dim {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============================================================
 *  Full variant — collapsed-beat choreography
 *  (concurrent brow lift + circle morph at 1.70-2.45s)
 * ============================================================ */

.theia-anim-full .greek-char {
  fill: var(--tan);
  font-family: inherit;
  font-size: 56px;
  font-weight: 500;
  text-anchor: middle;
  opacity: 0;
}
/* All four Greek glyphs fade out together at 1.70s so the morph
   beat starts from a clean stage. */
.theia-anim-full .greek-Θ {
  animation:
    theia-fade-in  calc(0.30s * var(--speed)) ease-out calc(0.15s * var(--speed)) 1 forwards,
    theia-fade-out calc(0.40s * var(--speed)) ease-in  calc(1.70s * var(--speed)) 1 forwards;
}
.theia-anim-full .greek-ε {
  animation:
    theia-fade-in  calc(0.30s * var(--speed)) ease-out calc(0.45s * var(--speed)) 1 forwards,
    theia-fade-out calc(0.40s * var(--speed)) ease-in  calc(1.70s * var(--speed)) 1 forwards;
}
.theia-anim-full .greek-ί {
  animation:
    theia-fade-in  calc(0.30s * var(--speed)) ease-out calc(0.75s * var(--speed)) 1 forwards,
    theia-fade-out calc(0.40s * var(--speed)) ease-in  calc(1.70s * var(--speed)) 1 forwards;
}
.theia-anim-full .greek-α {
  animation:
    theia-fade-in  calc(0.30s * var(--speed)) ease-out calc(1.05s * var(--speed)) 1 forwards,
    theia-fade-out calc(0.40s * var(--speed)) ease-in  calc(1.70s * var(--speed)) 1 forwards;
}

/* Geo-Θ: circle + bar fade in at 1.70s (overlapping the Greek-text
   fade-out tail).  No-JS path then runs the CSS cross-fade + bar-
   journey; the JS path (.js-enabled override below) replaces these
   with a true d-attribute morph driven by anime.js. */
.theia-anim-full .geo-circle {
  opacity: 0;
  stroke: var(--tan);
  stroke-width: 3.5;
  fill: none;
  animation:
    theia-fade-in    calc(0.30s * var(--speed)) ease-out calc(1.70s * var(--speed)) 1 forwards,
    theia-circle-out calc(0.55s * var(--speed)) ease-in  calc(1.90s * var(--speed)) 1 forwards;
}
.theia-anim-full .geo-bar {
  opacity: 0;
  stroke: var(--tan);
  stroke-width: 3.5;
  stroke-linecap: round;
  fill: none;
  animation:
    theia-fade-in     calc(0.30s * var(--speed)) ease-out calc(1.70s * var(--speed)) 1 forwards,
    theia-bar-journey calc(0.55s * var(--speed)) cubic-bezier(0.2, 0.7, 0.2, 1) calc(1.90s * var(--speed)) 1 forwards;
}
.theia-anim-full .eye-leaf {
  opacity: 0;
  stroke: var(--tan);
  stroke-width: 3.5;
  stroke-linejoin: round;
  fill: none;
  animation:
    theia-leaf-in calc(0.55s * var(--speed)) ease-out calc(1.90s * var(--speed)) 1 forwards,
    theia-blink   calc(0.80s * var(--speed)) linear   calc(2.55s * var(--speed)) 1 forwards;
}
.theia-anim-full .iris {
  opacity: 0;
  fill: var(--teal);
  animation:
    theia-iris-reveal calc(0.80s * var(--speed)) linear calc(2.55s * var(--speed)) 1 forwards,
    theia-blink       calc(0.80s * var(--speed)) linear calc(2.55s * var(--speed)) 1 forwards;
}

.theia-anim-full .caption {
  opacity: 0;
  text-anchor: middle;
  font-family: inherit;
}
.theia-anim-full .caption-name {
  fill: var(--tan);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: 2px;
  animation: theia-caption-rise calc(0.45s * var(--speed)) ease-out calc(3.45s * var(--speed)) 1 forwards;
}
.theia-anim-full .caption-fn {
  fill: var(--muted);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 1px;
  animation: theia-caption-rise calc(0.45s * var(--speed)) ease-out calc(3.65s * var(--speed)) 1 forwards;
}
.theia-anim-full .caption-platform {
  fill: #7d8a9e;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 1.5px;
  animation: theia-caption-rise-dim calc(0.45s * var(--speed)) ease-out calc(3.85s * var(--speed)) 1 forwards;
}

/* ============================================================
 *  Compact variant — drops Greek intro + captions.
 *  Whole sequence done in ~2s; plays once and holds.
 * ============================================================ */

.theia-anim-compact .geo-circle {
  opacity: 0;
  stroke: var(--tan);
  stroke-width: 3.5;
  fill: none;
  animation:
    theia-fade-in    calc(0.30s * var(--speed)) ease-out 0s 1 forwards,
    theia-circle-out calc(0.55s * var(--speed)) ease-in  calc(0.30s * var(--speed)) 1 forwards;
}
.theia-anim-compact .geo-bar {
  opacity: 0;
  stroke: var(--tan);
  stroke-width: 3.5;
  stroke-linecap: round;
  fill: none;
  animation:
    theia-fade-in     calc(0.30s * var(--speed)) ease-out 0s 1 forwards,
    theia-bar-journey calc(0.55s * var(--speed)) cubic-bezier(0.2, 0.7, 0.2, 1) calc(0.30s * var(--speed)) 1 forwards;
}
.theia-anim-compact .eye-leaf {
  opacity: 0;
  stroke: var(--tan);
  stroke-width: 3.5;
  stroke-linejoin: round;
  fill: none;
  animation:
    theia-leaf-in calc(0.55s * var(--speed)) ease-out calc(0.30s * var(--speed)) 1 forwards,
    theia-blink   calc(0.80s * var(--speed)) linear   calc(0.95s * var(--speed)) 1 forwards;
}
.theia-anim-compact .iris {
  opacity: 0;
  fill: var(--teal);
  animation:
    theia-iris-reveal calc(0.80s * var(--speed)) linear calc(0.95s * var(--speed)) 1 forwards,
    theia-blink       calc(0.80s * var(--speed)) linear calc(0.95s * var(--speed)) 1 forwards;
}

/* ============================================================
 *  JS-enabled overrides.
 *
 *  When theia-anim.js takes over:
 *   - geo-bar's translate is suppressed; anime.js morphs its
 *     d-attribute from straight line to curved brow (handles
 *     lift AND curve in one motion).
 *   - geo-circle's circle-out cross-fade AND its blink scaleY
 *     are both suppressed; anime.js morphs its d-attribute through
 *     the WHOLE sequence (open -> hold -> closed -> hold -> open)
 *     in a single anime() call.  Multiple anime() calls on the
 *     same target+property cause the second to silently override
 *     the first, so they must be combined.
 *   - .iris animation is suppressed; anime.js drives iris opacity
 *     in sync with the blink (iris hides during the closed phase,
 *     fades in as the lid re-opens — the iris is "unveiled" by
 *     the rising lid).
 *   - .eye-leaf is hidden because geo-circle has become the leaf
 *     via the d-morph.
 * ============================================================ */
.theia-anim-full.js-enabled .geo-circle {
  animation:
    theia-fade-in calc(0.30s * var(--speed)) ease-out calc(1.70s * var(--speed)) 1 forwards;
}
.theia-anim-full.js-enabled .geo-bar {
  animation:
    theia-fade-in calc(0.30s * var(--speed)) ease-out calc(1.70s * var(--speed)) 1 forwards;
}
.theia-anim.js-enabled .eye-leaf { display: none; }
.theia-anim.js-enabled .iris {
  animation: none !important;
}
.theia-anim-compact.js-enabled .geo-circle {
  animation:
    theia-fade-in calc(0.30s * var(--speed)) ease-out 0s 1 forwards;
}
.theia-anim-compact.js-enabled .geo-bar {
  animation:
    theia-fade-in calc(0.30s * var(--speed)) ease-out 0s 1 forwards;
}

/* ============================================================
 *  Launch-transition overlay
 *
 *  Renders the full-variant animation as a fullscreen splash on
 *  the run-detail page immediately after a Launch click. The
 *  view appends ?launched=1 to the redirect URL; the template
 *  conditionally includes the overlay; theia-anim.js strips the
 *  query param via history.replaceState after init so a refresh
 *  of the cleaned URL does not replay the overlay.
 *
 *  Total budget: ~3.2s for the full animation timeline + a 0.6s
 *  fade-out + a 0.2s pointer-events gap = ~4s before the
 *  underlying run-detail page is fully visible and interactive.
 *  After the fade, display:none takes the overlay out of the
 *  layout so it can't ever steal a click.
 * ============================================================ */

.theia-launch-overlay {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-page, #1c1f26);
  animation: theia-launch-overlay-out 4.0s ease-in-out 1 forwards;
}

/* The full animation root inside the overlay drops its bordered
   card chrome (it's redundant against the fullscreen backdrop).  */
.theia-launch-overlay .theia-anim-full {
  background: transparent;
  border: none;
  box-shadow: none;
  margin: 0;
}

@keyframes theia-launch-overlay-out {
  0%,
  80%   { opacity: 1; pointer-events: auto; }
  95%   { opacity: 0; pointer-events: none; }
  100%  { opacity: 0; pointer-events: none; visibility: hidden; }
}

/* ============================================================
 *  prefers-reduced-motion — endpoint state only.
 * ============================================================ */

@media (prefers-reduced-motion: reduce) {
  .theia-anim *,
  .nav-mark * {
    animation: none !important;
  }
  .theia-anim .greek-char { opacity: 0 !important; }
  .theia-anim .geo-circle { opacity: 0 !important; }
  .theia-anim .geo-bar    {
    opacity: 1 !important;
    transform: translateY(-132px) !important;
  }
  .theia-anim .eye-leaf,
  .theia-anim .iris,
  .theia-anim .caption {
    opacity: 1 !important;
    transform: none !important;
  }
  .theia-anim .caption-platform { opacity: 1 !important; }
  /* Reduced-motion: skip the splash entirely. The overlay is
     pure ceremony; users who request no motion get the run-
     detail content immediately.  */
  .theia-launch-overlay {
    display: none !important;
  }
}
