/* =====================================================================
   DECKNFORGE — terminal
   Black screen. Cream phosphor. One font. No layout.
   ===================================================================== */

/* A real terminal was never one colour. Body text is the phosphor, --hi
   is the ANSI accent that headers, chips and choices are drawn in, and
   --red is for the red suits, because ♥ and ♦ have been red since 1480. */

:root {
  --bg:      #0a0805;
  --fg:      #efe3c4;   /* light cream */
  --hi:      #ffb01f;   /* hot amber */
  --red:     #ff5f4d;
  --pale:    #fffaf0;   /* ♠ ♣ — neutral in every palette */
  --dim:     #8d8266;
  --bright:  #fffaf0;
  --glow:    rgba(239, 227, 196, 0.30);
  --sel:     #efe3c4;
  --selfg:   #0a0805;

  --cell:    16px;      /* set by JS to fit 42 columns */
  --lh:      1.35;
  --pad:     0.75rem;
}

/* Palette switches ---------------------------------------------------- */
html[data-color='amber'] {
  --fg:     #ffb642;
  --hi:     #fff06a;
  --red:    #ff7a4d;
  --pale:   #ffe9bd;
  --dim:    #8a5f1d;
  --bright: #ffe9bd;
  --glow:   rgba(255, 182, 66, 0.30);
  --sel:    #ffb642;
}
html[data-color='green'] {
  --fg:     #6cff8f;
  --hi:     #d8ff4a;
  --red:    #ff6b6b;
  --pale:   #ccffd8;
  --dim:    #2f7a45;
  --bright: #ccffd8;
  --glow:   rgba(108, 255, 143, 0.28);
  --sel:    #6cff8f;
}
/* Mode 4 — the palette that made 1983 look like 1983. */
html[data-color='cga'] {
  --fg:     #e8e8f0;
  --hi:     #ff55ff;
  --red:    #ff5555;
  --pale:   #ffffff;
  --dim:    #7f6b86;
  --bright: #55ffff;
  --glow:   rgba(255, 85, 255, 0.30);
  --sel:    #ff55ff;
}

/* Not on the prefs screen until you find it. The blue every serious
   program booted into — the one palette here that isn't a phosphor. */
html[data-color='blue'] {
  --bg:     #0000a8;
  --fg:     #d7d7ff;
  --hi:     #ffff55;
  --red:    #ff8f8f;
  --pale:   #ffffff;
  --dim:    #7d7de0;
  --bright: #ffffff;
  --glow:   rgba(215, 215, 255, 0.22);
  --sel:    #ffff55;
  --selfg:  #0000a8;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--fg);
  overscroll-behavior: none;
}

body {
  font-family: 'DejaVu Sans Mono', 'Liberation Mono', 'Cascadia Mono',
               'Consolas', 'SF Mono', Menlo, 'Courier New', monospace;
  font-size: var(--cell);
  line-height: var(--lh);
  font-variant-ligatures: none;
  /* ♠ ▶ ▪ and friends must stay glyphs, never colour emoji. */
  font-variant-emoji: text;
  -webkit-font-smoothing: none;
  -webkit-text-size-adjust: 100%;
  text-rendering: optimizeSpeed;
}

::selection { background: var(--sel); color: var(--selfg); }

/* ---------------------------------------------------------------------
   Screen
   ------------------------------------------------------------------ */

/* The tube. Full-bleed on a phone; on a desktop it stops at 1200px and
   sits in the middle of the screen, because a terminal stretched across
   a 34-inch monitor is not a terminal, it is a spreadsheet. */
#term {
  position: fixed;
  inset: 0;
  width: 100%;
  max-width: 1200px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  padding-top: env(safe-area-inset-top);
  cursor: text;
  z-index: 1;
}

#scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  padding: var(--pad) var(--pad) 0;
  scrollbar-width: thin;
  scrollbar-color: var(--dim) transparent;
}
#scroll::-webkit-scrollbar { width: 6px; }
#scroll::-webkit-scrollbar-thumb { background: var(--dim); }
#scroll::-webkit-scrollbar-track { background: transparent; }

/* 80 columns, centred in whatever the tube turned out to be. */
#out { max-width: 80ch; margin-inline: auto; }

