/* EYEZON header logo — three stacked layers.
 *
 * Scoped to the header: every selector sits under .site-header.
 *
 * FAIL-SAFE: all three layers are visible by default, at opacity 1, with no
 * classes and no JS. Together they compose the complete logo. CSS never gates
 * the logo's visibility on a class — losing the script leaves a correct,
 * static lockup.
 *
 * The rim is its own layer because it wraps the whole lockup: any horizontal
 * split cuts it in half, which is why it could not flip when the artwork was
 * only two layers.
 */

.site-header .ez-logo {
  /* Lens radius in px, not %. A percentage radius in radial-gradient resolves
     against the gradient ray on a non-square box and misses the circle.
     Box is 89x44; lens diameter is 15.5% of width = 13.8px, so r = 6.9px. */
  --ez-lens-r: 6.9px;
  --ez-flip-dur: 1.1s;
  --ez-flare-dur: 0.9s;
  --ez-flare-cycle: 12s;
  /* Flips settle, then a 0.35s hold before the first sweep. */
  --ez-flare-delay: 1.45s;
  /* Secury signature easing — the Act I character reveal curve. */
  --ez-ease: cubic-bezier(0.26, -0.14, 0, 1.01);

  position: relative;
  display: block;
  width: 89px;
  height: 44px;
  line-height: 0;
  /* Without perspective the rotation is flat and reads as a squash. */
  perspective: 800px;
}

/* All three share one canvas (1303x642) so they stack with zero offset. */
.site-header .ez-logo-layer {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 1;
}

/* Only the two that rotate need this. Without it the mirrored face shows
   through as each layer passes 90 degrees. */
.site-header .ez-logo-layer--rim,
.site-header .ez-logo-layer--wordmark {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  transform-origin: 50% 50%;
}

/* The tagline never moves. Stated explicitly so a later edit to the shared
   layer rule cannot start animating it. */
.site-header .ez-logo-layer--tagline {
  transform: none !important;
  transition: none !important;
}

/* ---- entrance -------------------------------------------------------------
   Primed state, set one frame before the animation so the transition has a
   value to move from. Opposite directions so the two cross in the middle.

   `transition: none` here is load-bearing, not tidiness. Both classes are added
   in the same frame, and the transition lives on .is-anim — so without this the
   element animates TOWARD rotateY(180deg) rather than starting there, and two
   frames later gets pulled back from wherever it reached. Measured: the layers
   sat at identity by 300ms and nothing visible happened. Suppressing the
   transition while priming makes the 180deg the start value, and removing
   .is-priming then hands over to .is-anim's transition.

   The selectors name BOTH classes for a second reason. They are present at the
   same instant, so `.is-anim`'s rotateY(0deg) and `.is-priming`'s
   rotateY(180deg) were an equal-specificity tie at (0,4,1) decided by source
   order — and .is-anim is declared later, so it won and the layer never sat at
   180. Naming both makes this (0,5,1) and removes the dependence on ordering. */
.site-header .ez-logo.is-anim.is-priming .ez-logo-layer--rim,
.site-header .ez-logo.is-anim.is-priming .ez-logo-layer--wordmark {
  transition: none !important;
}

.site-header .ez-logo.is-anim.is-priming .ez-logo-layer--rim {
  transform: rotateY(180deg);
}

.site-header .ez-logo.is-anim.is-priming .ez-logo-layer--wordmark {
  transform: rotateY(-180deg);
}

.site-header .ez-logo.is-anim .ez-logo-layer--rim,
.site-header .ez-logo.is-anim .ez-logo-layer--wordmark {
  transform: rotateY(0deg);
  /* Both start together — no stagger — so they meet head-on. */
  transition: transform var(--ez-flip-dur) var(--ez-ease);
}

