/* THE GOD TERMINAL — fx: CRT overlay, retro wobble, flyaway text and meters (GT.fx). */

/* ───────── CRT overlay (#crt + .fx-crt-grille, built by js/fx.js) ─────────
 * --fx-scan is set by fx.js to ~3px rounded to whole device pixels, so the
 * scanlines and aperture grille never beat against the pixel grid. */
#crt,
.fx-crt-grille {
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  transition: opacity 450ms ease, visibility 0s linear 450ms;
}
html[data-crt="on"] #crt {
  opacity: 1;
  visibility: visible;
  transition: opacity 450ms ease;
}
html[data-crt="off"] #crt > * { animation-play-state: paused; }
#crt > * { position: absolute; inset: 0; pointer-events: none; }

/* Scanlines: one bright row, then two progressively darker ones. */
.crt-screen {
  background: linear-gradient(to bottom,
      transparent 0 33.34%, rgba(0, 0, 0, 0.17) 33.34% 66.67%, rgba(0, 0, 0, 0.32) 66.67% 100%)
    0 0 / 100% var(--fx-scan, 3px);
  animation: crt-flicker 7s steps(1, end) infinite;
}

/* Aperture grille: faint R/G/B columns multiplied into the picture. */
.fx-crt-grille {
  position: fixed;
  inset: 0;
  z-index: var(--z-crt);
  pointer-events: none;
  background: linear-gradient(90deg, #ffd2d2 0 33.34%, #d2ffd6 33.34% 66.67%, #d6dcff 66.67% 100%)
    0 0 / var(--fx-scan, 3px) 100%;
  mix-blend-mode: multiply;
}
html[data-crt="on"] .fx-crt-grille {
  opacity: 0.5;
  visibility: visible;
  transition: opacity 450ms ease;
}

/* A slow, soft brighter band rolling down the tube. */
#crt > .crt-band {
  bottom: auto;
  height: 34vh;
  background: linear-gradient(to bottom,
    transparent,
    color-mix(in srgb, var(--text-bright) 3%, transparent) 35%,
    color-mix(in srgb, var(--text-bright) 6.5%, transparent) 55%,
    color-mix(in srgb, var(--text-bright) 2%, transparent) 75%,
    transparent);
  animation: crt-roll 11s linear infinite;
  will-change: transform;
}

/* Power-on sweep, played once by fx.js when the retro screen is switched on. */
#crt > .crt-sweep {
  bottom: auto;
  height: 22vh;
  opacity: 0;
  background: linear-gradient(to bottom,
    transparent,
    color-mix(in srgb, var(--text-bright) 14%, transparent) 70%,
    rgba(255, 255, 255, 0.4) 97%,
    transparent);
}

/* Cherry Soda: a slow pulsing edge glow in the palette's accent. */
.crt-glow { display: none; }
html[data-palette="cherry"] .crt-glow {
  display: block;
  box-shadow:
    inset 0 0 10vmin 1vmin color-mix(in srgb, var(--accent-3) 40%, transparent),
    inset 0 0 2.6vmin 0 color-mix(in srgb, var(--accent) 60%, transparent);
  animation: crt-cherry 5.2s ease-in-out infinite;
}

/* Bezel: black rounded corners, vignette and edge falloff that read as a curved tube,
 * plus a faint glass reflection near the top-left. */
#crt > .crt-bezel {
  inset: -64px;
  border: 64px solid #000;
  border-radius: calc(64px + clamp(10px, 2.4vmin, 24px));
  box-shadow:
    inset 0 0 8vmin 1.5vmin rgba(0, 0, 0, 0.5),
    inset 0 0 1.6vmin 0 rgba(0, 0, 0, 0.65);
  background:
    radial-gradient(ellipse 72% 66% at 50% 50%, transparent 58%, rgba(0, 0, 0, 0.34) 100%),
    radial-gradient(ellipse 55% 34% at 24% 4%, rgba(255, 255, 255, 0.04), transparent 70%);
}

@keyframes crt-flicker {
  0% { opacity: 1; }
  9% { opacity: 0.9; }
  10% { opacity: 1; }
  33% { opacity: 0.95; }
  34% { opacity: 1; }
  58% { opacity: 0.86; }
  59% { opacity: 0.96; }
  60% { opacity: 1; }
  81% { opacity: 0.93; }
  82% { opacity: 1; }
}
@keyframes crt-roll {
  from { transform: translateY(-36vh); }
  to { transform: translateY(102vh); }
}
@keyframes crt-cherry {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}

