/* assets/css/fx.css - the look of the FX pack (scripts: assets/js/fx/, spec:
   test/fx.test.mjs). Load it after site.css. Every bit of motion sits inside
   @media (prefers-reduced-motion: no-preference), so with reduce nothing here
   moves; only transform, opacity, clip-path and mask animate. The overlays
   the scripts add are aria-hidden, never take input, and are removed when
   done; nothing covers text at rest. */
@property --fx-fl-r{syntax:"<length>";inherits:true;initial-value:0px}

/* Overlays made by the scripts. */
.fx-ripple,.fx-sky,.fx-confetti{position:fixed;left:0;top:0;pointer-events:none}
.fx-ripple{z-index:60;width:56px;height:56px;margin:-28px 0 0 -28px;border:3px solid #ff5d8f;border-radius:50%;opacity:0}
.fx-confetti{z-index:60;width:100%;height:100%}
.fx-sugar{position:absolute;inset:0;z-index:-1;width:100%;height:100%;pointer-events:none}
/* The holo sheen: clipped to the logo picture's own shape (its mask), blended
   by colour so the logo keeps its lightness, and so its contrast. */
.fx-holo{position:absolute;left:0;top:0;overflow:hidden;pointer-events:none;opacity:0;mix-blend-mode:color;-webkit-mask:var(--fx-holo-m) 0 0/100% 100% no-repeat;mask:var(--fx-holo-m) 0 0/100% 100% no-repeat}
.fx-holo>i{position:absolute;left:-50%;top:50%;width:200%;aspect-ratio:1;translate:0 -50%;background:conic-gradient(#ff8fb1,#ffd36e,#8ef0c1,#7cc8ff,#c9a2ff,#ff8fb1)}
/* The little sky over the sun/moon switch. */
.fx-sky{z-index:40;width:120px;height:84px;margin:-42px 0 0 -60px;view-transition-name:fx-sky;-webkit-mask:linear-gradient(#000 58%,transparent 82%);mask:linear-gradient(#000 58%,transparent 82%)}
.fx-sky i{position:absolute;border-radius:50%}
.fx-sun{left:50px;top:32px;width:20px;height:20px;background:#f6a623;box-shadow:0 0 14px 4px rgba(246,166,35,.5)}
.fx-moon{left:51px;top:33px;width:18px;height:18px;box-shadow:inset -6px -3px 0 0 #fbeee4}
.fx-stars{left:59px;top:41px;width:2px;height:2px;background:#fff8f2;box-shadow:-46px -24px #fff8f2,-30px 6px #fff8f2,-16px -32px #fff8f2,22px -30px #fff8f2,38px -8px #fff8f2,50px 12px #fff8f2,-52px 10px #fff8f2}
/* Story snaps (the /oakland page): full-screen scenes. Set --story-top on
   .story to the sticky header's height if the page keeps one. */
.story-scene{min-height:calc(100vh - var(--story-top,0px));min-height:calc(100svh - var(--story-top,0px));display:grid;align-content:center;scroll-margin-top:var(--story-top,0px)}

@media (prefers-reduced-motion: no-preference){
  /* Page to page. Every arrival is a sprinkle circle (from the centre)
     with no script; transitions.js retypes /menu and /groups and adds the
     tap point and the burst. */
  @view-transition{navigation:auto;types:fx-sprinkle}
  html:active-view-transition-type(fx-glaze,fx-lid,fx-sprinkle)::view-transition-old(root),html:active-view-transition-type(fx-glaze,fx-lid,fx-sprinkle)::view-transition-new(root){mix-blend-mode:normal}
  /* Menu: pink glaze pours down over the old page, drips first, then drains
     away to show the menu. */
  html:active-view-transition-type(fx-glaze)::view-transition-image-pair(root){background:linear-gradient(#ff8fb1,#ff5d8f 35%,#e8457c)}
  html:active-view-transition-type(fx-glaze)::view-transition-old(root){animation:fx-pour 640ms cubic-bezier(.55,.05,.45,.95) both}
  html:active-view-transition-type(fx-glaze)::view-transition-new(root){animation:fx-drain 640ms cubic-bezier(.55,.05,.45,.95) both}
  @keyframes fx-pour{0%{clip-path:polygon(0 -7%,3.8% -7%,5.1% -4.7%,6.3% -4%,7.7% -4%,8.9% -4.7%,10.2% -7%,19.6% -7%,20.6% -3.1%,21.5% -2%,22.5% -2%,23.4% -3.1%,24.4% -7%,33.4% -7%,34.8% -5.4%,36.2% -5%,37.8% -5%,39.2% -5.4%,40.6% -7%,50.2% -7%,51.3% -2.3%,52.4% -1%,53.6% -1%,54.7% -2.3%,55.8% -7%,67.6% -7%,68.6% -4.7%,69.5% -4%,70.5% -4%,71.4% -4.7%,72.4% -7%,83.6% -7%,85% -3.9%,86.3% -3%,87.7% -3%,89% -3.9%,90.4% -7%,100% -7%,100% 100%,0 100%)}55%,100%{clip-path:polygon(0 101%,3.8% 101%,5.1% 108.8%,6.3% 111%,7.7% 111%,8.9% 108.8%,10.2% 101%,19.6% 101%,20.6% 114.3%,21.5% 118%,22.5% 118%,23.4% 114.3%,24.4% 101%,33.4% 101%,34.8% 107.2%,36.2% 109%,37.8% 109%,39.2% 107.2%,40.6% 101%,50.2% 101%,51.3% 115.8%,52.4% 120%,53.6% 120%,54.7% 115.8%,55.8% 101%,67.6% 101%,68.6% 110.4%,69.5% 113%,70.5% 113%,71.4% 110.4%,72.4% 101%,83.6% 101%,85% 112.7%,86.3% 116%,87.7% 116%,89% 112.7%,90.4% 101%,100% 101%,100% 100%,0 100%)}}
  @keyframes fx-drain{0%,45%{clip-path:polygon(0 0,100% 0,100% -3%,87.5% -1.4%,75% -4.2%,62.5% -1.6%,50% -4.6%,37.5% -1.9%,25% -4.3%,12.5% -1.5%,0 -3%)}100%{clip-path:polygon(0 0,100% 0,100% 103%,87.5% 104.6%,75% 101.8%,62.5% 104.4%,50% 101.4%,37.5% 104.1%,25% 101.7%,12.5% 104.5%,0 103%)}}
  /* Groups: the old page tilts shut like a pink box lid, the new one swings
     open. */
  html:active-view-transition-type(fx-lid)::view-transition-image-pair(root){background:radial-gradient(ellipse 30% 11% at 50% 46%,#ffdbe7 96%,transparent),linear-gradient(#ff7aa3,#ff5d8f 60%,#e8457c)}
  html:active-view-transition-type(fx-lid)::view-transition-old(root){transform-origin:50% 100%;animation:fx-shut 600ms cubic-bezier(.5,0,.75,0) both}
  html:active-view-transition-type(fx-lid)::view-transition-new(root){transform-origin:50% 0;animation:fx-open 600ms cubic-bezier(.25,1,.5,1) both}
  @keyframes fx-shut{0%{transform:perspective(1100px) rotateX(0)}48%,100%{transform:perspective(1100px) rotateX(86deg);opacity:.25}}
  @keyframes fx-open{0%,42%{transform:perspective(1100px) rotateX(-86deg);opacity:.25}100%{transform:perspective(1100px) rotateX(0)}}
  /* Everything else: the new page grows in a circle from the tapped point
     (the night switch uses the same circle from its button). */
  html:active-view-transition-type(fx-sprinkle)::view-transition-old(root){animation:none}
  html:active-view-transition-type(fx-sprinkle)::view-transition-new(root){animation:fx-circle 520ms cubic-bezier(.4,0,.2,1) both}
  @keyframes fx-circle{from{clip-path:circle(0 at var(--fx-x,50%) var(--fx-y,50%))}to{clip-path:circle(var(--fx-r,150vmax) at var(--fx-x,50%) var(--fx-y,50%))}}
  /* ...with a short sprinkle burst from the tap, drawn on the arriving page
     for as long as the transition runs. */
  html:active-view-transition-type(fx-burst) body::before,html:active-view-transition-type(fx-burst) body::after{content:"";position:fixed;left:var(--fx-x);top:var(--fx-y);z-index:2147483000;width:14px;height:5px;margin:-2.5px 0 0 -7px;border-radius:3px;pointer-events:none;animation:fx-burst 520ms cubic-bezier(.2,.8,.3,1) both}
  html:active-view-transition-type(fx-burst) body::before{background:#ff5d8f;box-shadow:58px -14px #f6a623,-52px -30px #4fb3f0,20px 56px #3cc68a,-34px 44px #a77bf3,70px 30px #c7295f,-66px 8px #f6a623,8px -64px #3cc68a,-12px 70px #ff5d8f,90px -46px #4fb3f0}
  html:active-view-transition-type(fx-burst) body::after{background:#3cc68a;rotate:62deg;box-shadow:54px -20px #ff5d8f,-48px -26px #a77bf3,26px 52px #f6a623,-40px 38px #4fb3f0,64px 26px #ff5d8f,-60px 14px #c7295f,-84px -40px #f6a623,40px -70px #a77bf3,-20px -80px #3cc68a}
  @keyframes fx-burst{from{transform:scale(.15);opacity:1}70%{opacity:1}to{transform:scale(1.4);opacity:0}}
  /* The sun/moon switch (night-switch.js): night spreads from the button,
     day comes back reversed. */
  html:is(.fx-to-night,.fx-to-day)::view-transition-old(root),html:is(.fx-to-night,.fx-to-day)::view-transition-new(root){mix-blend-mode:normal}
  html.fx-to-night::view-transition-old(root),html.fx-to-day::view-transition-new(root){animation:none}
  html.fx-to-night::view-transition-new(root){animation:fx-circle 640ms cubic-bezier(.4,0,.2,1) both}
  html.fx-to-day::view-transition-old(root){z-index:1;animation:fx-circle 640ms cubic-bezier(.4,0,.2,1) reverse both}
  ::view-transition-new(fx-sky){animation:none}
  .fx-sky{animation:fx-sky 1600ms linear both}
  .fx-sun,.fx-day .fx-moon{animation:fx-set 700ms cubic-bezier(.5,0,.75,.3) both}
  .fx-moon,.fx-day .fx-sun{animation:fx-rise 800ms 250ms cubic-bezier(.2,.8,.2,1) both}
  .fx-stars{animation:fx-twinkle 900ms 350ms ease-out both}
  .fx-day .fx-stars{animation:fx-twinkle 500ms ease-in reverse both}
  .fx-dim>svg{animation:fx-dim 1600ms linear both}
  @keyframes fx-sky{0%,78%{opacity:1}100%{opacity:0}}
  @keyframes fx-set{to{transform:translateY(34px);opacity:0}}
  @keyframes fx-rise{from{transform:translateY(34px);opacity:0}}
  @keyframes fx-twinkle{from{transform:scale(.4);opacity:0}}
  @keyframes fx-dim{0%,8%{opacity:1}14%,80%{opacity:0}100%{opacity:1}}
  /* The OPEN 24 HOURS neon flickers on: 2 flashes in the first second (WCAG
     2.3.1 allows 3), never below 45% (a low-contrast flicker), then steady. */
  .fx-flicker{animation:fx-flicker 1500ms linear both}
  @keyframes fx-flicker{0%{opacity:.45}7%{opacity:1}14%{opacity:.6}24%{opacity:1}46%{opacity:.75}58%,100%{opacity:1}}
  /* Touch (touch.js). */
  .fx-ripple{animation:fx-ripple 450ms cubic-bezier(.2,.8,.2,1) both}
  @keyframes fx-ripple{from{scale:.2;opacity:.9}to{scale:1;opacity:0}}
  .fx-mag{transition:transform var(--dur-ui,200ms) var(--ease-out,ease-out),translate 160ms ease-out}
  .fx-mag.fx-mag-back{transition:transform var(--dur-ui,200ms) var(--ease-out,ease-out),translate 420ms var(--ease-back,cubic-bezier(.34,1.56,.64,1))}
  .fx-fl{-webkit-mask:radial-gradient(circle var(--fx-fl-r) at var(--fx-fl-x,50%) var(--fx-fl-y,50%),#000 45%,rgba(0,0,0,.55));mask:radial-gradient(circle var(--fx-fl-r) at var(--fx-fl-x,50%) var(--fx-fl-y,50%),#000 45%,rgba(0,0,0,.55));transition:--fx-fl-r 350ms ease-out}
  .fx-fl-on{--fx-fl-r:var(--fx-fl-w,150px)}
  .fx-holo{transition:opacity 300ms ease-out}
  .fx-holo-on>.fx-holo{opacity:.9}
  /* Story snaps: scenes snap into place (proximity: never a trap). Their
     words rise in with site.css's own scroll-driven motion. */
  html:has(.story){scroll-snap-type:y proximity}
  .story-scene{scroll-snap-align:start}
}