/* ---- flare ----------------------------------------------------------------
   A specular sweep across the camera lens, clipped to the measured circle by a
   mask on a pseudo-element. The source images are never animated.

   This runs from CSS alone and is not gated on a JS class: the entrance plays
   once per session, but the flare is ambient and repeats on every load. Its
   only gate is prefers-reduced-motion below. */
.site-header .ez-logo::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(45deg,
    rgba(255,255,255,0) 35%,
    rgba(255,255,255,0.95) 50%,
    rgba(255,255,255,0) 65%);
  background-size: 300% 300%;
  background-position: 0% 100%;
  -webkit-mask-image: radial-gradient(circle var(--ez-lens-r) at 74.8% 55.5%, #000 98%, transparent 100%);
          mask-image: radial-gradient(circle var(--ez-lens-r) at 74.8% 55.5%, #000 98%, transparent 100%);
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  animation: ez-logo-flare var(--ez-flare-cycle) linear var(--ez-flare-delay) infinite;
}

/* The sweep occupies 0.9s of a 12s cycle — 7.5% — and the rest is idle.
   Percentages: 45% of the sweep is 0.9s*0.45 = 0.405s = 3.375% of the cycle. */
@keyframes ez-logo-flare {
  0%      { opacity: 0;    background-position: 0% 100%; }
  3.375%  { opacity: 0.85; }
  7.5%    { opacity: 0;    background-position: 100% 0%; }
  100%    { opacity: 0;    background-position: 100% 0%; }
}

/* ---- mobile --------------------------------------------------------------- */
@media (max-width: 860px) {
  .site-header .ez-logo {
    width: 68.8px;
    height: 34px;
    /* 15.5% of 68.8px = 10.66px diameter. */
    --ez-lens-r: 5.33px;
  }

  /* .site-branding is position:absolute and only 33px tall here — the theme
     sized it for its own ~30px logo — so centring inside it cannot work and a
     34px logo overhangs. Centre the box itself instead. */
  .site-header .site-branding:has(.ez-logo) {
    height: auto;
    top: 50%;
    transform: translateY(-50%);
  }
}

/* ---- reduced motion -------------------------------------------------------
   Skip the flips AND stop the repeating flare outright. A looping animation is
   precisely what this setting exists to prevent, so it is switched off rather
   than shortened. All three layers stay visible — the same state the page
   holds with no JS at all. */
@media (prefers-reduced-motion: reduce) {
  .site-header .ez-logo.is-priming .ez-logo-layer--rim,
  .site-header .ez-logo.is-priming .ez-logo-layer--wordmark,
  .site-header .ez-logo.is-anim .ez-logo-layer--rim,
  .site-header .ez-logo.is-anim .ez-logo-layer--wordmark {
    transform: none;
    transition: none;
  }

  .site-header .ez-logo::after {
    animation: none;
    opacity: 0;
  }
}

/* ---- header integration ---------------------------------------------------
   Dark ground on the graded homepage only. The theme paints #090909 under
   .is-header-dark; matching the Act I token removes the seam where the header
   meets the page. (0,2,1) beats the theme's (0,2,0) without !important. */
body.is-header-dark .header-wrap,
body.is-header-dark .site-header .menu-wrap {
  background: var(--ez-grade-bg-i, #0F0D0A);
}

/* The theme sizes .site-title for text; with an image inside, its margins and
   font metrics add stray space. */
.site-header .site-title.ez-logo-title {
  margin: 0;
  line-height: 0;
  font-size: 0;
}

/* main.css caps `.site-title img` at max-height 26px (0,1,1), which would hold
   the layers at 30px however tall the box is. This is (0,4,1). */
.site-header .site-title.ez-logo-title .ez-logo img {
  max-height: none;
  height: 100%;
}

/* .site-branding is align-items: flex-start, leaving a 44px logo overhanging a
   90px header. :has() keeps this to headers carrying our logo. */
.site-header .site-branding:has(.ez-logo) {
  align-items: center;
}

.site-header .site-branding:has(.ez-logo) .site-branding-wrap {
  align-items: center;
}
