/*
 * perf.css — Starforge GPU Animation Contract
 * ─────────────────────────────────────────────────────────────────────────────
 * Imported LAST in index.html. Overrides animation @keyframes from all earlier
 * stylesheets to enforce GPU-compositable properties only (transform + opacity).
 *
 * CONTRACT — future animation work MUST follow these rules:
 *   1. Animate ONLY: transform, opacity (and color/background-color for fades).
 *   2. NEVER animate: box-shadow, filter, width, height, top, left, margin,
 *      padding, border-width, or backdrop-filter.
 *   3. backdrop-filter: blur(N) ONLY — never add saturate(), contrast(),
 *      brightness(). They are 3-4× more expensive than blur alone.
 *   4. Declare will-change ONLY in this file, scoped to known high-frequency
 *      paths. Over-declaring will-change wastes GPU VRAM (every entry = a new
 *      GPU layer that must be composited every frame).
 *   5. Hover effects: use opacity/transform — never filter:brightness().
 *
 * Technique: @keyframes defined here WIN because CSS uses last-definition-wins
 * for identically-named @keyframes. Selectors match the originals for equal
 * specificity. This file is the single authoritative animation override layer.
 */


/* ════════════════════════════════════════════════════════════════════════════
 * §1 — GPU PROMOTION HINTS
 * will-change promotes elements to their own GPU compositing layer, removing
 * them from the main-thread stacking flow. Apply only to elements with
 * SIGNIFICANT, FREQUENT animation (infinite loops, per-beat transitions, or
 * multi-element choreography). Backdrop-filter elements create their own
 * layers already — will-change on them is redundant.
 * ════════════════════════════════════════════════════════════════════════════ */

/* CY2 victory ceremony — 8+ elements animate simultaneously */
.cer-cy2 .cer-vic   { will-change: transform, opacity; }
.cer-cy2 .cer-lbar  { will-change: transform; }
.cer-cy2 .cer-flash { will-change: opacity; }
.cer-plasma         { will-change: transform, opacity; }

/* Demo coach card — repositions and transitions every beat */
.sf-coach__card, .sf-coach__min { will-change: transform, opacity; }
.sf-caps__pill                  { will-change: transform, opacity; }

/* Header panels — slide in/out on user action */
.sf-evapanel, #sfes .evapanel { will-change: transform; }
.hc-pop, .hc-navpop           { will-change: transform, opacity; }

/* Shipyard ship cards — entrance animation on list mount */
.sy-ship { will-change: transform, opacity; }

/* Stage lobby — sflIn entrance when lobby mounts */
#sfes-lobby { will-change: transform, opacity; }

/* Carousel track — translates on every slide change */
.sf-poe-track { will-change: transform; }

/* WO raise kernel — spinning plasma rings (sfrSpin is continuous) */
.sfr-kernel__plasma { will-change: transform; }


/* ════════════════════════════════════════════════════════════════════════════
 * §2 — BOX-SHADOW ANIMATIONS → OPACITY + SCALE
 * Box-shadow changes trigger layout recalculation every frame. Replace all
 * pulsing-glow @keyframes with scale+opacity equivalents. The visual effect
 * is equivalent (element expands/contracts rhythmically) without layout cost.
 *
 * Each override matches the original @keyframes name exactly so the animation
 * property declarations in other CSS files require no change.
 * ════════════════════════════════════════════════════════════════════════════ */

/* app.css — .login__kernel .kernel (sign-in mote breathing pulse) */
@keyframes breathe {
  0%, 100% { transform: scale(1);    opacity: 1;   }
  50%       { transform: scale(1.07); opacity: .88; }
}

/* appHeader.css — .sf-standup.hot / .o3__mtg.hot (stand-up pressure alert) */
@keyframes sf-standup-pulse {
  0%, 100% { opacity: 1;   }
  50%       { opacity: .65; }
}

/* appHeader.css — .hc-mtg.is-ready (meeting chip ready-to-join pulse) */
@keyframes hc-mtg-pulse {
  0%, 100% { transform: scale(1);    opacity: 1;  }
  50%       { transform: scale(1.05); opacity: .8; }
}

/* shipyard.css — .sy-chip.boss (critical-WO chip infinite pulse) */
@keyframes sy-boss {
  0%, 100% { opacity: 1;   }
  50%       { opacity: .58; }
}

