/* fx.css: background canvas, grain, scanlines, cursor, glitch,
   boot screen and page transitions. Pure decoration: removing this file
   leaves a working page. Reduced motion calms or switches all of it off. */

/* ---------- layers ---------- */

#rain {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  opacity: .34;
  pointer-events: none;
}

.fx { position: fixed; pointer-events: none; }

.fx-vignette {
  inset: 0;
  z-index: 1;
  background: radial-gradient(ellipse at 50% 45%, transparent 35%, rgba(0, 0, 0, .78) 100%);
}

/* the grain layer is oversized so it can jitter without showing edges */
.fx-grain {
  inset: -20%;
  z-index: 60;
  background: url("../assets/grain.svg") repeat;
  background-size: 180px;
  opacity: .085;
  animation: grain 1s steps(6) infinite;
  will-change: transform;
  transition: opacity .4s;
}
@keyframes grain {
  0%   { transform: translate(0, 0); }
  17%  { transform: translate(-4%, 3%); }
  33%  { transform: translate(3%, -5%); }
  50%  { transform: translate(-6%, -2%); }
  67%  { transform: translate(5%, 4%); }
  83%  { transform: translate(-2%, 6%); }
  100% { transform: translate(0, 0); }
}

.fx-scan {
  inset: 0;
  z-index: 61;
  background: repeating-linear-gradient(to bottom, rgba(255, 255, 255, .028) 0 1px, transparent 1px 3px);
  transition: opacity .4s;
}
/* a faint refresh band rolling down the screen */
.fx-scan::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: 18vh;
  background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, .03), transparent);
  animation: sweep 9s linear infinite;
}
@keyframes sweep {
  from { transform: translateY(-20vh); }
  to   { transform: translateY(120vh); }
}

/* keep the video itself clean while it plays */
html.playing .fx-grain,
html.playing .fx-scan { opacity: 0; }

/* ---------- custom cursor (fine pointers only, added by fx.js) ---------- */

html.has-cursor,
html.has-cursor * { cursor: none !important; }
html.has-cursor input { cursor: text !important; }

.cur {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 100;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: difference;
  transition: opacity .2s;
}
.cur.on { opacity: 1; }
.cur.on.off { opacity: 0; }

.cur-dot {
  width: 4px;
  height: 4px;
  margin: -2px 0 0 -2px;
  background: #fff;
}
.cur-ring {
  width: 30px;
  height: 30px;
  margin: -15px 0 0 -15px;
}
.cur-ring::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid rgba(255, 255, 255, .7);
  border-radius: 50%;
  transition: transform .25s var(--ease), background-color .25s, border-color .25s;
}
.cur-ring.is-hot::before {
  transform: scale(1.6);
  border-color: #fff;
  background: rgba(255, 255, 255, .08);
}
.cur-ring.is-down::before { transform: scale(.7); }

/* ---------- glitch (two offset slices of the same text) ---------- */

.glitch { position: relative; display: inline-block; }
.glitch::before,
.glitch::after {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--bg);
  opacity: 0;
  pointer-events: none;
}
.glitch.is-glitching::before {
  opacity: 1;
  color: var(--hi);
  animation: glitch-a .5s steps(1) both;
}
.glitch.is-glitching::after {
  opacity: 1;
  color: #8a8a8a;
  animation: glitch-b .5s steps(1) both;
}
@keyframes glitch-a {
  0%   { clip-path: inset(10% 0 70% 0); transform: translate(-3px, 0); }
  20%  { clip-path: inset(62% 0 14% 0); transform: translate(3px, 0); }
  40%  { clip-path: inset(34% 0 46% 0); transform: translate(-2px, 0); }
  60%  { clip-path: inset(82% 0 4% 0);  transform: translate(4px, 0); }
  80%  { clip-path: inset(4% 0 84% 0);  transform: translate(-4px, 0); }
  100% { clip-path: inset(50% 0 50% 0); transform: none; }
}
@keyframes glitch-b {
  0%   { clip-path: inset(72% 0 8% 0);  transform: translate(3px, 1px); }
  20%  { clip-path: inset(20% 0 64% 0); transform: translate(-3px, 0); }
  40%  { clip-path: inset(48% 0 30% 0); transform: translate(4px, -1px); }
  60%  { clip-path: inset(6% 0 78% 0);  transform: translate(-2px, 0); }
  80%  { clip-path: inset(58% 0 26% 0); transform: translate(2px, 1px); }
  100% { clip-path: inset(50% 0 50% 0); transform: none; }
}

/* locked menu entry: short shake */
.item.is-denied { animation: denied .36s steps(2) both; }
@keyframes denied {
  0%   { transform: translateX(0); }
  25%  { transform: translateX(-5px); }
  50%  { transform: translateX(4px); }
  75%  { transform: translateX(-2px); }
  100% { transform: translateX(0); }
}

.boot-log::after {
  content: "_";
  margin-left: 2px;
  animation: blink 1.05s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* ---------- boot screen (first visit to the menu only) ---------- */

.boot {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: var(--gutter);
  font-size: 13px;
  color: var(--dim);
  background: var(--bg);
  transition: opacity .35s var(--ease);
}
.boot.is-done { opacity: 0; }
.boot-log { margin: 0 0 8vh; white-space: pre; }
.boot-log .ok { color: var(--hi); }
.boot-skip {
  position: absolute;
  top: var(--gutter);
  right: var(--gutter);
  font-size: 11px;
}

/* hide the page under the boot screen; the failsafe shows it anyway if
   fx.js never runs */
html.boot .shell {
  visibility: hidden;
  animation: boot-failsafe 0s 4.5s forwards;
}
@keyframes boot-failsafe { to { visibility: visible; } }

/* ---------- section transitions ---------- */

/* fill-mode backwards (not both) so the end state never overrides the
   leaving transition below */
.shell { animation: enter .5s var(--ease) backwards; }
@keyframes enter {
  from { opacity: 0; transform: translateY(8px); filter: blur(3px); }
}
html.leaving .shell {
  opacity: 0;
  transform: translateY(-6px);
  filter: blur(3px);
  transition: opacity .24s var(--ease), transform .24s var(--ease), filter .24s var(--ease);
}

/* ---------- reduced motion: calm everything down ---------- */

@media (prefers-reduced-motion: reduce) {
  .fx-scan::after,
  .glitch::before,
  .glitch::after { display: none; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .boot-log::after { animation: none; }
}
