/* The glass around the grid. The grid itself is painted by src/web.rs from the ratatui
   buffer; the Rust side sets --bg / --fg / --dim / --bright from the phosphor in use. */

:root {
  --bg: #050a06;
  --fg: #7bf3a0;
  --dim: #2f8a4f;
  --bright: #dbffe6;
  --font: "VT323", "Courier New", monospace;
  /* About 110 columns across, whatever the window width. */
  --size: clamp(15px, calc(100vw / 50), 32px);
  --lh: 1;
  --keys-h: 0px;
}

html,
body {
  margin: 0;
  height: 100%;
  background: #000;
  overflow: hidden;
}

body {
  position: fixed;
  inset: 0;
  font-family: var(--font);
  font-size: var(--size);
  line-height: var(--lh);
  color: var(--fg);
  -webkit-font-smoothing: antialiased;
}

/* Tube face: phosphor background, bowed by the warp filter. The filter runs on the CPU
   over the whole tube whenever anything inside repaints, so the tube gets its own layer
   (the animated overlays outside it never trigger that) and repaints are rationed by the
   Rust side, which only redraws on input or a static reseed. */
.tube {
  position: absolute;
  inset: 0 0 var(--keys-h) 0;
  background: var(--bg);
  overflow: hidden;
  filter: url(#warp);
  will-change: transform;
  contain: strict;
}

#screen {
  position: absolute;
  inset: 18px 24px;
  overflow: hidden;
  contain: strict;
}

#screen .row {
  white-space: pre;
  height: calc(var(--size) * var(--lh));
  contain: content;
}

/* One soft halo plus two crisp colour-fringe copies; the blur is the only costly one. */
#screen span {
  display: inline-block;
  width: 1ch;
  vertical-align: top;
  text-shadow:
    0 0 5px color-mix(in srgb, currentColor 60%, transparent),
    0.7px 0 rgba(255, 80, 80, 0.22),
    -0.7px 0 rgba(80, 140, 255, 0.22);
}

/* Selection blocks glow as a whole instead of per glyph. */
#screen span.inv {
  text-shadow: none;
  box-shadow: 0 0 10px color-mix(in srgb, var(--fg) 45%, transparent);
}

.glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    ellipse 70% 60% at 50% 45%,
    color-mix(in srgb, var(--fg) 9%, transparent),
    transparent 70%
  );
}

.scan {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* Translucent black lines darken exactly like a multiply blend without the blend. */
  background: repeating-linear-gradient(180deg, rgba(0, 0, 0, 0.3) 0 1px, rgba(0, 0, 0, 0) 1px 3px);
}

/* Vignette and a reflection across the glass. */
.glass {
  position: absolute;
  inset: 0 0 var(--keys-h) 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 58%, rgba(0, 0, 0, 0.72) 100%),
    linear-gradient(112deg, rgba(255, 255, 255, 0.075) 0%, rgba(255, 255, 255, 0) 38%);
}

/* Film grain: a tile of noise nudged around a few times a second. */
.grain {
  position: absolute;
  inset: -60px -60px calc(var(--keys-h) - 60px) -60px;
  pointer-events: none;
  opacity: 0.17;
  mix-blend-mode: screen;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.9 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  animation: static 0.45s steps(4) infinite;
  will-change: transform;
}

@keyframes static {
  0% { transform: translate(0, 0); }
  25% { transform: translate(-22px, 14px); }
  50% { transform: translate(18px, -26px); }
  75% { transform: translate(-10px, -8px); }
  100% { transform: translate(24px, 20px); }
}

/* The occasional brightness hiccup. */
.flicker {
  position: absolute;
  inset: 0 0 var(--keys-h) 0;
  pointer-events: none;
  background: var(--fg);
  mix-blend-mode: soft-light;
  opacity: 0;
  animation: flick 6s infinite;
  will-change: opacity;
}

@keyframes flick {
  0%, 96%, 100% { opacity: 0; }
  97% { opacity: 0.08; }
  98% { opacity: 0; }
  99% { opacity: 0.05; }
}

/* The keyboard hook: a real textarea the Rust side focuses when the notes or the seed
   take typing. Practically invisible, but not display:none (that would keep the
   keyboard away), and 16px so iOS does not zoom into it. */
#kbd {
  position: fixed;
  left: 0;
  bottom: 0;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  opacity: 0.01;
  font-size: 16px;
  resize: none;
  pointer-events: none;
}

/* Soft keys: hidden until there is a touch screen and no pointer. Filled by src/web.rs. */
#keys {
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* Wraps to as many rows as the screen needs; the Rust side copies the height into
     --keys-h so the tube ends where the bar begins. */
  box-sizing: border-box;
  padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
  gap: 6px;
  flex-wrap: wrap;
  align-content: flex-start;
  background: var(--bg);
}

#keys button {
  flex: 1 1 auto;
  min-width: 48px;
  min-height: 46px;
  padding: 0 10px;
  background: transparent;
  border: 1px solid var(--dim);
  border-radius: 0;
  color: var(--bright);
  font: inherit;
  font-size: 20px;
  line-height: 1;
  text-shadow: 0 0 6px color-mix(in srgb, var(--fg) 55%, transparent);
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

#keys button.arrow {
  flex: 0 0 52px;
}

#keys button:active {
  background: var(--fg);
  color: var(--bg);
  text-shadow: none;
}

@media (hover: none) and (pointer: coarse) {
  :root {
    --keys-h: 120px;
  }
  #keys {
    display: flex;
  }
  #screen {
    inset: 10px 10px 6px;
  }
}

/* ?keys=on forces the bar (a tablet with a mouse, say); ?keys=off hides it. */
body.keys {
  --keys-h: 120px;
}
body.keys #keys {
  display: flex;
}
body.nokeys {
  --keys-h: 0px;
}
body.nokeys #keys {
  display: none;
}

@media (max-width: 480px) {
  :root {
    --size: 17px;
  }
}

/* ?fx=off, and anyone who asked for less motion. */
body.plain .tube {
  filter: none;
}
body.plain .grain,
body.plain .flicker,
body.plain .scan,
body.plain .glass {
  display: none;
}
body.plain #screen span {
  text-shadow: none;
}

@media (prefers-reduced-motion: reduce) {
  .grain,
  .flicker {
    animation: none;
  }
}
