/* ============================================================================
   emily-idle.css — the only new CSS in the idle feature.

   EVERY SELECTOR IN THIS FILE IS GATED ON [data-idle] ON .emily, and
   `data-idle` is set by emily-idle.js and by nothing else. So removing the
   <script> tag alone already makes this entire file inert; removing the
   <link> as well only removes the bytes. That is rollback level 2.

   emily.css is byte-identical to what shipped. Nothing here overrides it —
   .emily__idle is a class that does not exist in emily.css, and every rule is
   further scoped by an attribute emily.css never sets.
   ---------------------------------------------------------------------------- */

.emily[data-idle] {
  /* --------------------------------------------------------------- tuning --
     Three durations, all resolving to existing tbg.css tokens. Retuning the
     feel of the feature is a change to these three lines and nothing else —
     no JavaScript edit, no re-render, no redeploy of assets. emily-idle.js
     reads these back with getComputedStyle, so the CSS is the source of truth
     for timing, not a duplicated constant in the script. */

  /* idle clip -> idle clip. P2b §2.1 set 320ms as the default and pre-
     authorised var(--dur-slow) "if P2a's per-clip seam numbers come back
     materially above the P1 P95 target for a substantial share of the
     library". They did: 12 of 12 clips exceed both the P95 and the 0.60
     absolute guard, mean seam 1.491 against a 0.60 bar (P2a §c). So this
     ships at the long token, which is the retune P2b already sanctioned for
     exactly this measurement — not a new number invented here. */
  --emily-idle-fade: var(--dur-slow);   /* 560ms */

  /* idle -> speaking. Short by design: this is a swap between two moving
     representations of the same face, and anything past ~160ms reads as a
     fade rather than a handover. P2b §3.1. */
  --emily-idle-out:  var(--dur-fast);   /* 120ms */

  /* speaking -> idle. P2b §3.2 made this conditional on P2a's measurement of
     the speaking-clip-end to idle-frame-0 MAD: 320ms if it came back "under,
     say, 0.6", 560ms if loose. Measured 1.296 whole-frame / 4.57 head-region
     (P2a §d). Loose. So 560ms. */
  --emily-idle-in:   var(--dur-slow);   /* 560ms */
}

/* --- geometry -----------------------------------------------------------
   DUPLICATED, DELIBERATELY, from emily.css:457-467. The idle layers must
   register pixel-for-pixel with the shipped speaking video or the cross-fade
   between them reads as a jump cut. They cannot simply be given the
   .emily__video class to inherit it, because emily.css:120 hides
   .emily__video under [data-video="off"] — which is the text-only state where
   idle is most wanted.

   THIS IS A REAL COUPLING. If anyone changes the hood geometry in emily.css,
   this block must change in the same commit. P1 §c.8.2, P2b §8.               */
.emily[data-idle] .emily__idle {
  position: absolute;
  top: 0; left: 50%;
  width: 150%;
  height: auto;
  min-height: 100%;
  transform: translateX(-50%);
  object-fit: cover;
  object-position: 50% 0;

  opacity: 0;
  pointer-events: none;          /* decoration: participates in nothing */
  background: transparent;       /* never paint a black box before frame 1 */

  /* LINEAR, non-negotiable. Both layers are the same face at close-to-neutral
     pose; an eased pair puts a luminance dip at the midpoint because both
     spend the middle of the fade below 50% opacity. P1 §c.4, P2b §2.2. */
  transition: opacity var(--emily-idle-fade) linear;
}

/* Fade kind. Set by emily-idle.js on the .emily root so all three durations
   stay retunable from CSS alone. */
.emily[data-idle][data-idle-fade="in"]  .emily__idle { transition-duration: var(--emily-idle-in); }
.emily[data-idle][data-idle-fade="out"] .emily__idle { transition-duration: var(--emily-idle-out); }

/* --- states -------------------------------------------------------------
   `yield` and `paused` are belt-and-braces: the script already drives opacity
   inline, and these make the intent declarative and inspectable. Show/hide is
   ALWAYS opacity, never display — dropping display would tear down the decode
   pipeline and cost a re-init on every handover. P1 §c.1, P2b §13.7.         */
.emily[data-idle="loading"] .emily__idle,
.emily[data-idle="yield"]   .emily__idle,
.emily[data-idle="paused"]  .emily__idle { opacity: 0; }

/* --- accessibility ------------------------------------------------------
   emily-idle.js never creates a layer at all when prefers-reduced-motion
   matches at boot, and tears down if it becomes true mid-session, so this
   block should be unreachable. It exists because an unreachable safety net
   costs two lines and a reachable one costs a complaint.                     */
@media (prefers-reduced-motion: reduce) {
  .emily[data-idle] .emily__idle { opacity: 0 !important; transition: none !important; }
}
