/* cyki-fx.css v1 - shared opt-in page effects (billboard, 2026-10-09; spec: docs/screens/effects-review/effects-review-2026-10-09.html).
   Opt-in by attribute: data-fx="reveal | split | draw | roll". A page that sets none of them is unchanged.
   The market hub (market*.js/css, GSAP) is NOT touched and never loads this pair.

   Safety rules, in the order they matter:
   1. NOTHING is hidden unless cyki-fx.js has added html.fxjs. No JS, a failed load, reduced motion or no
      IntersectionObserver = no class = the server HTML is the finished page.
   2. prefers-reduced-motion and print show the final state (belt and braces on top of rule 1).
   3. Only opacity / transform / clip-path animate. Nothing changes a box size, so nothing shifts layout.
   4. Tokens only (no colour literals live in this file). Orange is never touched. */

/* ---- reveal: fade + 14px rise ---- */
html.fxjs [data-fx="reveal"]:not(.fx-in){opacity:0;transform:translateY(14px)}
html.fxjs [data-fx="reveal"]{transition:opacity .5s ease,transform .5s ease;transition-delay:var(--fx-d,0ms)}
/* children of a data-fx-each container enter one after another (the container itself never hides) */
html.fxjs [data-fx-each]:not(.fx-in)>*{opacity:0;transform:translateY(14px)}
html.fxjs [data-fx-each]>*{transition:opacity .5s ease,transform .5s ease;transition-delay:calc(var(--fx-i,0)*80ms)}
/* keyboard focus inside a hidden block must still show it */
html.fxjs [data-fx="reveal"]:focus-within,html.fxjs [data-fx-each]>*:focus-within{opacity:1;transform:none}

/* ---- split: word mask-rise (transform only; the line box never reflows) ---- */
html.fxjs [data-fx="split"]:not(.fx-split){visibility:hidden}
.fx-w{display:inline-block;overflow:hidden;vertical-align:top;padding:.08em 0 .14em;margin:-.08em 0 -.14em}
.fx-c{display:inline-block}
html.fxjs [data-fx="split"].fx-split:not(.fx-in) .fx-c{transform:translateY(115%)}
html.fxjs [data-fx="split"].fx-split .fx-c{transition:transform .75s cubic-bezier(.16,1,.3,1);transition-delay:calc(var(--fx-i,0)*70ms)}

/* ---- draw: the server-drawn series wipes in left to right (the hub chart's 1.2s out-cubic) ----
   The renderer wraps the series in <g data-fx-clip> and the end-point markers in <g data-fx-after>.
   Axis labels, frame chips and every printed number stay visible from the first frame. */
html.fxjs [data-fx="draw"]:not(.fx-in) [data-fx-clip]{clip-path:inset(-4px 100% -4px -4px)}
/* The drawn state must be an explicit shape: clip-path "none" is not interpolable with inset(), so a bare :not(.fx-in) rule made the wipe SNAP
   open on entry instead of animating (found 2026-10-09, round 2). The 4px bleed keeps the stroke caps and end dot unclipped. */
html.fxjs [data-fx="draw"].fx-in [data-fx-clip]{clip-path:inset(-4px -4px -4px -4px)}
html.fxjs [data-fx="draw"] [data-fx-clip]{transition:clip-path 1.2s cubic-bezier(.33,1,.68,1);transition-delay:var(--fx-d,0ms)}
html.fxjs [data-fx="draw"]:not(.fx-in) [data-fx-after]{opacity:0}
html.fxjs [data-fx="draw"] [data-fx-after]{transition:opacity .35s ease;transition-delay:calc(var(--fx-d,0ms) + 1000ms)}

/* ---- roll: one single-lock digit roll. Built at run time from the element's own text, then put back. ---- */
html.fxjs [data-fx="roll"]:not(.fx-in):not(.fx-done){visibility:hidden}
.fx-rolling{position:relative}
.fx-rolling .fx-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.fx-drum{display:inline-block;height:1em;line-height:1;overflow:hidden;vertical-align:top;font-variant-numeric:tabular-nums}
.fx-strip{display:block;transition:transform 1.3s cubic-bezier(.25,1,.5,1);will-change:transform}
.fx-strip i{display:block;font-style:normal;height:1em;line-height:1}
.fx-ch{display:inline-block;height:1em;line-height:1;vertical-align:top;white-space:pre}

@media (prefers-reduced-motion:reduce){
  html.fxjs [data-fx="reveal"],html.fxjs [data-fx-each]>*{opacity:1!important;transform:none!important;transition:none!important}
  html.fxjs [data-fx="split"]{visibility:visible!important}
  html.fxjs [data-fx="split"] .fx-c{transform:none!important;transition:none!important}
  html.fxjs [data-fx="draw"] [data-fx-clip]{clip-path:none!important;transition:none!important}
  html.fxjs [data-fx="draw"] [data-fx-after]{opacity:1!important;transition:none!important}
  html.fxjs [data-fx="roll"]{visibility:visible!important}
  .fx-strip{transition:none!important}
}
@media print{
  [data-fx="reveal"],[data-fx-each]>*{opacity:1!important;transform:none!important;transition:none!important}
  [data-fx="split"]{visibility:visible!important}
  [data-fx="split"] .fx-c{transform:none!important;transition:none!important}
  [data-fx="draw"] [data-fx-clip]{clip-path:none!important;transition:none!important}
  [data-fx="draw"] [data-fx-after]{opacity:1!important;transition:none!important}
  [data-fx="roll"]{visibility:visible!important}
}