/* shipyard.css — .sy-meta.tick .sy-chip (live patch value-change flash) */
@keyframes sy-chiptick {
  0%   { opacity: 0; transform: scale(.94); }
  28%  { opacity: 1; transform: scale(1.05); }
  100% { opacity: 1; transform: scale(1);   }
}

/* enteredStage.css — .sfes-seal at gate-pass (the seal confirmation burst) */
@keyframes sfesSeal {
  0%   { opacity: 0; transform: scale(.8);  }
  55%  { opacity: 1; transform: scale(1.1); }
  100% { opacity: 0; transform: scale(1.4); }
}


/* ════════════════════════════════════════════════════════════════════════════
 * §3 — FILTER ANIMATIONS → OPACITY + TRANSFORM
 * Animated filter values (blur, brightness) create a new GPU layer per frame
 * and prevent the browser from caching composited results. Replace with
 * opacity+transform which composite cheaply and cache between frames.
 *
 * The cinematic quality is preserved: scale(.97→1) + opacity(0→1) reads as
 * a materialisation, which is the intended effect in every case below.
 * ════════════════════════════════════════════════════════════════════════════ */

/* app.css — founding-rise (identity founding hero element) */
@keyframes founding-rise {
  0%   { transform: scale(.1);   opacity: 0; }
  40%  { transform: scale(1.12); opacity: 1; }
  100% { transform: scale(1);    opacity: 1; }
}

/* ceremonies.css — cerVicIn (CY2 victory panel materialises after flash) */
@keyframes cerVicIn {
  from { opacity: 0; transform: translateY(36px) scale(.97); }
  to   { opacity: 1; transform: none; }
}

/* enteredStage.css — sfesCine (Begin→Turn cinematic handoff transition) */
@keyframes sfesCine {
  from { opacity: 0; transform: scale(.986); }
  to   { opacity: 1; transform: none; }
}

/* stageLobby.css — sflIn (stage lobby entrance on first mount) */
@keyframes sflIn {
  from { opacity: 0; transform: scale(.99); }
  to   { opacity: 1; transform: none;       }
}

/* workshopHome.css — whArrIn (WO-arrive stagger: text items cascade in) */
@keyframes whArrIn {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none;             }
}

/* demo-shell.css — sf-poe-cer-plate-settle (carousel CTA settle) */
@keyframes sf-poe-cer-plate-settle {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: scale(1);   }
}


/* ════════════════════════════════════════════════════════════════════════════
 * §4 — BACKDROP-FILTER: STRIP saturate()
 * saturate() multiplied with blur() is 3-4× more expensive than blur alone.
 * At these opacity levels the saturation boost is imperceptible. Override the
 * two known saturate() instances with blur() only.
 *
 * Future rule: if you need a glass panel to "pop", increase the blur value or
 * the panel's opacity — never reach for saturate(). This file enforces it.
 * ════════════════════════════════════════════════════════════════════════════ */

/* ceremonies.css: CY1 gate-sealed chip */
.cer-sealchip {
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
}

/* enteredStage.css: TX-A scene panel glass (scene body, options, canvas…) */
#sfes[data-tx="a"] .scene .art,
#sfes[data-tx="a"] .scene .opt,
#sfes[data-tx="a"] .scene .cmpc,
#sfes[data-tx="a"] .scene .q,
#sfes[data-tx="a"] .scene .can,
#sfes[data-tx="a"] .scene .sq,
#sfes[data-tx="a"] .scene .vrow {
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
}

/* demo-shell.css: veil behind teach-scrim (saturate(.94) = no-op visually) */
.sf-veil,
.sf-tile-scrim {
  -webkit-backdrop-filter: blur(3px);
          backdrop-filter: blur(3px);
}


/* ════════════════════════════════════════════════════════════════════════════
 * §5 — HOVER FILTER OVERRIDES
 * filter:brightness() on hover creates a new stacking context on each hover,
 * forcing the browser to re-composite that subtree. Replace with opacity.
 * ════════════════════════════════════════════════════════════════════════════ */

/* demo-shell.css: fork option hover and action button hovers */
.sf-fl-fork-btn:hover { filter: none !important; opacity: .88; }
