:root {
  /* Screen rectangle as % of the device image — pixel-detected from etd-*.png. */
  --screen-top: 24.08%;
  --screen-left: 38.47%;
  --screen-width: 23.62%;
  --screen-height: 25.59%;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }

body {
  background: #07060a;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

/* Stage is locked to the image aspect ratio and fit to the viewport, so the
   absolutely-positioned screen overlay tracks the device at any size. */
.stage {
  position: relative;
  aspect-ratio: 2560 / 1447;
  width: min(100vw, calc(100vh * 2560 / 1447));
  opacity: 0;
}
/* First paint stays pure black until the OFF hero has decoded — no half-loaded device pop-in. */
.stage.ready { opacity: 1; transition: opacity 420ms ease; }

.device {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}

/* Whole-page film grain — animated noise over everything, always on. */
#filmGrain {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 9999;
  opacity: 0.10;
  mix-blend-mode: overlay;
}

/* Off image sits over the On image; power-on hides it instantly (no fade). */
.device-off { z-index: 2; }
.stage.powered .device-off { opacity: 0; }
/* On power-off, snap the off-lever image back instantly while the screen (z-index 3,
   above both device images) keeps playing its collapse animation. */
.stage.powering-off .device-off { opacity: 1; }

/* Transmit state (hold LINE FEED): the red TX LED lights — show instantly over the others. */
.device-lf { z-index: 2; opacity: 0; }
.stage.transmitting .device-lf { opacity: 1; }

.screen {
  position: absolute;
  top: var(--screen-top);
  left: var(--screen-left);
  width: var(--screen-width);
  height: var(--screen-height);
  z-index: 3;
  overflow: hidden;
  /* match the glass: rounded corners clip the terminal + its bloom off the bezel */
  border-radius: 2.6% / 4.2%;
}

/* The bezel overhangs the recessed glass: darken the inner edges so the terminal
   sinks below the frame instead of floating on the surface. Matte sheen kept faint. */
.screen-recess {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  border-radius: inherit;
  box-shadow:
    inset 0 0 18px 6px rgba(0, 0, 0, 0.92),
    inset 0 1px 5px rgba(0, 0, 0, 0.9);
  background:
    radial-gradient(125% 120% at 50% 44%, transparent 56%, rgba(0, 0, 0, 0.5) 100%),
    linear-gradient(158deg, rgba(255, 255, 255, 0.015), transparent 30%);
}

/* The terminal is rendered at a fixed reference resolution and uniformly scaled to
   fill the screen, so the tuned CRT proportions (bloom, grain, scanlines) are
   preserved exactly. Reference aspect matches the screen rect (~1.633). */
.crt-fit {
  position: absolute;
  top: 0;
  left: 0;
  width: 800px;
  height: 490px;
  transform-origin: top left;
  opacity: 0;
  transition: opacity 130ms ease;   /* power-off cross-dissolve into the off png */
}
.stage.powering .crt-fit { transition: opacity 0s; }   /* power-on is instant — don't dampen the flash */
.stage.powering .crt-fit,
.stage.powered .crt-fit { opacity: 1; }

/* Wraps the text/app layers (not the grain/scanline overlays) so power-off can
   blur and collapse the content while the grain stays crisp on top. */
.crt-content { position: absolute; inset: 0; }

.hotspot {
  position: absolute;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  z-index: 4;
}

/* Physical ON/OFF toggle, bottom-right of the unit. */
.toggle { left: 63.5%; top: 74%; width: 8%; height: 13%; }

/* LINE FEED key (right side of the keyboard) — press and hold to transmit. */
.linefeed { left: 59.2%; top: 60.3%; width: 3.4%; height: 4%; }

/* Calibration aid — add class "debug" to <body> to see hotspots. */
body.debug .hotspot { outline: 1px solid rgba(255, 40, 90, 0.9); background: rgba(255, 40, 90, 0.12); }

/* Mobile keyboard proxy — parked in-viewport at 1px (iOS may refuse the keyboard for
   off-screen/display:none inputs), 16px font so iOS doesn't auto-zoom the stage on focus. */
#mobileKey {
  position: fixed;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  font-size: 16px;
  opacity: 0.01;
  color: transparent;
  caret-color: transparent;
  border: 0;
  padding: 0;
  background: transparent;
  outline: none;
}

/* Coarse pointers get fatter physical controls (same visual positions, larger hit boxes). */
@media (pointer: coarse) {
  .toggle { left: 61.5%; top: 71%; width: 12%; height: 19%; }
  .linefeed { left: 57.7%; top: 58.3%; width: 6.4%; height: 8%; }
}

