/* haohan.org logo animation — layout only. All motion lives in logo-anim.js. */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: #000;
  color: #f2f2f2;
}

/* Hero: 16:9 on desktop, never taller than the viewport. */
.logo-anim {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: 100vh;
  max-height: 100svh;
  background: #000;
  overflow: hidden;
}

/*
 * The source viewBox (1000x1000) leaves ~50% empty black around the lockup.
 * Sizing the square SVG at 118% of hero height makes the lockup ~60% of the
 * hero height; only empty black background falls outside the hero.
 */
.logo-anim > svg {
  position: absolute;
  top: 50%;
  left: 50%;
  display: block;
  height: 118%;
  width: auto;
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  /* Let flight, dust and rings use the whole hero (the hero itself clips).
     The final lockup lies well inside the viewBox, so nothing changes there. */
  overflow: visible;
}

/* Mobile / portrait: scale by width, square box, full viewBox visible (no cropping). */
@media (max-width: 640px), (max-aspect-ratio: 4 / 5) {
  .logo-anim {
    aspect-ratio: auto;
    max-height: none;
    min-height: 100vh;
    min-height: 100svh;
    display: flex;
    align-items: center;
  }

  .logo-anim > svg {
    position: static;
    width: 100%;
    height: auto;
    transform: none;
  }
}

/*
 * Sound toggle: absolute inside the hero (no layout shift), 44px hit area.
 * Hidden until logo-anim.js confirms Web Audio + animated mode.
 */
.hh-sound {
  position: absolute;
  right: 16px;
  bottom: 16px;
  z-index: 2;
  width: 44px;
  height: 44px;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(153, 153, 153, 0.35);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.4);
  color: #999999;
  cursor: pointer;
  /* Starts transparent so the very first frames are pure black; logo-anim.js
     adds .hh-ready and the button fades in after a short delay. */
  opacity: 0;
  transition: color 0.2s ease, border-color 0.2s ease, opacity 0.6s ease 0.8s;
  -webkit-tap-highlight-color: transparent;
}

.hh-sound[hidden] {
  display: none;
}

.hh-sound.hh-ready {
  opacity: 0.8;
}

.hh-sound:hover {
  color: #f2f2f2;
  border-color: rgba(242, 242, 242, 0.6);
  opacity: 1;
}

.hh-sound:focus {
  outline: none;
}

.hh-sound:focus-visible {
  outline: 2px solid #f2f2f2;
  outline-offset: 3px;
  opacity: 1;
}

.hh-sound .hh-sound-on { display: none; }
.hh-sound[aria-pressed="true"] .hh-sound-on { display: inline; }
.hh-sound[aria-pressed="true"] .hh-sound-off { display: none; }

@media (max-width: 640px), (max-aspect-ratio: 4 / 5) {
  .hh-sound {
    right: 12px;
    bottom: 12px;
  }
}

/*
 * First-paint gate. html.hh-anim is added by the synchronous inline script in
 * <head> only when the animation will play, so the master logo is hidden from
 * the very first paint (black screen, no flash). logo-anim.js removes the class
 * as soon as it has rendered the t = 0 (all-black) state and owns visibility.
 * ?static=1 / reduced motion / already played: no class, logo shows at once.
 *
 * Fail-safe: if logo-anim.js never runs (blocked / failed to load), the class
 * stays and this animation reveals the final logo after 5 s instead of leaving
 * the hero black forever. When JS removes the class the rule stops applying.
 */
html.hh-anim .logo-anim .hh-gate {
  visibility: hidden;
  animation: hh-failsafe 0s linear 5s forwards;
}

@keyframes hh-failsafe {
  to { visibility: visible; }
}
