*,
*::after,
*::before {
  box-sizing: border-box;
  transform-style: preserve-3d;
}
body {
  perspective: 2000px;
  height: 100vh;
  height: 100dvh; /* mobile-aware viewport height - 100vh includes the area behind a collapsible address bar, which makes the page taller than what's actually visible and lets swipes pan it instead of scrolling the terminal */
  width: 100vw;
  margin: 0;
  background: radial-gradient(circle at 50% 50%, #305055 0%, #101720 100%);
  overflow: hidden;
  overscroll-behavior: none;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  flex-direction:column;
  font-family: 'Roboto';
  font-weight: 300
}

/* Applied via JS (visualViewport resize) when the on-screen keyboard is
   open, so the CRT isn't left sitting half-covered by it - shifts up just
   enough to clear the keyboard rather than jumping to the literal top.
   The JS also sets explicit inline width/height on .monitor when it needs
   to shrink to fit - aspect-ratio combined with width:auto doesn't
   reliably shrink below the terminal content's own intrinsic size, so
   this is computed directly instead of left to CSS to infer. */
body.keyboard-open {
  justify-content: flex-start;
  padding-top: 12px;
}

.monitor{
  --bezel-bottom: clamp(26px, 7vw, 80px);
  position:relative;
  width:min(94vw, 1040px);
  aspect-ratio:4 / 3;
}

:root{
  /* Green phosphor bloom - this is a monochrome terminal, not a color
     CRT/arcade tube, so there's deliberately no RGB aperture-grille mask
     or chromatic aberration here (a single electron gun can't mis-converge
     colors it never had). Bright pixels on a real phosphor screen bleed
     light into the dark area around them; drop-shadow's alpha-silhouette
     blur reproduces that halo cheaply since xterm's canvas is otherwise
     opaque to CSS glow tricks. */
  --phosphor-glow: drop-shadow(0 0 1px rgba(48,240,48,.55)) drop-shadow(0 0 3px rgba(48,240,48,.35)) drop-shadow(0 0 7px rgba(48,240,48,.16));
}

.crt{
  width:100%;
  height:100%;
  box-sizing:border-box;
  position:relative;
  border:clamp(14px, 3.6vw, 40px) solid #807760;
  border-bottom-width:var(--bezel-bottom);
  box-shadow:0 10px 15px #0007;
  border-radius:10px;
  background:#001000;
  font-family:'Courier New';
  padding:clamp(8px, 2vw, 20px);
  color:#30f030;
  overflow:hidden;
}

/* Purely a display toggle - the terminal underneath (session, history,
   cwd) keeps running untouched, same as a real monitor's power button
   not affecting the computer behind it. Resting "off" state only; the
   actual transition is the multi-stage crtPowerOff/crtPowerOn keyframe
   animations below, driven by the .powering-off/.powering-on classes
   terminal.js adds for the duration of the animation. */
.crt.screen-off{
  background-color:#000;
}
.crt.screen-off::before,
.crt.screen-off::after,
.crt.screen-off .crt-flicker,
.crt.screen-off .crt-glass{
  opacity:0;
}

#terminal{
  width:100%;
  height:100%;
  transform-origin:50% 50%;
  filter:var(--phosphor-glow);
}
.crt.screen-off #terminal{
  transform:scaleY(.012) scaleX(.001);
  opacity:0;
}
#terminal .xterm{
  height:100%;
  padding:0;
}
#terminal .xterm-viewport{
  background-color:transparent !important;
  overflow-y:hidden;
}
#terminal .xterm-screen{
  background-color:transparent;
}
.crt::before,.crt::after{
  content:'';
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  left:0;
  pointer-events:none;
  transition:opacity 0.2s;
}
.crt::before{
  background:linear-gradient(to bottom, #00000077 0px, #00000077 3px, #00000000 3px, #00000000 10px);
  background-size:10px 10px;
  background-repeat:repeat;
  background-position:0px 0px;
  animation: freq 5s infinite linear;
}
.crt::after{
  background:radial-gradient(#00000000 50%, #000000aa 100%)
}

@keyframes freq{
  0% {background-position:0px 0px}
  100% {background-position:0px 10px}
}

/* Old phosphor brightness dips - irregular, unevenly-spaced blips read as
   "aging monitor" much better than a smooth sine wave would. */
.crt-flicker{
  position:absolute;
  inset:0;
  pointer-events:none;
  background:#000;
  opacity:0;
  animation:flicker 6.3s infinite linear;
}
@keyframes flicker{
  0%,3%,5%,16%,18%,37%,39.5%,42%,61%,64%,80%,84%,100%{opacity:0}
  4%{opacity:.07}
  17%{opacity:.03}
  38%{opacity:.09}
  40.5%{opacity:.025}
  62.5%{opacity:.05}
  82%{opacity:.03}
}

/* Static diagonal sheen suggesting light glancing off curved glass -
   doesn't animate, just sits there the way a real reflection would. */
.crt-glass{
  position:absolute;
  inset:0;
  pointer-events:none;
  background:linear-gradient(115deg, rgba(255,255,255,.10) 0%, rgba(255,255,255,.03) 16%, transparent 30%, transparent 100%);
  mix-blend-mode:screen;
}

/* Occasional vertical-hold hiccup: a bright band rolls down the tube while
   the picture jitters, then settles. Triggered rarely and irregularly by
   terminal.js (not a fixed loop) so it reads as an analog fault, not a
   scripted effect. */
.crt-glitch{
  position:absolute;
  left:0;
  right:0;
  top:-20%;
  height:16%;
  pointer-events:none;
  background:linear-gradient(to bottom, transparent, rgba(255,255,255,.1) 45%, transparent 90%);
  opacity:0;
  mix-blend-mode:overlay;
}
.crt-glitch.active{
  opacity:1;
  animation:crtRoll 900ms linear;
}
@keyframes crtRoll{
  0%{top:-20%}
  100%{top:120%}
}
#terminal.glitching{
  animation:crtJitter 900ms linear;
}
@keyframes crtJitter{
  0%,45%,100%{transform:translateY(0)}
  10%{transform:translateY(-2px)}
  20%{transform:translateY(1px)}
  30%{transform:translateY(-1px)}
}

/* --- Power off/on: asymmetric on purpose, matching real CRT electronics.
   Cutting power collapses the raster to a bright line then a dot almost
   instantly (vertical deflection needs continuous drive current and dies
   first) before the tube goes dark - that part is fast, ~620ms. Powering
   back on is different: the deflection yoke reaches full scan size almost
   immediately, well before the cathode has heated up enough to emit a
   visible beam, so there's no reverse "dot growing outward" in real
   hardware - just a full-size, dark picture that fades up quickly (no
   scale change at all, just a brightness ramp) with a faint degauss
   skew wobble riding along. Both keyframe sets keep --phosphor-glow
   chained onto every filter stop so the bloom doesn't flatten out
   mid-animation. */
.crt.powering-off{
  animation:crtPowerOffGlow 620ms ease-out forwards;
}
.crt.powering-on{
  animation:crtPowerOnGlow 550ms ease-out forwards;
}
.crt.powering-off::before,
.crt.powering-off::after{
  animation:crtOverlayFadeOut 620ms ease-out forwards;
}
.crt.powering-on::before,
.crt.powering-on::after{
  animation:crtOverlayFadeIn 550ms ease-out forwards;
}
.crt.powering-off .crt-flicker,
.crt.powering-on .crt-flicker{
  opacity:0;
  animation-play-state:paused;
}
.crt.powering-off #terminal{
  animation:crtPowerOff 620ms cubic-bezier(.4,0,.7,1) forwards;
}
.crt.powering-on #terminal{
  animation:crtPowerOn 550ms ease-out forwards;
}