html[data-reduced-motion="on"] .crt-screen { animation: none; }
html[data-reduced-motion="on"] #crt > .crt-band,
html[data-reduced-motion="on"] #crt > .crt-sweep { display: none; }
html[data-reduced-motion="on"] .crt-glow { animation: none; opacity: 0.7; }
/* Phones: the grille is invisible at 3× density and costs a full-screen blend. */
@media (max-width: 599px) {
  .fx-crt-grille { display: none; }
}

/* ───────── retro wobble (F8 mode and GT.fx.wobble bursts) ─────────
 * fx.js toggles html.fx-wobble and drives --fx-wob (channel offset). Part of the text
 * offset scales with the font so small labels stay legible and big titles split wide. */
html.fx-wobble {
  --fx-wob-a: 0.6;
  --fx-wob-d: calc(var(--fx-wob, 1.8px) * 0.45 + 0.045em);
  /* Coloured edge offsets on panels and windows: red fringe left, cyan right. */
  --fx-edge: calc(var(--fx-wob, 1.8px) * 1.1 + 0.8px);
  --fx-fringe:
    calc(var(--fx-edge) * -1) 0 0 -1px rgba(255, 36, 84, 0.62),
    var(--fx-edge) 0 0 -1px rgba(30, 230, 255, 0.62);
}
html.fx-wobble[data-reduced-motion="on"] { --fx-wob-a: 0.45; }
html.fx-wobble :is(#app, #windows, #modal, #stage) * {
  --fx-wob-r: rgba(255, 36, 84, var(--fx-wob-a));
  --fx-wob-c: rgba(30, 230, 255, var(--fx-wob-a));
  text-shadow:
    calc(var(--fx-wob-d) * -1) 0 0 var(--fx-wob-r),
    var(--fx-wob-d) 0 0 var(--fx-wob-c),
    0 0 calc(7px * var(--glow-k)) var(--glow) !important;
}
/* A channel ghost can't outshine its own text: each ghost takes the text's brightest
 * channel, so dim labels split faintly and stay readable while bright titles split hard. */
@supports (color: rgb(from red max(r, g, b) 0 0 / 0.5)) {
  html.fx-wobble :is(#app, #windows, #modal, #stage) * {
    --fx-wob-r: rgb(from currentColor max(r, g, b) calc(max(r, g, b) * 0.14) calc(max(r, g, b) * 0.33) / var(--fx-wob-a));
    --fx-wob-c: rgb(from currentColor calc(max(r, g, b) * 0.12) calc(max(r, g, b) * 0.9) max(r, g, b) / var(--fx-wob-a));
  }
}
/* box-shadow can't be appended to, so each rule restates its owner's shadows
 * (base.css .panel, windows.css .win) after the fringe. */
html.fx-wobble .panel {
  box-shadow:
    var(--fx-fringe),
    var(--box-glow),
    inset 0 0 calc(36px * var(--glow-k)) calc(-18px * var(--glow-k)) var(--glow) !important;
}
html.fx-wobble .win {
  box-shadow:
    var(--fx-fringe),
    0 0 0 1px rgba(0, 0, 0, 0.5),
    0 0 calc(28px * var(--glow-k)) calc(-6px * var(--glow-k)) var(--glow),
    0 24px 50px -16px rgba(0, 0, 0, 0.9),
    inset 0 0 calc(40px * var(--glow-k)) calc(-16px * var(--glow-k)) var(--glow),
    inset 0 1px 0 rgba(255, 255, 255, 0.08) !important;
}

/* ───────── flyaway text ───────── */
.fx-text-layer {
  position: fixed;
  inset: 0;
  z-index: var(--z-fx);
  pointer-events: none;
  overflow: hidden;
  contain: strict;
}
.fx-fly {
  position: absolute;
  left: 0;
  top: 0;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  font-family: var(--font-mono);
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--fly-c);
  /* Glow on top, then a dark halo underneath so it reads over busy code. */
  text-shadow:
    0 0 0.08em rgba(255, 255, 255, 0.55),
    0 0 0.3em var(--fly-c),
    0 0 0.9em color-mix(in srgb, var(--fly-c) 50%, transparent),
    0 0.05em 0.04em rgba(0, 0, 0, 0.9),
    0 0 0.16em rgba(0, 0, 0, 0.95),
    0 0 0.45em rgba(0, 0, 0, 0.75);
  will-change: transform, opacity;
}
.fx-fly--display {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.03em;
}

