/* Dream transitions: the dreamy, animated change between pages and Admin panels.
 *
 *   dreamy  the page dissolves into drifting mist, ripples spread from the tap, light motes rise and the new page
 *           resolves out of the haze (set on <html data-transitions="dreamy"> by assets/transitions.js)
 *   soft    the original quick fade (the .page.active rule in base.css) and nothing else
 *   off     no entrance animation at all
 *
 * Reduced motion, "Pause motion" and the visitor's own choice always win over the site default. Timings here must
 * match LEAVE_MS and SETTLE_MS in assets/transitions.js. Loads after interface.css.
 */
:root {
  --dream-ease: cubic-bezier(.2, .7, .2, 1);
  --dv-leave: 170ms;
  --dv-arrive: 780ms;
  --dv-total: 1100ms;
  /* Dark: deep indigo haze with violet, rose and aqua light. */
  --dv-base: rgba(9, 11, 27, .72);
  --dv-core: rgba(86, 64, 158, .55);
  --dv-a: rgba(152, 122, 255, .58);
  --dv-b: rgba(255, 128, 188, .40);
  --dv-c: rgba(82, 212, 222, .36);
  --dv-ring: rgba(218, 204, 255, .72);
  --dv-ring2: rgba(255, 172, 214, .58);
  --dv-glow: rgba(172, 142, 255, .36);
  --dv-mote: rgba(255, 244, 222, .96);
  --dv-star: #f6ddb0;
}
html[data-appearance=light] {
  /* Light: warm cream haze with soft lilac, rose and mint light. */
  --dv-base: rgba(249, 245, 239, .80);
  --dv-core: rgba(214, 196, 246, .72);
  --dv-a: rgba(150, 110, 218, .42);
  --dv-b: rgba(240, 148, 184, .40);
  --dv-c: rgba(108, 200, 206, .36);
  --dv-ring: rgba(118, 78, 176, .58);
  --dv-ring2: rgba(212, 108, 150, .48);
  --dv-glow: rgba(150, 110, 218, .30);
  --dv-mote: rgba(255, 255, 255, .98);
  --dv-star: #8a5f2e;
}

/* ── Off: no entrance animation ── */
html[data-transitions=off] :is(.page, .panel).active { animation: none; }

/* ── Dreamy: the pages themselves ──
 * dream-arriving stays on the active page until it is left, so removing it never restarts the original fade. */
html[data-transitions=dreamy] :is(.page, .panel).active.dream-arriving {
  animation: dreamArrive var(--dv-arrive) var(--dream-ease) both;
  transform-origin: 50% 0;
}
html[data-transitions=dreamy] :is(.page, .panel).active.dream-leaving {
  animation: dreamLeave var(--dv-leave) cubic-bezier(.4, 0, 1, 1) both;
  pointer-events: none;
}
@keyframes dreamLeave {
  from { opacity: 1; transform: translateY(0); filter: none; }
  to   { opacity: 0; transform: translateY(-8px); filter: blur(7px) saturate(1.35) hue-rotate(14deg); }
}
@keyframes dreamArrive {
  0%   { opacity: 0; transform: translateY(18px) scale(1.012); filter: blur(14px) saturate(1.5) hue-rotate(-22deg); }
  55%  { opacity: 1; filter: blur(2px) saturate(1.15) hue-rotate(-6deg); }
  100% { opacity: 1; transform: translateY(0) scale(1); filter: none; }
}

