/* ============================================================
   QUIZORIA — television performance overrides.

   Scoped entirely to `html.is-tizen`, which src/main.js sets from
   platform.isTizen. The web build never sees a single rule in this file, so the
   full design is untouched in a browser.

   WHY THIS FILE EXISTS
   --------------------
   Measured on the target set (Samsung Q60A, 2021, Tizen 6.0 / Chromium M76) the
   application ran at **2.4 fps** with the stage backdrop live. Sampling frame
   times while removing one layer at a time gave:

       everything on ......  2.4 fps   mean 417 ms   p95 1878 ms
       canvas stopped ..... 14.1 fps   mean  71 ms
       + beams hidden .....  (noisy)
       + grain hidden ..... 18.0 fps   mean  55 ms   p95   62 ms

   So the cost is not one effect but a stack of them: four large blurred,
   screen-blended, infinitely animated beams; a grain layer twice the viewport
   in each direction; and full-screen gradient *transitions*, which cannot be
   composited and repaint two million pixels per frame.

   Nothing here changes the palette, the layout or the identity. It removes the
   parts of the decoration that a 2021 television GPU cannot afford, and keeps
   the parts that carry the look.
   ============================================================ */

/* ---- the stage itself: never transition a gradient ---- */
/* `background` is not a compositable property; interpolating a full-screen
   three-layer gradient repaints the whole screen every frame of the change.
   The mood still changes, it simply cuts rather than cross-fades. */
.is-tizen .stage,
.is-tizen .stage__beams,
.is-tizen .stage__canvas,
.is-tizen .stage__vignette {
  transition: opacity 620ms var(--ease-in-out);
}

/* ---- beams: the single most expensive layer ---- */
/* blur() on a 422x1404 surface, four of them, re-run every frame because the
   keyframes animate scaleY and so invalidate the cached blurred texture; plus
   mix-blend-mode: screen, which forces a read-back of everything underneath.
   The softness is baked into the gradient stops instead, which costs nothing. */
.is-tizen .beam {
  filter: none;
  mix-blend-mode: normal;
  opacity: .5;
  background: linear-gradient(180deg, rgba(140, 110, 255, .20) 0%,
                                      rgba(90, 70, 220, .07) 40%,
                                      transparent 82%);
}
.is-tizen .beam--2 {
  background: linear-gradient(180deg, rgba(53, 208, 255, .16) 0%, transparent 80%);
}
.is-tizen .beam--4 {
  background: linear-gradient(180deg, rgba(243, 200, 96, .12) 0%, transparent 78%);
}
/* Two sweeping beams read the same as four from the sofa and halve the work. */
.is-tizen .beam--3,
.is-tizen .beam--4 { display: none; }

/* The beams hold still on a television.
   With the blur and the blend gone the app reached 38.5 fps, and hiding the
   beams entirely took it to a locked 59.6 (p95 17 ms). The whole of that
   remaining gap is the cost of compositing two 422x1404 layers on every frame,
   which is what an animated transform requires however cheap the property is.
   Composited once, they cost nothing: the lit arena is still there, angled and
   glowing exactly as designed. Only the slow sweep stops. */
.is-tizen .beam {
  animation: none;
  transition: none;
}
.is-tizen .beam--1 { transform: rotate(-11deg); opacity: .5; }
.is-tizen .beam--2 { transform: rotate(9deg);   opacity: .42; }

/* ---- grain: 3840x2160 of animated SVG noise, at 4.5% opacity ---- */
/* Invisible at viewing distance, ~33 MB as a composited texture, repainted
   four times a second. The best cost-to-benefit removal in the whole design. */
.is-tizen .stage__grain { display: none; }

/* ---- floor: a blurred, 3D-transformed layer ---- */
/* 0.4px of blur is not visible; the render surface it forces is. */
.is-tizen .stage__floor { filter: none; }

/* The dim state swapped a full-screen radial gradient for another one and
   transitioned between them. Dim the existing layer instead. */
.is-tizen .stage.is-dim .stage__vignette { opacity: .55; }

/* ---- screen transitions: two full-screen blurs at once ---- */
/* The router keeps the outgoing screen for 340 ms, so screenIn and screenOut
   overlap: two animated `filter: blur()` passes over 1920x1080, on every
   navigation. Opacity and transform alone give the same gesture. */
