/* ============================================================
   tty.css  ::  the terminal login, RobCo flavoured
   ------------------------------------------------------------
   Loaded only by pages/private.html, which uses the bare shell,
   so this owns the whole window.

   Modelled on the Fallout: New Vegas terminals. What makes those
   read the way they do, in the order the eye notices it:

     1. BLOOM. Enormous, far past what a real CRT did. The glyphs
        bleed several pixels of green into everything around them
        and the whole tube glows. This is the single biggest
        thing; get it too subtle and it just looks like green
        text on black.
     2. CURVATURE. The picture is a bowed tube, dark and soft at
        the corners, brightest in the middle.
     3. SCANLINES, heavier than a real display, plus a bright
        band that sweeps slowly down the screen.
     4. Text that TYPES OUT rather than appearing, one character
        at a time. That is in js/tty.js.

   Real barrel distortion needs SVG filters or 3D transforms that
   Safari 7 cannot do, so the curve is faked with a heavily
   rounded frame, an inset shadow for the tube edge, and a
   radial falloff. At this scale the eye accepts it.

   Monochrome on purpose, failures included. A real terminal had
   one colour of phosphor, and a red error would be the one
   detail that gave the whole thing away.

   Safari 7 rules: no grid, no flexbox gap, no :has(), prefixes
   on every gradient, transform and animation.
   ============================================================ */

*,
*:before,
*:after {
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}