/* One row of the screen. Never reflows art. */
.ln {
  white-space: pre;
  min-height: calc(1em * var(--lh));
}
.ln.wrap { white-space: pre-wrap; }

/* Block/box-drawing art: character cells must touch, so no leading. */
.ln.blk { line-height: 1; min-height: 1em; }

.b   { color: var(--bright); }
.hi  { color: var(--hi); }

/* ANSI header bar: an inverse tag with the shade blocks fading off it. */
.ln.hd { color: var(--hi); }
.ln.hd .t { background: var(--hi); color: var(--bg); }

/* ♥ ♦ red, ♠ ♣ pale — the one place this screen has always had colour. */
.sr { color: var(--red); }
.sb { color: var(--pale); }
.d   { color: var(--dim); }
.rule { color: var(--dim); }

/* A full-width choice. The whole row is the tap target, sized for a
   thumb, so nothing on this terminal needs the keyboard. */
.ln.choice {
  white-space: pre-wrap;
  display: block;
  /* Never smaller than a fingertip, whatever the font scales to. */
  min-height: max(2.6em, 44px);
  padding: 0.55em var(--pad) 0.55em 0;
  color: var(--bright);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ln.choice .arrow { color: var(--hi); }
.ln.choice:active,
.ln.choice:focus-visible {
  background: var(--hi);
  color: var(--bg);
  outline: none;
}
/* Inverted, the whole row is one colour — arrow, suits, dim asides and
   all. Anything in a label that had its own colour gives it up. */
.ln.choice:active *,
.ln.choice:focus-visible * { color: inherit; }

@media (hover: hover) {
  .ln.choice:hover { background: var(--hi); color: var(--bg); }
  .ln.choice:hover * { color: inherit; }
}

/* Tappable command chip inside output */
.cmd {
  color: var(--bg);
  background: var(--hi);
  cursor: pointer;
  padding: 0;
}
.cmd:active { background: var(--bright); }

a, .lnk {
  color: var(--fg);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
a:active, .lnk:active { color: var(--bg); background: var(--fg); }

/* ---------------------------------------------------------------------
   Prompt line
   ------------------------------------------------------------------ */

#promptline {
  padding: 0 var(--pad) var(--pad);
  max-width: 80ch;
  margin-inline: auto;
  width: 100%;
  white-space: pre-wrap;
  word-break: break-word;
  position: relative;
}
#promptline[hidden] { display: none; }

/* The one line anybody types into. On a touch screen it gets its own
   size — a little above the output, so it reads at arm's length and
   takes a thumb without taking the wrong character. */
@media (pointer: coarse) {
  #promptline {
    font-size: 1.25em;
    /* ch follows this line's own font, so 64 of them is still the 80
       columns the output is measured in. */
    max-width: 64ch;
    padding-bottom: calc(var(--pad) + 0.15em);
  }
}

#ps1 { color: var(--fg); }
#typed { color: var(--bright); }
#hint { color: var(--dim); }

/* The prompt is the one tap that means "open the keyboard". */
#promptline { cursor: text; -webkit-tap-highlight-color: transparent; }

#cursor {
  display: inline-block;
  width: 0.6em;
  height: 1em;
  vertical-align: text-bottom;
  background: var(--fg);
  animation: blink 1.06s steps(1, end) infinite;
}
#cursor.hollow {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--fg);
}
@keyframes blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

/* The real input, parked invisibly under the rendered prompt. */
#kbd {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1.4em;
  opacity: 0;
  border: 0;
  padding: 0;
  margin: 0;
  background: transparent;
  color: transparent;
  font: inherit;
  font-size: 16px;     /* stops iOS from zooming on focus */
  caret-color: transparent;
  outline: none;
  z-index: 2;
}

/* ---------------------------------------------------------------------
   Soft keys — the thumb row
   ------------------------------------------------------------------ */

#keys {
  flex: 0 0 auto;
  display: flex;
  gap: 0;
  border-top: 1px solid var(--dim);
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--bg);
}
/* Keyboard up: the home indicator is under it, so stop leaving room. */
html[data-kbd='up'] #keys { padding-bottom: 0; }
#keys[hidden] { display: none; }

