/* ============================================================
   reveal-fx.css
   1. Theme switch animations (eclipse to dark, blinds to light)
   2. Reveal scene: red storm, rain, embers, lightning, artwork
   Zero em dashes. Does not touch the Thing companion styles.
   ============================================================ */

/* ---------- 1. THEME SWITCH ---------- */

@property --fx-r {
  syntax: '<length>';
  inherits: false;
  initial-value: 0px;
}

@property --fx-p {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

html.fx-to-dark::view-transition-old(root),
html.fx-to-dark::view-transition-new(root),
html.fx-to-light::view-transition-old(root),
html.fx-to-light::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

/* Light to dark: dark spreads from the toggle with a soft edge, old page dims */
html.fx-to-dark::view-transition-old(root) {
  z-index: 1;
  animation: fx-dim 950ms ease-in both;
}

html.fx-to-dark::view-transition-new(root) {
  z-index: 2;
  -webkit-mask-image: radial-gradient(circle at var(--fx-x) var(--fx-y), #000 calc(var(--fx-r) - 64px), transparent var(--fx-r));
  mask-image: radial-gradient(circle at var(--fx-x) var(--fx-y), #000 calc(var(--fx-r) - 64px), transparent var(--fx-r));
  animation: fx-eclipse 950ms cubic-bezier(0.5, 0, 0.2, 1) both;
}

@keyframes fx-eclipse {
  from { --fx-r: 0px; }
  to { --fx-r: var(--fx-max); }
}

@keyframes fx-dim {
  to { filter: brightness(0.55); }
}

/* Dark to light: horizontal blinds open from the top down */
html.fx-to-light::view-transition-old(root) {
  z-index: 1;
}

html.fx-to-light::view-transition-new(root) {
  z-index: 2;
  -webkit-mask-image: linear-gradient(to bottom, #000 var(--fx-p), transparent var(--fx-p));
  mask-image: linear-gradient(to bottom, #000 var(--fx-p), transparent var(--fx-p));
  -webkit-mask-size: 100% 12.5vh;
  mask-size: 100% 12.5vh;
  -webkit-mask-repeat: repeat-y;
  mask-repeat: repeat-y;
  animation: fx-blinds 760ms cubic-bezier(0.4, 0, 0.2, 1) both;
}

@keyframes fx-blinds {
  from { --fx-p: 0%; }
  to { --fx-p: 101%; }
}

/* Toggle icon snaps in after the swap */
#theme-toggle-btn.fx-spin svg {
  animation: fx-icon 620ms cubic-bezier(0.3, 1.3, 0.5, 1) both;
}

@keyframes fx-icon {
  from { transform: rotate(-140deg) scale(0.3); opacity: 0; }
  to { transform: rotate(0deg) scale(1); opacity: 1; }
}

/* ---------- 2. REVEAL SCENE ---------- */

html.fx-storm-active, body.fx-storm-active {
  overflow: hidden !important;
}

.fx-storm {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  min-height: -webkit-fill-available;
  z-index: 10000;
  pointer-events: none;
  overflow: hidden;
  opacity: 1;
  transition: opacity 800ms ease;
}

.fx-storm.fx-fading {
  opacity: 0;
}

/* Deep blood-dark nocturnal sky, fully opaque so the page below is completely concealed during the storm */
.fx-veil {
  position: absolute;
  inset: 0;
  opacity: 1;
  background-color: #050102;
  background:
    radial-gradient(120% 70% at 30% 0%, #5a0d12 0%, rgba(90, 13, 18, 0) 70%),
    linear-gradient(to bottom, #2a0508 0%, #120304 45%, #050102 100%);
  transition: filter 110ms linear;
}

.fx-storm.is-lit .fx-veil {
  filter: brightness(2.4);
}

/* Clouds roll in from off screen left and sit behind the figure */
.fx-clouds {
  position: absolute;
  top: 0;
  left: -5vw;
  width: 110vw;
  height: 46vh;
  transform: translateX(-40%);
  transition: transform 1600ms cubic-bezier(0.15, 0.7, 0.2, 1), filter 90ms linear;
}

.fx-storm.on .fx-clouds {
  transform: translateX(0);
}

.fx-storm.is-lit .fx-clouds {
  filter: brightness(2.6);
}

.fx-c-back { animation: fx-drift 9s linear both; }
.fx-c-mid { animation: fx-drift 6.5s linear both; }
.fx-c-front { animation: fx-drift 4.5s linear both; }

@keyframes fx-drift {
  from { transform: translateX(-40px); }
  to { transform: translateX(30px); }
}

/* Lichtenberg figure: the strike burns it in, then it grows and cools. */
.fx-hero {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.fx-hero.is-here {
  opacity: 1;
  animation: fx-emerge 1100ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

.fx-hero.is-gone {
  opacity: 0;
  animation: none;
  transition: opacity 60ms linear;
}

@keyframes fx-emerge {
  from { filter: brightness(0.15); }
  to { filter: brightness(1); }
}

/* The grid is wider than the strip (the ground sits off screen), so
   script sets its size and left offset. Cells are scaled up and smoothed. */
.fx-fern {
  position: absolute;
  top: 0;
  display: block;
  filter: drop-shadow(0 0 6px rgba(255, 60, 48, 0.75));
  transition: filter 110ms linear;
}

.fx-storm.is-lit .fx-fern {
  filter: drop-shadow(0 0 10px rgba(255, 150, 130, 0.95));
}

/* Light that rakes across everything during a flash */
.fx-glow {
  position: absolute;
  inset: 0;
  opacity: 0;
  mix-blend-mode: screen;
  background: radial-gradient(90% 60% at 50% 8%, rgba(255, 236, 230, 0.9) 0%, rgba(255, 70, 60, 0.45) 40%, rgba(255, 40, 30, 0) 75%);
  transition: opacity 110ms linear;
}

.fx-storm.is-lit .fx-glow {
  opacity: 1;
}

/* Rain */
.fx-rain {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Film grain */
.fx-grain {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0.18;
  mix-blend-mode: overlay;
}

/* Embers rising */
.fx-air {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.fx-fly {
  fill: #ff4a3d;
  opacity: 0;
}

.fx-storm.on .fx-fly {
  animation: fx-fly var(--t) ease-out var(--d) both;
}

@keyframes fx-fly {
  0% { opacity: 0; transform: translate(0, 0); }
  15% { opacity: 0.9; }
  80% { opacity: 0.7; }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)); }
}

/* Lightning bolt */
.fx-bolt {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.fx-bolt path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  opacity: 0;
}

.fx-bolt .halo { stroke: rgba(255, 190, 180, 0.4); stroke-width: 8; }
.fx-bolt .core { stroke: #fff4f0; stroke-width: 2.4; }
.fx-bolt .branch { stroke: #fff4f0; stroke-width: 1.4; }

.fx-bolt.strike path {
  animation: fx-bolt-draw 150ms ease-out forwards, fx-bolt-flicker 620ms linear 150ms forwards;
}

@keyframes fx-bolt-draw {
  from { stroke-dashoffset: 1; opacity: 1; }
  to { stroke-dashoffset: 0; opacity: 1; }
}

@keyframes fx-bolt-flicker {
  0% { opacity: 1; }
  25% { opacity: 0.2; }
  45% { opacity: 0.9; }
  100% { opacity: 0; }
}

/* Flash across the whole page. Peaks are kept low and the double flicker is
   gentle, because a full-screen strobe is hard on the eyes. */
.fx-flash {
  position: fixed;
  inset: 0;
  z-index: 10001;
  pointer-events: none;
  opacity: 0;
  background: rgba(255, 232, 228, 0.9);
}

html.light .fx-flash {
  background: transparent;
  -webkit-backdrop-filter: invert(0.92);
  backdrop-filter: invert(0.92);
}

.fx-flash.go-soft {
  animation: fx-flash-soft 360ms linear both;
}

.fx-flash.go-main {
  animation: fx-flash-main 640ms linear both;
}

@keyframes fx-flash-soft {
  0% { opacity: 0; }
  10% { opacity: 0.22; }
  100% { opacity: 0; }
}

@keyframes fx-flash-main {
  0% { opacity: 0; }
  6% { opacity: 0.55; }
  20% { opacity: 0.12; }
  32% { opacity: 0.2; }
  100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-storm,
  .fx-flash {
    display: none;
  }
  #theme-toggle-btn.fx-spin svg {
    animation: none;
  }
}