html.logon-root { background: #01070300; background-color: #010703; }

/* ------------------------------------------------------------
   PAGES SERVER CORE IS DRIVEN BY THE KEYBOARD
   ------------------------------------------------------------
   No mouse pointer at all, because there is nothing here for it
   to point at. A serial console never had one: the machine has no
   graphical shell, which is the entire reason this screen looks
   the way it does rather than looking like the Aero site.

   Hiding the pointer is not decoration, it is the instruction.
   A visible arrow on a screen where clicking achieves nothing is
   an invitation to click things and find out that nothing
   happens, which reads as broken. No arrow reads as "type".

   IT COMES BACK THE MOMENT A WINDOW OPENS. js/win98.js adds
   has-gui to <html> when it draws one, and a Command Prompt you
   can drag by its title bar plainly does need a pointer. That is
   the line: console, keyboard; window, mouse.
   ------------------------------------------------------------ */
body.tty-body {
  margin: 0;
  padding: 0;
  background: #010703;
  overflow: hidden;
  cursor: none;
}

html.has-gui body.tty-body,
html.has-gui .tty,
html.has-gui .tty__screen {
  cursor: url("../img/cursors/normal.png") 0 0, default;
}


/* ---------- the tube turning on --------------------------------
   A CRT does not fade up. The gun fires before the deflection
   coils have anything to deflect, so for a fraction of a second
   the whole picture is one bright horizontal line across the
   middle of the tube, and then it snaps open vertically.

   Two stages, which is what makes it read as a tube rather than
   as a box growing:

     1. a white line, full width, one pixel tall, very bright
     2. the line opens out to full height, overshooting slightly,
        while the brightness falls back to normal

   scaleY plus a brightness wash, both of which Safari 7 can do
   with -webkit- prefixes. No filter: brightness(), which is
   Safari 9 and would simply not run on the machine this is for.
   ------------------------------------------------------------ */
.tty__glass.is-waking {
  -webkit-animation: ttywake 620ms ease-out 1;
          animation: ttywake 620ms ease-out 1;
}

@-webkit-keyframes ttywake {
  0%   { -webkit-transform: scaleY(0.004); background-color: #eafff2; }
  22%  { -webkit-transform: scaleY(0.004); background-color: #eafff2; }
  55%  { -webkit-transform: scaleY(1.06);  background-color: #9dffc4; }
  75%  { -webkit-transform: scaleY(0.98);  background-color: #2c8f52; }
  100% { -webkit-transform: scaleY(1);     background-color: #04170b; }
}
@keyframes ttywake {
  0%   { transform: scaleY(0.004); background-color: #eafff2; }
  22%  { transform: scaleY(0.004); background-color: #eafff2; }
  55%  { transform: scaleY(1.06);  background-color: #9dffc4; }
  75%  { transform: scaleY(0.98);  background-color: #2c8f52; }
  100% { transform: scaleY(1);     background-color: #04170b; }
}

/* The text must not be readable through the flash, or the effect
   reads as a coloured wash over a page rather than as a screen
   coming on with nothing on it yet. */
.tty__glass.is-waking .tty__screen,
.tty__glass.is-waking .tty__scan,
.tty__glass.is-waking .tty__sweep,
.tty__glass.is-waking .tty__vignette { opacity: 0; }


/* ---------- the tube ------------------------------------------
   The outer element is the cabinet; the inner screen is inset
   and rounded so its edges read as glass curving away. */
.tty {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  overflow: hidden;
  background: #010703;
  padding: 2.2vh 2.2vw;
}

.tty__glass {
  position: absolute;
  top: 2.2vh; left: 2.2vw; right: 2.2vw; bottom: 2.2vh;
  overflow: hidden;

  -webkit-border-radius: 3.2vw / 4.5vh;
          border-radius: 3.2vw / 4.5vh;

  background-color: #04170b;
  background-image:
    -webkit-radial-gradient(50% 46%, ellipse, rgba(20,120,55,.34) 0%, rgba(6,30,14,0) 72%);
  background-image:
    radial-gradient(ellipse at 50% 46%, rgba(20,120,55,.34) 0%, rgba(6,30,14,0) 72%);

  /* the tube edge: light falls off hard into the bezel */
  -webkit-box-shadow:
    inset 0 0 7vw 3vw rgba(0,0,0,.92),
    inset 0 0 2vw .6vw rgba(0,0,0,.75),
    0 0 5vw rgba(30,200,90,.16);
          box-shadow:
    inset 0 0 7vw 3vw rgba(0,0,0,.92),
    inset 0 0 2vw .6vw rgba(0,0,0,.75),
    0 0 5vw rgba(30,200,90,.16);
}


/* ---------- the text ------------------------------------------ */
.tty__screen {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  padding: 5vh 5vw;

  /* SCROLLBACK. This was overflow: hidden, and js/tty.js has always
     ended draw() with out.scrollTop = out.scrollHeight, so new output
     did scroll into view. What you could not do was go back: help
     prints more commands than fit on a screen, the top of the list
     went above the first row, and the wheel had nothing to move
     because the box was not scrollable.

     A real VT of this era had exactly this problem and answered it
     with Shift+PageUp, which js/tty.js now handles as well. */
  overflow-y: auto;
  overflow-x: hidden;

  font-family: "Lucida Console", Consolas, Monaco, "Courier New", monospace;
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: .06em;
  color: #2bff7c;

  /* THE BLOOM. Deliberately far past a real tube.

     THREE LAYERS, NOT FIVE. There used to be a 26px and a 48px
     pass on the end of this list. A blurred text-shadow is
     rasterised per glyph on the CPU, and the cost climbs with the
     radius, so those two were the most expensive thing on the
     page: a full screen of monospace text, every glyph blurred
     five times, re-rendered on every keystroke because draw()
     rewrites the whole buffer.

     The wide passes were doing the room-glow job that
     .tty__glass already does ONCE, as a static radial gradient
     that never re-rasterises. The near passes are what actually
     read as phosphor. Dropping the far two costs almost nothing
     visually and takes the per-glyph work down by two fifths. */
  text-shadow:
    0 0 1px rgba(43,255,124,1),
    0 0 4px rgba(43,255,124,.95),
    0 0 11px rgba(30,230,105,.75);

  white-space: pre-wrap;
  word-wrap: break-word;
}

/* A default scrollbar on a phosphor terminal looks like exactly what
   it is, a browser widget sitting on top of the illusion. This makes
   it a thin green track that belongs to the tube.

   Safari 7 supports the -webkit- pseudo elements, so this is the one
   place where the prefixed form is the only form. Anything that does
   not understand them gets a normal scrollbar, which still works. */
.tty__screen::-webkit-scrollbar {
  width: 10px;
}

.tty__screen::-webkit-scrollbar-track {
  background: rgba(20, 90, 45, .18);
}

.tty__screen::-webkit-scrollbar-thumb {
  background: rgba(43, 255, 124, .30);
  border: 2px solid transparent;
  background-clip: padding-box;
}

.tty__screen::-webkit-scrollbar-thumb:hover {
  background: rgba(43, 255, 124, .55);
  background-clip: padding-box;
}


.tty__dim { color: #17a352; }

.tty__hi {
  color: #c6ffdc;
  /* Same again: the 44px pass sat on top of the five below it. */
  text-shadow:
    0 0 2px rgba(198,255,220,1),
    0 0 7px rgba(140,255,180,.9),
    0 0 20px rgba(60,235,120,.6);
}

/* a selected menu row, drawn as inverse video the way the games
   and every real terminal did it */
.tty__sel {
  background: #2bff7c;
  color: #04170b;
  text-shadow: none;
}


/* ---------- the block cursor ---------------------------------- */
/* THE CURSOR AND THE SELECTION MUST BE THE SAME HEIGHT.

   They are both meant to be one character cell. The selection is
   an ordinary inline background, so its box is the font's own
   content box: at 16px in this face that is 19px, or 1.1875em.
   The cursor was 1.05em, which left it visibly shorter than a
   highlight sitting right next to it.

   Matching them by hand rather than by some shared unit, because
   the font decides the first number and CSS has no way to ask it
   what that number is. */
.tty__cursor {
  display: inline-block;
  width: .58em;
  height: 1.1875em;
  vertical-align: -.25em;
  background: #2bff7c;
  -webkit-box-shadow: 0 0 6px rgba(43,255,124,.95), 0 0 16px rgba(30,220,100,.6);
          box-shadow: 0 0 6px rgba(43,255,124,.95), 0 0 16px rgba(30,220,100,.6);
  -webkit-animation: ttyblink 1.05s steps(1) infinite;
          animation: ttyblink 1.05s steps(1) infinite;
}
@-webkit-keyframes ttyblink {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}
@keyframes ttyblink {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}

/* while a request is in flight the cursor sits solid, because
   the terminal is waiting on the far end rather than on you */
.tty__cursor.is-waiting {
  -webkit-animation: none;
          animation: none;
  opacity: 1;
}

/* AND SOLID WHILE YOU ARE ACTUALLY TYPING.

   A blinking cursor means "waiting for you". The moment you start
   typing it is not waiting for anything, and a caret that keeps
   flashing under your own keystrokes reads as a stutter: half the
   characters you type land while it is in its invisible half.

   So it goes solid on a keystroke and starts blinking again after
   a short pause. Every real terminal and text editor does this and
   almost nobody notices, which is exactly the point. */
.tty__cursor.is-typing {
  -webkit-animation: none;
          animation: none;
  opacity: 1;
}


/* ---------- scanlines ------------------------------------------
   Heavier than a real display. Sits above the text and never
   takes a click, so the hidden input underneath keeps focus. */
.tty__scan {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  pointer-events: none;
  z-index: 4;
  background-image: -webkit-repeating-linear-gradient(top,
    rgba(0,0,0,.42) 0px, rgba(0,0,0,.42) 1px,
    rgba(0,0,0,0) 1px, rgba(0,0,0,0) 3px);
  background-image: repeating-linear-gradient(to bottom,
    rgba(0,0,0,.42) 0px, rgba(0,0,0,.42) 1px,
    rgba(0,0,0,0) 1px, rgba(0,0,0,0) 3px);
}

/* the bright band drifting down the screen */
.tty__sweep {
  position: absolute;
  left: 0; right: 0;
  top: -30%;
  height: 26%;
  pointer-events: none;
  z-index: 5;
  background-image: -webkit-linear-gradient(top,
    rgba(80,255,150,0) 0%,
    rgba(80,255,150,.05) 45%,
    rgba(140,255,190,.10) 55%,
    rgba(80,255,150,0) 100%);
  background-image: linear-gradient(to bottom,
    rgba(80,255,150,0) 0%,
    rgba(80,255,150,.05) 45%,
    rgba(140,255,190,.10) 55%,
    rgba(80,255,150,0) 100%);
  -webkit-animation: ttysweep 7.5s linear infinite;
          animation: ttysweep 7.5s linear infinite;
}
@-webkit-keyframes ttysweep {
  from { -webkit-transform: translateY(0); }
  to   { -webkit-transform: translateY(520%); }
}
@keyframes ttysweep {
  from { transform: translateY(0); }
  to   { transform: translateY(520%); }
}

/* the corners of a bowed tube are dimmer than its middle */
.tty__vignette {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  pointer-events: none;
  z-index: 4;
  background-image:
    -webkit-radial-gradient(50% 50%, ellipse, rgba(0,0,0,0) 42%, rgba(0,0,0,.88) 100%);
  background-image:
    radial-gradient(ellipse at 50% 50%, rgba(0,0,0,0) 42%, rgba(0,0,0,.88) 100%);
}

/* the whole picture never sits perfectly still */
.tty__flicker {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  pointer-events: none;
  z-index: 4;
  background: rgba(60,255,130,.03);
  -webkit-animation: ttyflicker 4.2s ease-in-out infinite;
          animation: ttyflicker 4.2s ease-in-out infinite;
}
@-webkit-keyframes ttyflicker {
  0%, 100% { opacity: .3; }
  18%      { opacity: .85; }
  41%      { opacity: .15; }
  63%      { opacity: .7; }
  82%      { opacity: .35; }
}
@keyframes ttyflicker {
  0%, 100% { opacity: .3; }
  18%      { opacity: .85; }
  41%      { opacity: .15; }
  63%      { opacity: .7; }
  82%      { opacity: .35; }
}


/* ---------- the real inputs -----------------------------------
   Genuine form fields, visually hidden but focusable and still in
   the document.

   NOT display:none and NOT visibility:hidden, because both make a
   field unfocusable and invisible to password managers. Keeping
   them real keeps typing, autofill, IME input, accessibility and
   the browser's own password handling working, while what you SEE
   is the text the terminal draws.

   Separate fields rather than one that changes type, because
   password managers key off autocomplete="username",
   autocomplete="current-password" and autocomplete="one-time-code"
   being on distinct inputs.

   ------------------------------------------------------------
   WHY THEY ARE PARKED OFF SCREEN RATHER THAN LAID OVER THE TUBE
   ------------------------------------------------------------

   They used to sit transparently across the whole screen, held
   invisible by color:transparent plus caret-color:transparent.

   caret-color is Safari 16. On Safari 7 and Safari 11, the two
   browsers this site is actually built for, it is ignored
   completely. The field went transparent and its blinking system
   caret DID NOT, so both target Macs would have shown a real
   caret flashing on top of the drawn green block. Two cursors,
   permanently, on the machines that matter most.

   Moving the field off screen fixes it everywhere at once and
   needs no property newer than 1996. Focus, typing, autofill and
   screen readers all still work, because the element is still
   rendered and still in the tab order; it simply is not where you
   are looking.

   Clicking still focuses it, because .tty (the whole tube) has a
   click handler that calls focusField(). That existed already for
   other reasons and now carries this too.

   left is a large negative number rather than a percentage so it
   clears the viewport at any window size. It stays 1em tall and
   wide rather than collapsing to nothing, because a zero sized
   input is treated as hidden by some engines and drops out of the
   accessibility tree.                                           */
.tty__input {
  position: fixed;
  top: 0;
  left: -9999px;
  width: 1em;
  height: 1em;
  padding: 0;
  border: 0;
  outline: none;
  background: transparent;
  color: transparent;
  font-family: inherit;
  font-size: 16px;              /* stops mobile Safari zooming on focus */
  z-index: 3;
}
.tty__input::-webkit-input-placeholder { color: transparent; }

/* The field not in use must not be able to take the caret.

   THE TAB ORDER IS NOT DONE HERE, and this comment used to claim it
   was. Neither of these properties has any effect on tabbing:
   z-index is paint order, and pointer-events is the mouse. All four
   fields stayed in the sequence, so Tab at the login prompt put the
   real caret in the hidden Password field while the drawn caret
   stayed put, and everything typed afterwards went nowhere visible.

   focusField() in js/tty.js sets tabIndex now, which is the only
   thing that actually does this. What is left here is what these
   two properties are genuinely good for: keeping the off screen
   field from being clicked, and from painting over anything. */
.tty__input.is-off {
  z-index: -1;
  pointer-events: none;
}

/* The submit button that makes Enter work. Hidden, but RENDERED:
   a display:none button does not count for implicit submission
   in every engine, and without a counted submit button a form
   with more than one field ignores Enter entirely. */
.tty__go {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  opacity: 0;
  overflow: hidden;
  background: transparent;
  z-index: -1;
}

/* ---------- selection -----------------------------------------
   Ctrl+A selects the SCREEN text, so it has to be selectable even
   though a hidden input is what holds focus.

   text-shadow: none IS LOAD BEARING. The screen text carries a
   five layer green bloom, and a selection highlight underneath
   that bloom is a smear rather than a highlight: the glow spills
   over the edges of the block and the inverted text stays fuzzy.
   Dropping the shadow on the selected run is what makes a
   selection actually readable on this screen.

   The colours are the same inverse video the menus use, so
   selecting text and highlighting a menu row look like the same
   machine doing the same thing.                                 */
.tty__screen {
  -webkit-user-select: text;
     -moz-user-select: text;
          user-select: text;
}
.tty__screen ::-moz-selection,
.tty__screen::-moz-selection {
  background: #2bff7c;
  color: #04170b;
  text-shadow: none;
}
.tty__screen ::selection,
.tty__screen::selection {
  background: #2bff7c;
  color: #04170b;
  text-shadow: none;
}


/* ---------- burn in --------------------------------------------
   Left alone for a few minutes, the picture starts to ghost.

   Phosphor burn is what actually happened to a terminal somebody
   walked away from: the image stops being crisp, dims, and leaves
   a faint afterglow of itself. It is cheaper than a screensaver,
   it needs no extra element, and it is far more unsettling,
   because the screen is not doing something else, it is decaying.

   A single transition on opacity and a text-shadow smear. Both
   come off the instant you touch a key, and js/tty.js is what
   adds and removes the class. */
.tty__screen {
  -webkit-transition: opacity 8s linear;
          transition: opacity 8s linear;
}

.tty.is-burned .tty__screen {
  opacity: .38;
}

.tty.is-burned .tty__glass {
  -webkit-box-shadow:
    inset 0 0 7vw 3vw rgba(0,0,0,.96),
    inset 0 0 2vw .6vw rgba(0,0,0,.85),
    0 0 5vw rgba(30,200,90,.06);
          box-shadow:
    inset 0 0 7vw 3vw rgba(0,0,0,.96),
    inset 0 0 2vw .6vw rgba(0,0,0,.85),
    0 0 5vw rgba(30,200,90,.06);
}


/* ---------- reduced motion -------------------------------------
   The blink, the sweep and the flicker are all movement for its
   own sake, so they stop. The cursor stays visible so you can
   still see where you are typing; it simply stops blinking.

   THE TEXT KEEPS TYPING. prefers-reduced-motion is about things
   that move, and text arriving in order is content appearing,
   not the screen moving. js/tty.js types faster under this
   setting rather than not at all, because the typing is the
   single most recognisable thing this screen does and taking it
   away leaves nothing but green text on black. */

  /* The tube comes on without the snap. It is a scale transform,
     which is exactly the kind of movement this setting is asking
     to be spared. */
html.motion-off .tty__glass.is-waking {
  -webkit-animation: none !important;
          animation: none !important;
}
  html.motion-off .tty__glass.is-waking .tty__screen,
html.motion-off .tty__glass.is-waking .tty__scan,
html.motion-off .tty__glass.is-waking .tty__sweep,
html.motion-off .tty__glass.is-waking .tty__vignette { opacity: 1; }

  html.motion-off .tty__flicker,
html.motion-off .tty__sweep {
    -webkit-animation: none !important;
            animation: none !important;
  }

  /* Burn in still happens, it just does not fade into it. The
     dimming is the point; the eight second cross fade is the
     movement. */
html.motion-off .tty__screen {
  -webkit-transition: none !important;
          transition: none !important;
}
  html.motion-off .tty__flicker { opacity: .3; }
  html.motion-off .tty__sweep { display: none; }

  /* THE CURSOR STILL BLINKS, and that is not an oversight.

     prefers-reduced-motion is about animation: things that slide,
     sweep, spin and parallax. A blinking text caret is none of
     those, it is the oldest interface convention there is, and
     every operating system keeps blinking its caret with this
     setting turned on. macOS and Windows both do.

     An earlier version killed it here along with the sweep, which
     meant the person who set the preference got a terminal whose
     cursor never moved: the one piece of feedback telling you the
     machine is waiting for you rather than hung. */

