/**
 * be-os pulse loader — the wordmark, breathing.
 *
 * One loader. One rhythm. Used everywhere — engine runs, Studio tools,
 * inline status indicators. The two-intensity system is retired: no
 * separate ceremonial / quiet variants. The pulse is restrained enough
 * to belong in any context, scaled to fit the surface.
 *
 * The animation is the em-dash glyph from the be—os wordmark, gently
 * compressing and expanding along its horizontal axis. On irregular
 * intervals two small dots appear above the bar, briefly forming a
 * smiley face. When the eyes appear, the bar settles down so the full
 * face composition lands balanced inside its container — when the eyes
 * fade, the bar floats back up to vertical center. Two coordinated
 * states, one continuous gesture.
 *
 * Anatomy
 * -------
 *   - <svg> with viewBox="-20 -14 40 28"
 *   - <rect class="beos-pulse-bar"> at vertical center (SMIL animates
 *     x + width for the breath; CSS keyframe shifts y when eyes appear)
 *   - Two <circle class="beos-pulse-eye"> eyes above (CSS keyframes
 *     animate opacity, blinking on irregular intervals)
 *
 * Animation
 * ---------
 *   Bar breath:    1.6s cycle. SMIL animates x + width. Always running.
 *   Eye blinks:    12s cycle. Eyes appear at ~2.5s, 5s, 8s, 10.5s.
 *                  CSS keyframes (SMIL multi-begin isn't reliable).
 *   Bar settle:    12s cycle, synced with eye blinks. Bar shifts down
 *                  translateY(125%) when eyes show, returns to 0 when
 *                  they fade. CSS keyframes.
 *
 * Size variants (set on the container)
 * ------------------------------------
 *   .beos-pulse-sm  → 36px wide   (inline status, buttons, narrow pills)
 *   .beos-pulse-md  → 72px wide   (Studio tool runs, panel-level loading)
 *   .beos-pulse-lg  → 100px wide  (engine runs, full-width waiting states)
 *
 * Display heights follow the viewBox aspect (40:28 = 1.428:1):
 *   .beos-pulse-sm  → ~25px tall
 *   .beos-pulse-md  → ~50px tall
 *   .beos-pulse-lg  → ~70px tall
 *
 * Default size when no variant is present: .beos-pulse-md (72px).
 *
 * Colour
 * ------
 * Fill uses currentColor. Set `color: <value>` on the container to adopt
 * the surface's text tone — works automatically on light and dark bgs.
 *
 * Markup
 * ------
 *   <span class="beos-pulse beos-pulse-md">
 *     <svg viewBox="-20 -14 40 28" aria-label="Loading">
 *       <circle class="beos-pulse-eye" cx="-4" cy="-7" r="2" opacity="0"/>
 *       <circle class="beos-pulse-eye" cx="4"  cy="-7" r="2" opacity="0"/>
 *       <rect class="beos-pulse-bar" y="-2" height="4" rx="2" ry="2">
 *         <animate attributeName="x"     dur="1.6s" repeatCount="indefinite"
 *           calcMode="spline" keyTimes="0; 0.5; 1"
 *           keySplines="0.4 0 0.2 1; 0.4 0 0.2 1"
 *           values="-14; -10; -14"/>
 *         <animate attributeName="width" dur="1.6s" repeatCount="indefinite"
 *           calcMode="spline" keyTimes="0; 0.5; 1"
 *           keySplines="0.4 0 0.2 1; 0.4 0 0.2 1"
 *           values="28; 20; 28"/>
 *       </rect>
 *     </svg>
 *   </span>
 *
 * Accessibility
 * -------------
 * Respects prefers-reduced-motion: bar animation stops at full width,
 * eyes hidden, bar held at vertical center.
 */

/* ── The pulse — unified loader (PRIMARY) ─────────────────── */

.beos-pulse {
  display: inline-block;
  line-height: 0;
  color: #13181B;           /* VOID — overrideable via `color` on container */
  vertical-align: middle;
}

.beos-pulse svg {
  width: 100%;
  height: auto;
  display: block;
  overflow: visible;        /* eyes sit above the bar baseline */
}

.beos-pulse rect,
.beos-pulse circle {
  fill: currentColor;
}

.beos-pulse-sm { width: 36px; }
.beos-pulse-md { width: 72px; }
.beos-pulse-lg { width: 100px; }