#keys button {
  flex: 1 1 0;
  min-width: 0;
  font: inherit;
  font-size: 0.86em;
  color: var(--fg);
  background: transparent;
  border: 0;
  border-right: 1px solid var(--dim);
  padding: 0.7em 0.1em;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
  -webkit-tap-highlight-color: transparent;
}
#keys button:last-child { border-right: 0; }
#keys button:active,
#keys button.on { background: var(--hi); color: var(--bg); }

/* ---------------------------------------------------------------------
   Phosphor burn

   Ten thousand hours of the same logo and the tube keeps a copy. Sits
   behind the text, in the glass, the way a screen that ran one program
   for a decade never quite goes black again. Only ever built by JS, and
   only for somebody who earned it.
   ------------------------------------------------------------------ */

/* Laid out exactly like #scroll and #out, at exactly the cell size, so
   the ghost sits where the logo itself sat. A watermark floating in the
   middle of the screen would be a logo; this is a scar. */
#burn {
  position: absolute;
  inset: 0;
  z-index: -1;                /* behind the text, in front of nothing */
  overflow: hidden;
  padding: var(--pad) var(--pad) 0;
  pointer-events: none;
  user-select: none;
}

#burn pre {
  max-width: 80ch;
  margin: 0 auto;
  font: inherit;
  font-size: var(--cell);
  line-height: 1;
  white-space: pre;
  color: var(--fg);
  opacity: 0.08;
}

/* ---------------------------------------------------------------------
   CRT
   ------------------------------------------------------------------ */

html[data-crt='on'] body { text-shadow: 0 0 5px var(--glow); }

#crt {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9;
  display: none;
}
html[data-crt='on'] #crt { display: block; }

#crt::before {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0px,
    rgba(0, 0, 0, 0) 2px,
    rgba(0, 0, 0, 0.26) 3px,
    rgba(0, 0, 0, 0.26) 4px
  );
}
#crt::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(
    ellipse at center,
    rgba(0, 0, 0, 0) 55%,
    rgba(0, 0, 0, 0.55) 100%
  );
  animation: flicker 5.2s infinite steps(1, end);
}
@keyframes flicker {
  0%, 96%  { opacity: 1; }
  97%      { opacity: 0.88; }
  98%      { opacity: 1; }
  99%      { opacity: 0.93; }
}

/* ---------------------------------------------------------------------
   A tube that reacts

   Three moments, all of them short: the switch-on, a flash when a roll
   lands well, and a twitch when the terminal disagrees with you.
   ------------------------------------------------------------------ */

#term { transform-origin: center; }

/* The flash sits over the text and under the scanlines. */
#term::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--fg);
  opacity: 0;
  pointer-events: none;
  z-index: 8;
}
#term.flash::after { animation: flash 0.36s ease-out 1; }
@keyframes flash {
  from { opacity: 0.4; }
  to   { opacity: 0; }
}

#term.glitch { animation: glitch 0.16s steps(2, end) 2; }
@keyframes glitch {
  0%   { transform: none; }
  25%  { transform: translate3d(-2px, 1px, 0) skewX(-0.6deg); }
  50%  { transform: translate3d(2px, -1px, 0) skewX(0.5deg); }
  75%  { transform: translate3d(-1px, 0, 0); }
  100% { transform: none; }
}

/* Switch-on: the picture opens out of a line, the way a CRT does. */
#term.poweron { animation: poweron 0.55s ease-out 1; }
@keyframes poweron {
  0%   { transform: scale(1.35, 0.004); filter: brightness(3);   opacity: 0.85; }
  35%  { transform: scale(1, 0.03);     filter: brightness(2.2); opacity: 1; }
  100% { transform: none; filter: none; }
}

@media (prefers-reduced-motion: reduce) {
  #cursor { animation: none; }
  #crt::after { animation: none; }
  #term.poweron,
  #term.glitch { animation: none; }
  #term.flash::after { animation: none; }
}

/* ---------------------------------------------------------------------
   No JavaScript
   ------------------------------------------------------------------ */

#nojs {
  padding: 2rem var(--pad);
  max-width: 60ch;
  white-space: pre-wrap;
}
#nojs pre { white-space: pre; overflow-x: auto; }