/* No-JS fallback — in-fiction fault message on the pure-black page. */
.noscript-note {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
  color: #79ff8c;
  font-family: "VGA437", ui-monospace, Menlo, monospace;
  font-size: clamp(14px, 2.2vw, 22px);
  letter-spacing: 0.12em;
  text-align: center;
  text-shadow: 0 0 12px rgba(121, 255, 140, 0.55);
  padding: 0 8vw;
  z-index: 10000;
}

/* Portrait phones: the unit is landscape-native — hold the room in-fiction until rotated.
   max-width keeps portrait iPads (which render the stage fine) out of the blackout. */
.rotate-note { display: none; }
@media (orientation: portrait) and (pointer: coarse) and (max-width: 767px) {
  .rotate-note {
    position: fixed;
    inset: 0;
    z-index: 800;                 /* above the stage + takeover scene (500), below film grain */
    display: flex;
    align-items: center;
    justify-content: center;
    background: #000;
    color: #79ff8c;
    font-family: "VGA437", ui-monospace, Menlo, monospace;
    font-size: clamp(14px, 4.2vw, 22px);
    letter-spacing: 0.12em;
    text-align: center;
    text-shadow: 0 0 12px rgba(121, 255, 140, 0.55);
    padding: 0 8vw;
  }
}

/* --- CRT power-on: no fade. The raster fires from a bright center line, overshoots
   open, and flickers down to steady — the way a tube TV snaps on. --- */
.crt-flash {
  z-index: 7;
  background: radial-gradient(130% 118% at 50% 50%, #eafff0 0%, #74ff9c 50%, transparent 92%);
  opacity: 0;
  mix-blend-mode: screen;
}
.stage.powering #crt { animation: crt-on 650ms linear; transform-origin: 50% 50%; }
.stage.powering .crt-flash { animation: crt-flash 650ms linear; }

@keyframes crt-on {
  0%   { transform: scaleY(0.003); filter: brightness(10) contrast(1.3); }
  7%   { transform: scaleY(0.014); filter: brightness(16) contrast(1.2); }
  17%  { transform: scaleY(1.07);  filter: brightness(3.2); }
  23%  { transform: scaleY(0.955); filter: brightness(0.4); }
  31%  { transform: scaleY(1.018); filter: brightness(2.7); }
  41%  { transform: scaleY(0.99);  filter: brightness(0.7); }
  54%  { filter: brightness(1.75); }
  68%  { filter: brightness(0.92); }
  82%  { filter: brightness(1.22); }
  100% { transform: scaleY(1);     filter: brightness(1); }
}
@keyframes crt-flash {
  0%   { opacity: 0; }
  4%   { opacity: 0.95; }
  13%  { opacity: 0.08; }
  22%  { opacity: 0.5; }
  33%  { opacity: 0.04; }
  100% { opacity: 0; }
}

/* CRT power-off: the whole monitor flares bright (full-screen flash, like power-on),
   then dies; the content collapses, blurs, and grains underneath as it cuts to black.
   The brightness comes from the full-screen flash, not the shrinking content. */
.stage.powering-off #crtContent { animation: crt-off 460ms ease-in forwards; transform-origin: 50% 50%; }
.stage.powering-off .crt-flash { animation: crt-off-flash 440ms ease-out forwards; }
.stage.powering-off .crt { --grain-opacity: 0.55; }
@keyframes crt-off {
  0%   { transform: scale(1, 1);        filter: brightness(1.3) blur(0px); }
  22%  { transform: scale(1.07, 0.9);   filter: brightness(1.6) blur(4px); }
  48%  { transform: scale(1.2, 0.4);    filter: brightness(1.3) blur(10px); }
  74%  { transform: scale(1.38, 0.07);  filter: brightness(0.6) blur(16px); }
  100% { transform: scale(1.55, 0.012); filter: brightness(0.04) blur(24px); opacity: 0; }
}
@keyframes crt-off-flash {
  0%   { opacity: 0; }
  40%  { opacity: 0.95; }   /* full monitor ramps up bright */
  55%  { opacity: 0.82; }
  100% { opacity: 0; }      /* then off */
}

/* Accessibility: no brightness strobes for reduced-motion users. Power on/off become calm
   fades and the full-screen flashes are suppressed (mirrors the takeover-soft pattern;
   the JS grain/flicker are gated in main.js on the same media query). */
@media (prefers-reduced-motion: reduce) {
  .stage.powering #crt { animation: crt-on-soft 480ms ease-out; }
  .stage.powering .crt-flash,
  .stage.powering-off .crt-flash { animation: none; opacity: 0; }
  .stage.powering-off #crtContent { animation: crt-off-soft 420ms ease-in forwards; }
  @keyframes crt-on-soft {
    from { filter: brightness(0); transform: none; }
    to   { filter: brightness(1); transform: none; }
  }
  @keyframes crt-off-soft {
    from { filter: brightness(1); opacity: 1; transform: none; }
    to   { filter: brightness(0); opacity: 0; transform: none; }
  }
}