/* Default size when no variant is present */
.beos-pulse:not(.beos-pulse-sm):not(.beos-pulse-md):not(.beos-pulse-lg) {
  width: 72px;
}

/* ── Eye easter-egg keyframe ──────────────────────────────────
   12-second cycle. Eyes blink ON during four windows at
   irregular intervals: roughly 2.5s, 5s, 8s, 10.5s within the
   cycle. Each blink ~0.3s visible. CSS keyframes are reliable
   across renderers — SMIL with multi-begin + fill="freeze" is
   not. The face shows often enough to feel like a recurring
   micro-character, but the irregular spacing keeps it surprising.
*/
@keyframes beos-pulse-eye-blink {
  0%, 20%, 24%, 41%, 45%, 66%, 70%, 87%, 91%, 100% { opacity: 0; }
  21%, 23%, 42%, 44%, 67%, 69%, 88%, 90%           { opacity: 1; }
}

.beos-pulse-eye {
  animation: beos-pulse-eye-blink 12s infinite;
}

/* ── Bar settle keyframe ──────────────────────────────────────
   Synced 1:1 with the eye blink keyframe. When the eyes appear,
   the bar shifts down translateY(125%) of its own height so the
   full face composition lands lower in the viewBox (eye-top high,
   bar low — like a real smiley). When eyes fade, bar floats back
   to viewBox center. The two animations together create the face;
   bar alone reads as the em-dash signature. */
@keyframes beos-pulse-bar-settle {
  0%, 19%        { transform: translateY(0); }
  21%, 23%       { transform: translateY(125%); }
  25%, 40%       { transform: translateY(0); }
  42%, 44%       { transform: translateY(125%); }
  46%, 65%       { transform: translateY(0); }
  67%, 69%       { transform: translateY(125%); }
  71%, 86%       { transform: translateY(0); }
  88%, 90%       { transform: translateY(125%); }
  92%, 100%      { transform: translateY(0); }
}

.beos-pulse-bar {
  /* transform-box: fill-box keeps the transform calc against the
     bar's own bounding rect, so translateY(125%) shifts by 125%
     of the bar's height regardless of SMIL-driven x/width changes. */
  transform-box: fill-box;
  transform-origin: center;
  animation: beos-pulse-bar-settle 12s infinite;
}

/* ── Reduced motion fallback ──────────────────────────────────
   Stop all animations. Bar holds at viewBox center, eyes hidden. */
@media (prefers-reduced-motion: reduce) {
  .beos-pulse rect animate { display: none; }
  .beos-pulse-eye {
    animation: none;
    opacity: 0;
  }
  .beos-pulse-bar {
    animation: none;
    transform: none;
  }
}


/* ═════════════════════════════════════════════════════════════
   LEGACY: .beos-loader (ceremonial pulse with goo blob morph)
   ─────────────────────────────────────────────────────────────
   The previous two-intensity system. Currently still used by
   showEngineLoader() in system/cms/index.html. Will be retired
   when LOADER-ENGINE-REPLACE swaps the engine card markup over
   to .beos-pulse. Don't add new consumers of these classes.
   ═════════════════════════════════════════════════════════════ */

.beos-loader {
  display: inline-block;
  line-height: 0;
  color: #13181B;
  vertical-align: middle;
}

.beos-loader svg {
  width: 100%;
  height: auto;
  display: block;
}

.beos-loader .beos-blobs {
  filter: url(#beos-goo);
}

.beos-loader path,
.beos-loader circle {
  fill: currentColor;
}

.beos-loader-sm { width: 24px; }
.beos-loader-md { width: 48px; }
.beos-loader-lg { width: 172px; }

.beos-loader:not(.beos-loader-sm):not(.beos-loader-md):not(.beos-loader-lg) {
  width: 48px;
}

@keyframes beosLoaderVoltReveal {
  0%,  6%  { color: #003A6C; }
  18%, 92% { color: #13181B; }
  100%     { color: #003A6C; }
}

.beos-loader-volt-reveal {
  animation: beosLoaderVoltReveal 3.6s linear infinite;
}

.beos-loader svg.beos-loader-static { display: none; }

@media (prefers-reduced-motion: reduce) {
  .beos-loader svg.beos-loader-animated { display: none; }
  .beos-loader svg.beos-loader-static   { display: block; }
  .beos-loader-volt-reveal {
    animation: none;
    color: #13181B;
  }
}