/* ───────── meters (GT.fx.Meter) ───────── */
.fx-meter {
  --meter-c: var(--meter-color, var(--accent));
  --meter-r: var(--meter-radius, 2px);
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  min-width: 0;
}
.fx-meter-track {
  position: relative;
  flex: 1 1 auto;
  min-width: 2rem;
  height: var(--meter-h, 0.625rem);
  border-radius: var(--meter-r);
  background: color-mix(in srgb, var(--meter-c) 10%, rgba(0, 0, 0, 0.4));
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--meter-c) 30%, transparent),
    inset 0 1px 3px rgba(0, 0, 0, 0.5);
}
.fx-meter-clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
}
.fx-meter-back,
.fx-meter-fill {
  position: absolute;
  inset: 0;
  transform-origin: 0 50%;
  transform: scaleX(0);
}
.fx-meter-back { background: #fff; }
.fx-meter-fill {
  overflow: hidden;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--meter-c) 45%, transparent),
    var(--meter-c) 72%,
    color-mix(in srgb, var(--meter-c) 55%, #fff));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
}
/* A soft sheen that drifts along the fill now and then. */
.fx-meter-fill::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 35%, rgba(255, 255, 255, 0.38) 50%, transparent 65%);
  transform: translateX(-100%);
  animation: fx-sheen 3.4s cubic-bezier(.45, 0, .25, 1) infinite;
  animation-delay: var(--fx-sheen-d, 0s);
}
.fx-meter-flash {
  position: absolute;
  inset: 0;
  transform-origin: 0 50%;
  background: #fff;
  opacity: 0;
}
.fx-meter-glow {
  position: absolute;
  inset: -3px;
  border-radius: calc(var(--meter-r) + 3px);
  box-shadow:
    0 0 14px 3px var(--meter-c),
    0 0 4px 1px color-mix(in srgb, var(--meter-c) 50%, #fff);
  opacity: 0;
  pointer-events: none;
}
.fx-meter.is-full .fx-meter-glow { opacity: 0.4; }
.fx-meter-headwrap {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.fx-meter-head {
  position: absolute;
  left: -1.5px;
  top: -40%;
  bottom: -40%;
  width: 3px;
  border-radius: 2px;
  background: #fff;
  box-shadow:
    0 0 5px 1px var(--meter-c),
    0 0 14px 3px color-mix(in srgb, var(--meter-c) 55%, transparent);
  transition: opacity 160ms ease;
}
.fx-meter-value {
  flex: none;
  min-width: 4ch;
  text-align: right;
  font-family: var(--font-mono);
  font-size: 0.9375rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--text-bright);
  text-shadow: var(--text-glow);
}

/* Segmented (blocky) meters: one cell per segment, lit cell by cell. */
.fx-meter--seg .fx-meter-track {
  height: var(--meter-h, 1rem);
  background: none;
  box-shadow: none;
}
.fx-meter--seg .fx-meter-clip { overflow: visible; }
.fx-meter-blocks {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(var(--segments), minmax(0, 1fr));
  gap: var(--meter-gap, 3px);
}
.fx-meter-block {
  display: block;
  border-radius: 1px;
  background: color-mix(in srgb, var(--meter-c) 11%, rgba(0, 0, 0, 0.4));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--meter-c) 24%, transparent);
}
.fx-meter-block.is-on {
  background: linear-gradient(to bottom, color-mix(in srgb, var(--meter-c) 70%, #fff), var(--meter-c) 45%);
  box-shadow: 0 0 9px -1px var(--meter-c);
}
.fx-meter-block.is-back {
  background: #fff;
  box-shadow: 0 0 9px -1px rgba(255, 255, 255, 0.8);
}

@keyframes fx-sheen {
  0% { transform: translateX(-100%); }
  45%, 100% { transform: translateX(100%); }
}
html[data-reduced-motion="on"] .fx-meter-fill::after { display: none; }