/* ── Dreamy: the mist ── */
.dream-veil {
  position: fixed; inset: 0; z-index: 90; overflow: hidden; pointer-events: none; contain: layout paint;
  --dv-x: 50%; --dv-y: 42%;
  background: radial-gradient(120% 95% at var(--dv-x) var(--dv-y), var(--dv-core) 0%, var(--dv-base) 66%);
  opacity: 0;
}
.dream-veil[hidden] { display: none; }
.dream-veil.run { animation: dvEnvelope var(--dv-total) linear both; }
/* In over the leave, hold while the new page starts to arrive, then lift slowly. */
@keyframes dvEnvelope {
  0%   { opacity: 0; animation-timing-function: ease-in; }
  15%  { opacity: 1; animation-timing-function: linear; }
  28%  { opacity: 1; animation-timing-function: cubic-bezier(.3, .6, .4, 1); }
  100% { opacity: 0; }
}
.dream-veil i, .dream-veil b, .dream-veil span { position: absolute; display: block; }
.dv-bloom { left: 50%; top: 50%; width: 85vmax; height: 85vmax; margin: -42.5vmax 0 0 -42.5vmax; border-radius: 50%; will-change: transform; }
.dv-bloom.a { background: radial-gradient(closest-side, var(--dv-a), transparent 72%); animation: dvDriftA var(--dv-total) var(--dream-ease) both; }
.dv-bloom.b { background: radial-gradient(closest-side, var(--dv-b), transparent 72%); animation: dvDriftB var(--dv-total) var(--dream-ease) both; }
.dv-bloom.c { background: radial-gradient(closest-side, var(--dv-c), transparent 72%); animation: dvDriftC var(--dv-total) var(--dream-ease) both; }
@keyframes dvDriftA { from { transform: translate3d(-38vw, -20vh, 0) scale(.65) rotate(0deg); } to { transform: translate3d(24vw, 14vh, 0) scale(1.15) rotate(46deg); } }
@keyframes dvDriftB { from { transform: translate3d(36vw, 22vh, 0) scale(.7) rotate(0deg); }  to { transform: translate3d(-22vw, -16vh, 0) scale(1.2) rotate(-52deg); } }
@keyframes dvDriftC { from { transform: translate3d(-8vw, 34vh, 0) scale(.6) rotate(0deg); }  to { transform: translate3d(14vw, -26vh, 0) scale(1.1) rotate(38deg); } }
/* Orbit-like ripples spreading from where the dreamer tapped, echoing the moon rings on the landing page. */
.dv-ring {
  left: var(--dv-x); top: var(--dv-y); width: 70vmin; height: 70vmin; margin: -35vmin 0 0 -35vmin; border-radius: 50%;
  border: 1.5px solid var(--dv-ring); box-shadow: 0 0 34px var(--dv-glow), inset 0 0 34px var(--dv-glow);
  opacity: 0; transform: rotate(-16deg) scale(.08, .04);
  animation: dvRing 880ms var(--dream-ease) both;
}
.dv-ring.r2 { border-color: var(--dv-ring2); animation-delay: 90ms; }
.dv-ring.r3 { animation-delay: 190ms; }
@keyframes dvRing {
  0%   { opacity: 0; transform: rotate(-16deg) scale(.08, .04); }
  14%  { opacity: .95; }
  100% { opacity: 0; transform: rotate(-16deg) scale(2.7, 1.35); }
}
.dv-star {
  left: var(--dv-x); top: var(--dv-y); margin: -.6em 0 0 -.5em; font-size: 34px; line-height: 1; color: var(--dv-star);
  text-shadow: 0 0 22px var(--dv-glow), 0 0 8px var(--dv-glow); opacity: 0; animation: dvStar 760ms var(--dream-ease) both;
}
.dream-veil.offstage .dv-star { display: none; }
@keyframes dvStar {
  0%   { opacity: 0; transform: scale(.3) rotate(-30deg); }
  30%  { opacity: 1; }
  100% { opacity: 0; transform: scale(1.7) rotate(70deg); }
}
.dv-motes { inset: 0; }
.dv-motes i {
  left: var(--x, 50%); top: var(--y, 50%); width: 3px; height: 3px; border-radius: 50%;
  background: var(--dv-mote); box-shadow: 0 0 9px 2px var(--dv-glow); opacity: 0;
  animation: dvMote var(--d, 1000ms) ease-out var(--delay, 0ms) both;
}
@keyframes dvMote {
  0%   { opacity: 0; transform: translate3d(0, 12px, 0) scale(.4); }
  28%  { opacity: 1; }
  100% { opacity: 0; transform: translate3d(var(--dx, 0px), -110px, 0) scale(1.25); }
}

/* Admin: the mist covers the working area, not the top bar or the sidebar. */
body.admin-page .dream-veil { top: 78px; left: 244px; }
@media (max-width: 900px) { body.admin-page .dream-veil { top: 70px; left: 0; } }

/* A phone has less to cover and less power to spend. */
@media (max-width: 640px) {
  .dv-bloom { width: 110vmax; height: 110vmax; margin: -55vmax 0 0 -55vmax; }
  .dv-ring { width: 86vmin; height: 86vmin; margin: -43vmin 0 0 -43vmin; }
}

@media (prefers-reduced-motion: reduce) { .dream-veil { display: none !important; } }
/* High-contrast modes replace backgrounds with solid system colours, which would turn the mist into a flat cover. */
@media (forced-colors: active) { .dream-veil { display: none !important; } }
html.motion-paused .dream-veil { display: none !important; }
html[data-transitions=off] .dream-veil, html[data-transitions=soft] .dream-veil { display: none !important; }
