/* V236 FX2 | cinematic layer 2: scroll-driven effects, CSS only. The page-to-page morph script is a separate file.
   Opt in per element:  data-fx2="rise wipe redact stamp scan count stagger depth"
   Contract: each effect starts from a hidden or offset pose and ends on the element's own natural style.
   Without support, with prefers-reduced-motion, in html.v215-lite, or under [data-fx2-off], the finished page is shown.
   Only transform-family properties, opacity and clip-path are animated (plus one integer variable for count).
   Uses data-fx2 / data-fx2-depth / data-stamp / --fx2-* only, so it can sit next to the data-fx layer of v234-fx.js.
   Do not combine two effects that use the same pseudo-element on one node:
   redact uses ::before and ::after, scan uses ::before, stamp uses ::after.
   Every animated pose stays inside its host on the right and bottom edge of the page flow, so no effect can widen the page (checked on a 390px layout).
   stamp: the host needs about 18px of top padding (or set --fx2-stamp-top on it), because the lower half of the stamp sits inside the host. */

:root{--fx2-ink:#2b4152;--fx2-edge:#dfbe85;--fx2-stamp:#e5bf82;--fx2-ease:cubic-bezier(.22,.7,.2,1);--fx2-inset:56px}

/* ---- stamp: the finished pose is plain CSS, so it also shows without motion ---- */
:where([data-fx2~=stamp]){position:relative}
[data-fx2~=stamp]::after{content:attr(data-stamp)/"";position:absolute;z-index:2;top:var(--fx2-stamp-top,-16px);inset-inline-end:16px;width:max-content;max-width:72%;
  padding:5px 11px 5px 14px;border:2px solid var(--fx2-stamp);border-radius:5px;outline:1px solid var(--fx2-stamp);outline-offset:-5px;
  background:rgb(7 16 25/.9);color:var(--fx2-stamp);font:700 13px/1.35 "Noto Sans TC",system-ui,-apple-system,sans-serif;letter-spacing:.3em;
  white-space:nowrap;overflow:hidden;text-overflow:clip;transform-origin:right center;rotate:6deg;opacity:.94;pointer-events:none}

@supports (animation-timeline:view()){
@media screen and (prefers-reduced-motion:no-preference){

@property --fx2-n{syntax:"<integer>";inherits:false;initial-value:0}

@keyframes fx2-rise{from{opacity:0;translate:0 20px}}
@keyframes fx2-wipe{from{clip-path:inset(0 calc(50% + 50%) 0 0)}to{clip-path:inset(0 0 0 0)}}
@keyframes fx2-bar{from{scale:1 1}to{scale:0 1}}
@keyframes fx2-edge{from{opacity:0;translate:calc(-50% - 50%) 0}8%{opacity:1}92%{opacity:1}to{opacity:0;translate:0 0}}
@keyframes fx2-stamp{
  from{opacity:0;scale:2.1;rotate:20deg;translate:0 -14px;animation-timing-function:cubic-bezier(.55,0,.85,.35)}
  56%{opacity:.98;scale:.93;rotate:5.4deg;translate:0 2px;animation-timing-function:cubic-bezier(.3,.9,.4,1)}
  78%{scale:1.035;rotate:6.4deg;translate:0 -1px;animation-timing-function:ease-out}
  to{opacity:.94;scale:1;rotate:6deg;translate:0 0}}
@keyframes fx2-scan{from{opacity:0;translate:0 0}14%{opacity:1}80%{opacity:1}to{opacity:0;translate:285% 0}}
@keyframes fx2-n{from{--fx2-n:0}to{--fx2-n:var(--fx2-to,0)}}
@keyframes fx2-ghost{0%,94%{-webkit-text-fill-color:transparent}}
@keyframes fx2-ov{from{opacity:1}94%{opacity:1}to{opacity:0}}
@keyframes fx2-depth{to{translate:0 var(--fx2-dy,0px)}}

/* every opted-in node owns a named view timeline; its pseudo-elements and the stagger children read it */
[data-fx2]{view-timeline:--fx2-v block 0px var(--fx2-inset)}
:where([data-fx2~=redact],[data-fx2~=scan],[data-fx2~=count]){position:relative;isolation:isolate}
:where([data-fx2~=count]){display:inline-block}

/* 1 rise */
[data-fx2~=rise]{animation:fx2-rise var(--fx2-ease) backwards;animation-timeline:--fx2-v;animation-range:entry 0% entry min(60%,240px)}

/* 2 wipe: clip-path is only applied before and during the reveal, never afterwards (shadows and focus rings stay intact) */
[data-fx2~=wipe]{animation:fx2-wipe var(--fx2-ease) backwards;animation-timeline:--fx2-v;animation-range:entry 0% entry min(80%,300px)}

/* 3 redact: per-line bars with ragged lengths shrink to the right; a gold hairline rides the leading edge */
[data-fx2~=redact]::before,[data-fx2~=redact]::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none}
[data-fx2~=redact]::before{--g:calc(1lh*.14);transform-origin:right center;scale:0 1;
  background:
    linear-gradient(transparent var(--g),var(--fx2-ink) var(--g) calc(1lh - var(--g)),transparent calc(1lh - var(--g))) 0 0/auto 3lh repeat-y,
    linear-gradient(transparent calc(1lh + var(--g)),var(--fx2-ink) calc(1lh + var(--g)) calc(2lh - var(--g)),transparent calc(2lh - var(--g))) 0 0/93% 3lh repeat-y,
    linear-gradient(transparent calc(2lh + var(--g)),var(--fx2-ink) calc(2lh + var(--g)) calc(3lh - var(--g)),transparent calc(3lh - var(--g))) 0 0/97% 3lh repeat-y;
  animation:fx2-bar var(--fx2-ease) backwards;animation-timeline:--fx2-v;animation-range:entry 0% entry min(85%,320px)}
[data-fx2~=redact]::after{opacity:0;border-right:2px solid var(--fx2-edge);background:linear-gradient(to left,rgb(223 190 133/.2),transparent 42px);
  animation:fx2-edge var(--fx2-ease) backwards;animation-timeline:--fx2-v;animation-range:entry 0% entry min(85%,320px)}

/* 4 stamp: only the entrance is animated here */
[data-fx2~=stamp]::after{animation:fx2-stamp backwards;animation-timeline:--fx2-v;animation-range:entry min(30%,90px) entry min(95%,230px)}

/* 5 scan */
[data-fx2~=scan]::before{content:"";position:absolute;z-index:1;top:0;bottom:0;left:0;width:26%;opacity:0;pointer-events:none;
  background:linear-gradient(90deg,transparent,rgb(150 216 220/.1) 30%,rgb(223 190 133/.26) 52%,rgb(150 216 220/.1) 72%,transparent);
  animation:fx2-scan linear backwards;animation-timeline:--fx2-v;animation-range:entry 0% entry min(calc(50% + 50%),440px)}

/* 7 count: the real number stays in the text; a decorative counter overlays it while the range plays */
[data-fx2~=count]{counter-reset:fx2n var(--fx2-n);animation:fx2-n linear backwards,fx2-ghost linear backwards;animation-timeline:--fx2-v;animation-range:entry 0% entry min(90%,300px)}
[data-fx2~=count]::after{content:counter(fx2n)/"";position:absolute;inset:0;padding:inherit;opacity:0;pointer-events:none;-webkit-text-fill-color:currentcolor;
  animation:fx2-ov linear backwards;animation-timeline:--fx2-v;animation-range:entry 0% entry min(90%,300px)}

/* 8 stagger: the first 12 children enter one after another (index --i, pre-written); later children are left alone, so a long list costs nothing extra */
[data-fx2~=stagger]>:nth-child(-n+12){animation:fx2-rise var(--fx2-ease) backwards;animation-timeline:view(block 0px var(--fx2-inset));
  animation-range:entry calc(var(--i,0)*4%) entry min(calc(50% + var(--i,0)*4%),calc(200px + var(--i,0)*8px))}
[data-fx2~=stagger]>:nth-child(2){--i:1}[data-fx2~=stagger]>:nth-child(3){--i:2}[data-fx2~=stagger]>:nth-child(4){--i:3}
[data-fx2~=stagger]>:nth-child(5){--i:4}[data-fx2~=stagger]>:nth-child(6){--i:5}[data-fx2~=stagger]>:nth-child(7){--i:6}
[data-fx2~=stagger]>:nth-child(8){--i:7}[data-fx2~=stagger]>:nth-child(9){--i:8}[data-fx2~=stagger]>:nth-child(10){--i:9}
[data-fx2~=stagger]>:nth-child(11){--i:10}[data-fx2~=stagger]>:nth-child(12){--i:11}

/* 6 depth: layers drift at different speeds while the root scrolls (layer 1 far, 3 near) */
[data-fx2~=depth] [data-fx2-depth]{will-change:transform;animation:fx2-depth linear both;animation-timeline:scroll(root block);animation-range:0px 70vh}
[data-fx2~=depth] [data-fx2-depth="1"]{--fx2-dy:18vh}
[data-fx2~=depth] [data-fx2-depth="2"]{--fx2-dy:9vh}
[data-fx2~=depth] [data-fx2-depth="3"]{--fx2-dy:-7vh}

/* off switches: lite mode and [data-fx2-off] (on html, on a subtree, or on the node) restore the natural pose */
:root.v215-lite [data-fx2],:root.v215-lite [data-fx2]::before,:root.v215-lite [data-fx2]::after,:root.v215-lite [data-fx2]>*,:root.v215-lite [data-fx2-depth],
[data-fx2-off],[data-fx2-off]::before,[data-fx2-off]::after,[data-fx2-off][data-fx2]>*,
[data-fx2-off] [data-fx2],[data-fx2-off] [data-fx2]::before,[data-fx2-off] [data-fx2]::after,[data-fx2-off] [data-fx2]>*,[data-fx2-off] [data-fx2-depth]{animation:none!important;will-change:auto!important}
}}

/* ---- shared-element morph (needs v236-fx2.js on both pages; the pages must opt in with @view-transition) ---- */
@supports (view-transition-name:x){
@media (prefers-reduced-motion:no-preference){
@keyframes fx2-vo{to{opacity:0}}
@keyframes fx2-vi{from{opacity:0}}
::view-transition-group(fx2-morph){animation-duration:.46s;animation-timing-function:cubic-bezier(.2,.8,.2,1)}
::view-transition-old(fx2-morph),::view-transition-new(fx2-morph){height:calc(50% + 50%);object-fit:none;object-position:left top;overflow:clip}
::view-transition-old(fx2-morph){animation:fx2-vo .18s ease-in both}
::view-transition-new(fx2-morph){animation:fx2-vi .22s ease-out .1s both}
::view-transition-old(fx2-morph):only-child{animation:fx2-vo .14s linear both}
::view-transition-new(fx2-morph):only-child{animation:fx2-vi .14s linear both}
}}