@keyframes crtOverlayFadeOut{
  0%{opacity:1}
  60%{opacity:.5}
  100%{opacity:0}
}
@keyframes crtOverlayFadeIn{
  0%{opacity:0}
  40%{opacity:.5}
  100%{opacity:1}
}

@keyframes crtPowerOff{
  0%   {transform:scaleY(1) scaleX(1);       filter:brightness(1) var(--phosphor-glow);   opacity:1}
  25%  {transform:scaleY(1) scaleX(1.03);    filter:brightness(2.4) var(--phosphor-glow); opacity:1}
  55%  {transform:scaleY(.012) scaleX(1.12); filter:brightness(3) var(--phosphor-glow);   opacity:1}
  82%  {transform:scaleY(.012) scaleX(.03);  filter:brightness(3) var(--phosphor-glow);   opacity:1}
  100% {transform:scaleY(.012) scaleX(.001); filter:brightness(0) var(--phosphor-glow);   opacity:0}
}
@keyframes crtPowerOn{
  0%   {transform:skewX(0deg);    filter:brightness(0) var(--phosphor-glow);   opacity:1}
  10%  {transform:skewX(.8deg);   filter:brightness(.2) var(--phosphor-glow);  opacity:1}
  30%  {transform:skewX(-.4deg);  filter:brightness(.55) var(--phosphor-glow); opacity:1}
  55%  {transform:skewX(.15deg);  filter:brightness(.8) var(--phosphor-glow);  opacity:1}
  100% {transform:skewX(0deg);    filter:brightness(1) var(--phosphor-glow);   opacity:1}
}
@keyframes crtPowerOffGlow{
  0%   {background-color:#001000}
  20%  {background-color:#daffda}
  55%  {background-color:#001a00}
  100% {background-color:#000}
}
@keyframes crtPowerOnGlow{
  0%   {background-color:#000}
  40%  {background-color:#001a00}
  100% {background-color:#001000}
}

.blink {
  animation: blinker 1s linear infinite;
}

@keyframes blinker {
  50% {
    opacity: 0;
  }
}
/* A sibling of .crt (not a child) positioned against .monitor instead,
   so .crt's own overflow:hidden (needed to contain the scanline/vignette
   effects) can't clip it. Anchored to the bottom bezel via --bezel-bottom
   (shared with .crt's border-bottom-width, both inherited from .monitor)
   so it stays centered in that strip and scales with the CRT at every
   size instead of drifting off the bezel like the old version did. */
.power-control{
  position:absolute;
  right:clamp(14px, 4vw, 40px);
  bottom:calc(var(--bezel-bottom) / 2);
  transform:translateY(50%);
  display:flex;
  align-items:center;
  gap:clamp(6px, 1.6vw, 14px);
  pointer-events:auto;
}

.power-led{
  width:clamp(7px, 1vw, 14px);
  height:clamp(7px, 1vw, 14px);
  border-radius:50%;
  background:#30f030;
  box-shadow:0 0 4px 1px #30f030cc, 0 0 1px #eaffea;
  transition:background 0.15s, box-shadow 0.15s;
}

.power-led.off{
  background:#1a3a1a;
  box-shadow:inset 0 0 2px #000a;
}

.power-btn{
  width:clamp(20px, 3vw, 52px);
  height:clamp(20px, 3vw, 52px);
  border-radius:50%;
  border:1px solid #5c5546;
  background:radial-gradient(circle at 35% 30%, #ded6bc 0%, #a89e82 45%, #6b6350 100%);
  box-shadow:0 2px 2px #00000055, inset 0 1px 1px #ffffff77;
  padding:0;
  cursor:pointer;
}

.power-btn:active{
  box-shadow:0 1px 1px #00000055, inset 0 1px 2px #00000088;
}

/* Old push-push CRT power switches latch in when on and click back out
   when off, rather than springing back after every press. */
.power-btn.pressed{
  background:radial-gradient(circle at 35% 30%, #8f8672 0%, #6b6350 60%, #55503f 100%);
  box-shadow:inset 0 2px 3px #00000099, inset 0 -1px 1px #ffffff22;
  transform:scale(0.94);
}