@keyframes tvScreenIn {
  from { opacity: 0; transform: translate3d(0, 2.2%, 0) scale(.985); }
  to   { opacity: 1; transform: none; }
}
@keyframes tvScreenOut {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translate3d(0, -1.6%, 0) scale(.99); }
}
.is-tizen .screen--enter,
.is-tizen .overlay,
.is-tizen .levelup { animation-name: tvScreenIn; }
.is-tizen .screen--exit { animation-name: tvScreenOut; }

/* `will-change` here is unconditional, so it holds a promoted full-screen layer
   for the life of every screen rather than for the length of the transition. */
.is-tizen .screen { will-change: auto; }

/* ---- one-off reveals that also animated a filter ---- */
@keyframes tvQuestionReveal {
  from { opacity: 0; transform: translateY(calc(var(--u) * .7)) rotateX(10deg); }
  to   { opacity: 1; transform: none; }
}
.is-tizen .question { animation-name: tvQuestionReveal; }

/* letter-spacing forces a full layout pass on every frame of the boot logo. */
@keyframes tvLogoRise {
  from { opacity: 0; transform: translateY(calc(var(--u) * 1.1)) scale(.97); }
  to   { opacity: 1; transform: none; }
}
.is-tizen .logo { animation-name: tvLogoRise; }

/* The gold flash listed `background` among its animated properties for no
   visual gain, which took the whole full-screen flash off the compositor. */
@keyframes tvFlashGold {
  0%   { opacity: 0; }
  18%  { opacity: .85; }
  100% { opacity: 0; }
}
.is-tizen .flash.is-firing--gold { animation-name: tvFlashGold; }

/* ---- infinite box-shadow animations ---- */
/* box-shadow is never compositable, so these repaint their element plus ~90px
   of glow bleed every frame, forever - and lockPulse runs at the most
   timing-sensitive moment in the game. Opacity on the same glow instead. */
@keyframes tvGlowPulse { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }

.is-tizen .answer.is-locked {
  animation: none;
  box-shadow: var(--glow-gold);
}
.is-tizen .answer.is-locked::after {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 calc(var(--u) * 2.6) rgba(243, 200, 96, .5);
  animation: tvGlowPulse 1.05s var(--ease-in-out) infinite;
  pointer-events: none;
}
/* The welcome call to action pulsed its glow from nothing to full. Pulsing the
   button's own opacity would fade the label with it, so the glow stays lit and
   only the scale breathes - the same invitation, composited. */
@keyframes tvOkPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.035); }
}
.is-tizen .pressOk {
  animation: tvOkPulse 2.4s var(--ease-in-out) infinite;
  box-shadow: var(--glow-gold);
}

/* The urgent timer scales a filtered SVG, re-applying the drop-shadow each
   frame. The ring still turns and still pulses; it just stops re-filtering. */
.is-tizen .timer.is-urgent .timer__bar { filter: none; }

/* ---- focus feedback: keep the look, drop the paint animation ---- */
/* Focusing transitioned a three-layer box-shadow and a gradient background over
   260 ms, on both the incoming and the outgoing control - roughly a fifth of
   the screen repainted per frame, on every arrow press. The focused state is
   identical; it simply arrives at once instead of fading in. */
.is-tizen .btn,
.is-tizen .tile,
.is-tizen .answer,
.is-tizen .kbd__key,
.is-tizen .lifeline,
.is-tizen .playerCard,
.is-tizen .setting,
.is-tizen .navbtn,
.is-tizen .answer__letter {
  transition: transform 140ms var(--ease-out);
}

/* `all` across fifteen ladder rungs makes the engine diff every animatable
   property on all of them whenever the current rung moves. */
.is-tizen .rung {
  transition: background 220ms var(--ease-out), color 220ms var(--ease-out);
}

/* The conic-gradient rim sweep needs @property (Chromium 85) to interpolate, so
   on M76 it cannot animate at all - it only costs a masked extra layer. */
.is-tizen .tile.is-focused::after { animation: none; }

/* The heartbeat pulsed the opacity of the whole beam container - a full-screen
   group, re-composited every frame. The moment is carried by the answer's own
   pulse and by the music. */
.is-tizen .stage.is-pulsing .stage__beams { animation: none; }
