/* ==========================================================================
   DEMONIC playground — terminal chrome + runtime theme system.
   --------------------------------------------------------------------------
   Themes are runtime CSS custom properties on <body data-theme="…">.
   Every theme defines the same 8 slots:
     --bg      screen background
     --fg      body text (readable, ≥4.5:1 on --bg)
     --dim     secondary/muted text, borders, scrollbar
     --accent  prompt user@host, highlights, cursor tint
     --warn    warnings
     --crit    errors / ACCESS DENIED
     --rain    matrix-rain glyph color (read by effects.js)
     --glow    phosphor bloom color (translucent)
   Default (no/unknown data-theme) = refined-green.
   CRT layers live on #screen and are disabled by body.crt-off and, for the
   motion-bearing parts (flicker, curvature), by prefers-reduced-motion.
   ========================================================================== */

/* ---- Type ---------------------------------------------------------------- */

@font-face {
  font-family: "JetBrains Mono";
  src: url("jetbrains-mono.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

/* ---- Theme catalog ------------------------------------------------------- */

/* refined-green — the default. Green is the accent, not the wallpaper:
   soft off-white body text on near-black with a green undertone. */
body {
  --bg:     #0b0f0d;
  --fg:     #d7e0d9;
  --dim:    #71806f;
  --accent: #38d98a;
  --warn:   #e8c268;
  --crit:   #e0604f;
  --rain:   #38d98a;
  --glow:   rgba(56, 217, 138, 0.40);
  color-scheme: dark;
}
body[data-theme="refined-green"] {
  --bg: #0b0f0d; --fg: #d7e0d9; --dim: #71806f; --accent: #38d98a;
  --warn: #e8c268; --crit: #e0604f; --rain: #38d98a;
  --glow: rgba(56, 217, 138, 0.40);
}

/* light — plain non-hacker skin: white paper, ink text, no phosphor bloom
   (glow transparent → text-shadow renders nothing). */
body[data-theme="light"] {
  --bg: #f5f6f7; --fg: #1f2328; --dim: #586069; --accent: #0969da;
  --warn: #9a6700; --crit: #cf222e; --rain: #c7ccd1;
  --glow: rgba(0, 0, 0, 0);
}

/* dark — plain non-hacker skin: slate bg, soft text, no neon glow. */
body[data-theme="dark"] {
  --bg: #1c2128; --fg: #e6edf3; --dim: #8b949e; --accent: #4493f8;
  --warn: #d29922; --crit: #f85149; --rain: #444c56;
  --glow: rgba(0, 0, 0, 0);
}

/* matrix-green — the saturated classic. Green wall, unapologetic. */
body[data-theme="matrix-green"] {
  --bg: #010401; --fg: #28fe63; --dim: #0f7c34; --accent: #8dffb0;
  --warn: #d8ff5e; --crit: #ff5c39; --rain: #00ff41;
  --glow: rgba(0, 255, 65, 0.55);
}

/* amber — P3 phosphor, VT220 after midnight. */
body[data-theme="amber"] {
  --bg: #120b01; --fg: #ffb000; --dim: #93641a; --accent: #ffd75e;
  --warn: #ffe08a; --crit: #ff6b4a; --rain: #ffb000;
  --glow: rgba(255, 176, 0, 0.45);
}

/* white-phosphor — P4 mono, lab terminal. */
body[data-theme="white-phosphor"] {
  --bg: #0a0a0a; --fg: #e6e6e6; --dim: #7c7c7c; --accent: #ffffff;
  --warn: #e8c268; --crit: #e0604f; --rain: #cfcfcf;
  --glow: rgba(230, 230, 230, 0.38);
}

/* c64-blue — READY. the one light-on-mid classic. */
body[data-theme="c64-blue"] {
  --bg: #40318d; --fg: #c8c4f4; --dim: #8a82d8; --accent: #ffffff;
  --warn: #f0d858; --crit: #ff7a68; --rain: #8a80e8;
  --glow: rgba(165, 161, 224, 0.50);
}

/* arch — btw. Arch cyan on cool slate. */
body[data-theme="arch"] {
  --bg: #0c1219; --fg: #d4dde6; --dim: #5f7183; --accent: #1793d1;
  --warn: #e8c268; --crit: #e0604f; --rain: #1793d1;
  --glow: rgba(23, 147, 209, 0.45);
}

/* gentoo — compiled overnight. Gentoo purples (#54487a family). */
body[data-theme="gentoo"] {
  --bg: #100d17; --fg: #ddd8ec; --dim: #6f6890; --accent: #9c86e0;
  --warn: #e8c268; --crit: #e0604f; --rain: #6e56af;
  --glow: rgba(110, 86, 175, 0.50);
}

/* dracula */
body[data-theme="dracula"] {
  --bg: #282a36; --fg: #f8f8f2; --dim: #6272a4; --accent: #bd93f9;
  --warn: #f1fa8c; --crit: #ff5555; --rain: #50fa7b;
  --glow: rgba(189, 147, 249, 0.45);
}

/* nord */
body[data-theme="nord"] {
  --bg: #2e3440; --fg: #e5e9f0; --dim: #7b88a1; --accent: #88c0d0;
  --warn: #ebcb8b; --crit: #bf616a; --rain: #81a1c1;
  --glow: rgba(136, 192, 208, 0.40);
}

/* gruvbox */
body[data-theme="gruvbox"] {
  --bg: #282828; --fg: #ebdbb2; --dim: #928374; --accent: #fe8019;
  --warn: #fabd2f; --crit: #fb4934; --rain: #b8bb26;
  --glow: rgba(254, 128, 25, 0.40);
}

/* tokyo-night */
body[data-theme="tokyo-night"] {
  --bg: #1a1b26; --fg: #c0caf5; --dim: #737aa2; --accent: #7aa2f7;
  --warn: #e0af68; --crit: #f7768e; --rain: #bb9af7;
  --glow: rgba(122, 162, 247, 0.45);
}

/* catppuccin-mocha */
body[data-theme="catppuccin-mocha"] {
  --bg: #1e1e2e; --fg: #cdd6f4; --dim: #7f849c; --accent: #cba6f7;
  --warn: #f9e2af; --crit: #f38ba8; --rain: #94e2d5;
  --glow: rgba(203, 166, 247, 0.42);
}

/* solarized-dark */
body[data-theme="solarized-dark"] {
  --bg: #002b36; --fg: #9fb2b2; --dim: #657b83; --accent: #268bd2;
  --warn: #b58900; --crit: #dc322f; --rain: #2aa198;
  --glow: rgba(42, 161, 152, 0.40);
}

/* synthwave — neon over deep violet. */
body[data-theme="synthwave"] {
  --bg: #190b2b; --fg: #f2e7ff; --dim: #8a6bb8; --accent: #ff4fd8;
  --warn: #ffd166; --crit: #ff2a6d; --rain: #ff4fd8;
  --glow: rgba(255, 79, 216, 0.55);
}

/* cyberpunk — cyan + signal yellow on asphalt. */
body[data-theme="cyberpunk"] {
  --bg: #0a0a12; --fg: #dff4ff; --dim: #57798c; --accent: #00f0ff;
  --warn: #fcee0a; --crit: #ff003c; --rain: #00f0ff;
  --glow: rgba(0, 240, 255, 0.50);
}

/* hacker-red — alarm-lit basement. */
body[data-theme="hacker-red"] {
  --bg: #0c0203; --fg: #ff6b5e; --dim: #ad4a3f; --accent: #ff2020;
  --warn: #ffb35c; --crit: #ff2020; --rain: #ff3333;
  --glow: rgba(255, 51, 51, 0.55);
}

/* plasma — the Konami unlock. Violet base; the rainbow is earned in JS. */
body[data-theme="plasma"] {
  --bg: #0b0716; --fg: #f2ecff; --dim: #7d6f9e; --accent: #b26bff;
  --warn: #ffd166; --crit: #ff2a6d; --rain: #b26bff;
  --glow: rgba(178, 107, 255, 0.55);
}

/* solarized-light — “paper”, the real light mode. Phosphor effects stay shy. */
body[data-theme="solarized-light"] {
  --bg: #fdf6e3; --fg: #586e75; --dim: #78898b; --accent: #1d6fa8;
  --warn: #8f6c00; --crit: #dc322f; --rain: #93a1a1;
  --glow: rgba(29, 111, 168, 0.18);
  color-scheme: light;
}

/* inferno — The Breach ROOT prize. Ember red over near-black; earned only
   by taking root (gated behind breach>=5 in themes.js). Swatches mirror the
   THEMES entry in themes.js — change BOTH if you touch the palette. */
body[data-theme="inferno"] {
  --bg: #0a0203; --fg: #ff5c42; --dim: #7a2a1e; --accent: #ff2a12;
  --warn: #ffab5c; --crit: #fff0e6; --rain: #ff3b18;
  --glow: rgba(255, 42, 18, 0.55);
}

/* ---- Z scale (semantic, no arbitrary values) ------------------------------ */

:root {
  --z-rain: 0;
  --z-term: 1;
  --z-chip: 1; /* the login chip lives on the tube: boot covers it, CRT scanlines wash over it */
  --z-boot: 2;
  --z-crt:  3;
  /* #login-modal needs no slot — native <dialog> promotes to the top layer */
}

/* ---- Base / reset --------------------------------------------------------- */

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

html, body {
  height: 100%;
  margin: 0;
}

body {
  background: #000; /* bezel behind the curved tube */
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: clamp(13px, 2.4vw, 15.5px);
  line-height: 1.5;
  overflow: hidden; /* the screen owns scrolling */
}

::selection {
  background: var(--accent);
  color: var(--bg);
}

/* ---- The screen ------------------------------------------------------------ */

#screen {
  position: fixed;
  inset: 0;
  background: var(--bg);
  color: var(--fg);
  overflow: hidden;
  transition: background-color 240ms cubic-bezier(0.22, 1, 0.36, 1),
              color 240ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* Theme swap: recolor instantly (no 240ms cross-fade smear) and freeze the
   CRT flicker for the two frames the swap paints, so the full-screen
   compositor layer isn't re-rasterized mid opacity-animation — kills the
   "GPU flash/blink" on theme change. themes.js toggles this class. The
   `.theme-switching.crt` compound outranks `body.crt #screen` (which sets the
   flicker animation later in this file) so `animation: none` actually wins. */
body.theme-switching #screen {
  transition: none;
}
body.theme-switching.crt #screen {
  transition: none;
  animation: none;
}

/* rain canvas sits behind the text, ambient only */
#rain {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: var(--z-rain);
  pointer-events: none;
  opacity: 0.5;
}

/* ---- Terminal -------------------------------------------------------------- */

#term {
  position: absolute;
  inset: 0;
  z-index: var(--z-term);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: clamp(14px, 3vmin, 36px);
  padding-bottom: max(clamp(14px, 3vmin, 36px), env(safe-area-inset-bottom));
  scrollbar-width: thin;
  scrollbar-color: var(--dim) transparent;
  -webkit-tap-highlight-color: transparent;
}

#boot {
  position: absolute;
  inset: 0;
  z-index: var(--z-boot);
  overflow-y: auto;
  padding: clamp(14px, 3vmin, 36px);
  background: var(--bg);
}
#boot[hidden] { display: none; }

/* scrollback lines */
.t-line {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  min-height: 1.5em; /* blank lines keep their height */
}

/* ASCII art / banners: never wrap, scale down instead of overflowing */
.t-pre {
  margin: 0;
  font: inherit;
  white-space: pre;
  overflow-x: auto;
  color: var(--accent);
  text-shadow: 0 0 10px var(--glow);
}
@media (max-width: 480px) {
  .t-pre { font-size: 0.72em; line-height: 1.35; }
}

/* semantic tones */
.t-accent { color: var(--accent); text-shadow: 0 0 8px var(--glow); }
.t-dim    { color: var(--dim); }
.t-warn   { color: var(--warn); }
.t-crit   { color: var(--crit); }

/* ---- Input line ------------------------------------------------------------ */

.input-line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  min-height: 1.5em;
}

/* display:flex beats the hidden attribute — restore it. Programs (the theme
   picker, the arcade) hide the input via setInputVisible(false). */
.input-line[hidden] {
  display: none;
}

.t-prompt {
  white-space: pre;
  user-select: none;
}
.t-prompt .p-user { color: var(--accent); text-shadow: 0 0 8px var(--glow); }
.t-prompt .p-path { color: var(--dim); }
.t-prompt .p-sigil { color: var(--fg); }

/* The Breach: once you're root, the prompt burns red (root@demonic:…#). The
   modifier outweighs the base rules above; it rides both the live prompt and
   the echoed history lines, so a reloaded rooted session looks right too. */
.t-prompt .p-user.is-root { color: var(--crit); text-shadow: 0 0 10px var(--glow); }
.t-prompt .p-sigil.is-root { color: var(--crit); }

/* typed-so-far text (REPL fills this in a later slice) */
.t-typed { white-space: pre-wrap; overflow-wrap: break-word; }

/* the blinking block cursor */
.t-cursor {
  display: inline-block;
  width: 1ch;
  height: 1.15em;
  transform: translateY(0.18em);
  background: var(--fg);
  box-shadow: 0 0 10px var(--glow);
  animation: cursor-blink 1.06s steps(1, end) infinite;
}

@keyframes cursor-blink {
  0%, 49%  { opacity: 1; }
  50%, 100% { opacity: 0; }
}

/* ---- CRT layers -------------------------------------------------------------
   Order (z within #screen): rain < term/boot < crt overlays.
   body.crt-off kills everything; prefers-reduced-motion kills the parts
   that move (flicker) or distort (curvature) but keeps static texture.  */

/* curvature: rounded tube corners + inner bloom against the black bezel */
body.crt #screen {
  border-radius: clamp(8px, 1.8vmin, 22px);
  box-shadow:
    inset 0 0 clamp(40px, 12vmin, 140px) rgba(0, 0, 0, 0.55),
    inset 0 0 4px rgba(0, 0, 0, 0.8);
}

/* scanlines (::after) — static texture, cheap repeating gradient */
body.crt #screen::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--z-crt);
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0)      0px,
    rgba(0, 0, 0, 0)      2px,
    rgba(0, 0, 0, 0.14)   3px,
    rgba(0, 0, 0, 0)      4px
  );
  mix-blend-mode: multiply;
}

/* vignette + phosphor wash (::before) */
body.crt #screen::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--z-crt);
  pointer-events: none;
  background:
    radial-gradient(ellipse at center,
      rgba(0, 0, 0, 0) 58%,
      rgba(0, 0, 0, 0.26) 100%),
    radial-gradient(ellipse at center,
      var(--glow) 0%,
      rgba(0, 0, 0, 0) 62%);
  opacity: 0.55;
}

/* chromatic aberration: sub-pixel RGB fringe on the text layers */
body.crt #term,
body.crt #boot {
  text-shadow:
    0.4px 0 0 rgba(255, 0, 80, 0.14),
    -0.4px 0 0 rgba(0, 200, 255, 0.14);
}

/* flicker: slow, irregular, barely-there luminance wobble */
body.crt #screen {
  animation: crt-flicker 4.2s steps(1, end) infinite;
}

@keyframes crt-flicker {
  0%, 100% { opacity: 1; }
  7%   { opacity: 0.986; }
  9%   { opacity: 1; }
  31%  { opacity: 0.994; }
  33%  { opacity: 1; }
  58%  { opacity: 0.982; }
  60%  { opacity: 1; }
  83%  { opacity: 0.995; }
  85%  { opacity: 1; }
}

/* ---- The Breach: ROOT payoff flash ----------------------------------------
   A brief red convulsion the daemon gives up when you take root. Rides above
   the CRT layers (z 4 > z-crt 3), never eats pointer events, and removes
   itself on animationend (effects.js). Reduced motion gets no flash at all. */
.root-flash {
  position: fixed;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background: radial-gradient(circle at 50% 42%,
              rgba(255, 120, 90, 0.18), rgba(255, 42, 18, 0.62) 72%);
  mix-blend-mode: screen;
  opacity: 0;
  animation: breach-root-flash 900ms ease-out forwards;
}
@keyframes breach-root-flash {
  0%   { opacity: 0; }
  7%   { opacity: 0.72; }
  22%  { opacity: 0.14; }
  36%  { opacity: 0.9; }
  100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .root-flash { animation: none; opacity: 0; display: none; }
}

/* ---- Kill switches ---------------------------------------------------------- */

/* user said no: everything off */
body.crt-off #screen,
body.crt-off #screen::before,
body.crt-off #screen::after {
  animation: none;
  border-radius: 0;
  box-shadow: none;
  background-image: none;
  content: none;
}
body.crt-off #screen::before,
body.crt-off #screen::after { display: none; }
body.crt-off #term,
body.crt-off #boot { text-shadow: none; }

/* vestibular safety: no flicker, no curvature; static texture may stay */
@media (prefers-reduced-motion: reduce) {
  body.crt #screen {
    animation: none;
    border-radius: 0;
    box-shadow: none;
  }
  .t-cursor { animation: none; opacity: 1; }
  #screen { transition: none; }
}

/* ---- No-JS fallback ---------------------------------------------------------- */

.noscript-msg {
  padding: clamp(14px, 3vmin, 36px);
  color: var(--warn);
  white-space: pre-wrap;
}

/* ---- Arcade (Task 9+) --------------------------------------------------------
   #arcade is a full-screen program overlay built by arcade.js: HUD on top,
   canvas stage in the middle, touch controls + a hint at the bottom. It sits
   above the terminal and below the CRT overlays (same layer the boot uses),
   so games keep the scanlines — they're period-correct. */

#arcade {
  position: absolute;
  inset: 0;
  z-index: var(--z-boot);
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--fg);
  padding: clamp(10px, 2vmin, 24px);
  padding-bottom: max(clamp(10px, 2vmin, 24px), env(safe-area-inset-bottom));
}

.arc-hud {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1ch;
  padding-bottom: clamp(6px, 1.2vmin, 12px);
  border-bottom: 1px solid color-mix(in srgb, var(--dim) 45%, transparent);
}
.arc-title {
  color: var(--accent);
  letter-spacing: 0.35em;
  font-weight: 700;
  text-shadow: 0 0 12px var(--glow);
}
.arc-stats { white-space: nowrap; }
.arc-dim { color: var(--dim); }
.arc-score { color: var(--fg); font-weight: 700; }
.arc-high { color: var(--accent); font-weight: 700; }

.arc-stage {
  position: relative;
  flex: 1;
  min-height: 0;
  margin-top: clamp(6px, 1.2vmin, 12px);
}
.arc-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* game-over veil */
.arc-over {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.35em;
  text-align: center;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: blur(1.5px);
}
.arc-over[hidden] { display: none; }
.arc-over p { margin: 0; }
.arc-over-title {
  color: var(--crit);
  font-size: clamp(1.4em, 5vmin, 2.4em);
  letter-spacing: 0.3em;
  font-weight: 700;
  text-shadow: 0 0 16px var(--glow);
}
.arc-over-score { color: var(--fg); font-size: 1.1em; }
.arc-over-best { color: var(--accent); }
.arc-over-hint { color: var(--dim); margin-top: 0.8em; }

.arc-hint {
  padding-top: clamp(6px, 1.2vmin, 12px);
  color: var(--dim);
  font-size: 0.85em;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- touch controls: hidden on fine pointers, shown on coarse ------------- */

.arc-touch {
  display: none;
  justify-content: space-between;
  align-items: center;
  padding-top: clamp(8px, 1.6vmin, 14px);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.arc-dpad {
  display: grid;
  grid-template-columns: repeat(3, clamp(44px, 12vw, 60px));
  grid-template-rows: repeat(3, clamp(44px, 12vw, 60px));
  gap: 4px;
}
.arc-ab {
  display: flex;
  gap: clamp(10px, 3vw, 18px);
  align-items: center;
}
.arc-ab .arc-btn {
  width: clamp(52px, 14vw, 68px);
  height: clamp(52px, 14vw, 68px);
  border-radius: 50%;
}

.arc-btn {
  font: inherit;
  font-size: 1.1em;
  color: var(--fg);
  background: color-mix(in srgb, var(--fg) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--dim) 60%, transparent);
  border-radius: 10px;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
  cursor: pointer;
}
.arc-btn:active {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
  border-color: var(--accent);
  color: var(--accent);
}

@media (pointer: coarse) {
  .arc-touch { display: flex; }
  .arc-hint { display: none; } /* fingers don't need the keyboard legend */
}

/* ---- the trail: tappable text-adventure choices (Task 13) ------------------ */

.trail-choices {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  margin: 0.4em 0 0.6em;
}
.trail-btn {
  font: inherit;
  text-align: left;
  color: var(--accent);
  background: color-mix(in srgb, var(--fg) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--dim) 50%, transparent);
  border-radius: 6px;
  padding: 0.3em 0.8em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.trail-btn:hover:not(:disabled),
.trail-btn:active:not(:disabled) {
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  border-color: var(--accent);
}
.trail-btn:disabled {
  color: var(--dim);
  opacity: 0.55;
  cursor: default;
}

/* keyboard focus — themed, visible on every palette (UA default rings
   drown in some of the darker themes) */
.trail-btn:focus-visible,
.chip:focus-visible,
.arc-btn:focus-visible,
.arc-quit:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---- Mobile parity (Task 20) --------------------------------------------------
   Four pieces, all invisible on fine-pointer desktops:
   1. #kbd-proxy — the soft-keyboard bridge textarea (shell.js). Focusable
      and technically on-screen (iOS refuses to raise the keyboard for
      display:none / visibility:hidden), but 2px, transparent, and
      pointer-events:none so it can never be interacted with directly.
   2. #chips — tappable quick-command bar, coarse pointers only.
   3. --kbd-inset — the height the soft keyboard occludes (shell.js measures
      the visual viewport); pads #term and lifts #chips above the keys.
   4. touch affordances for programs: arcade quit / game-over buttons,
      theme-picker keep/cancel. */

#kbd-proxy {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 2px;
  height: 2px;
  padding: 0;
  border: 0;
  margin: 0;
  opacity: 0;
  background: transparent;
  color: transparent;
  caret-color: transparent;
  font-size: 16px; /* <16px would trigger iOS focus-zoom */
  resize: none;
  overflow: hidden;
  pointer-events: none; /* taps go to the terminal, never the proxy */
  z-index: var(--z-rain);
}
#kbd-proxy:focus { outline: none; }

/* quick-command chips — a thumb row pinned above the safe area / keyboard */
#chips {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--kbd-inset, 0px) + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-term);
  display: none; /* coarse pointers only, below */
  gap: 8px;
  padding: 10px clamp(12px, 3vmin, 20px) 12px;
  overflow-x: auto;
  scrollbar-width: none;
  background: linear-gradient(to top, var(--bg) 62%, transparent);
  -webkit-tap-highlight-color: transparent;
}

.chip {
  font: inherit;
  font-size: 0.9em;
  min-height: 44px; /* touch target */
  padding: 0.35em 1.1em;
  color: var(--accent);
  background: color-mix(in srgb, var(--fg) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--dim) 50%, transparent);
  border-radius: 8px;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.chip:active {
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  border-color: var(--accent);
}

/* arcade: touch quit (HUD) + game-over actions — hidden off coarse */
.arc-quit {
  display: none;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  font: inherit;
  color: var(--dim);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--dim) 50%, transparent);
  border-radius: 10px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.arc-quit:active {
  color: var(--crit);
  border-color: var(--crit);
}

.arc-over-actions {
  display: none;
  gap: 14px;
  margin-top: 0.8em;
}
.arc-over-actions .arc-btn {
  min-width: 44px;
  min-height: 44px;
  padding: 0 1.3em;
  border-radius: 8px;
}

/* theme picker: keep/cancel row + tappable rows — hidden off coarse */
.picker-actions {
  display: none;
  gap: 10px;
  margin: 0.5em 0 0.3em;
}
.picker-actions .trail-btn {
  min-height: 44px;
  padding: 0.3em 1.4em;
}

/* ---- GUI login greeter (login-gui task) --------------------------------------
   A real <form> in a native <dialog>, styled as DemonicOS raising a graphical
   session manager over the console — NOT a generic web modal. Everything is
   drawn from the 8 theme slots so all themes (light solarized included) keep
   their contrast guarantees. The password managers only see the form; the
   phosphor is for the humans. */

/* the corner chip: discreet, always present, part of the tube (scanlines wash
   over it). Dim at rest; wakes to accent on hover/focus. */
#login-chip {
  position: absolute;
  right: clamp(10px, 2vmin, 22px);
  bottom: max(clamp(10px, 2vmin, 22px), env(safe-area-inset-bottom, 0px));
  z-index: var(--z-chip);
  font: inherit;
  font-size: 0.85em;
  padding: 0.3em 0.85em;
  color: var(--dim);
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  border: 1px solid color-mix(in srgb, var(--dim) 45%, transparent);
  border-radius: 8px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color 160ms ease-out, border-color 160ms ease-out,
              text-shadow 160ms ease-out;
}
#login-chip:hover,
#login-chip:focus-visible {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 70%, transparent);
  text-shadow: 0 0 8px var(--glow);
}
#login-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
#login-chip:active {
  background: color-mix(in srgb, var(--accent) 22%, transparent);
}

/* authed-console: the corner chip becomes a dashboard return link */
a#login-chip.chip-dashboard {
  display: block;
  text-decoration: none;
  line-height: 1;
}

/* the greeter window */
#login-modal {
  /* dialog UA resets */
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: 10px;
  width: min(92vw, 380px);
  background: var(--bg);
  color: var(--fg);
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--bg) 40%, #000),
    0 0 46px color-mix(in srgb, var(--glow) 65%, transparent),
    0 18px 60px rgba(0, 0, 0, 0.55);
  overflow: hidden; /* keeps the scanline overlay + header inside the radius */
}
#login-modal[open] {
  animation: login-rise 220ms cubic-bezier(0.22, 1, 0.36, 1);
}
#login-modal::backdrop {
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(2px) saturate(0.8);
  animation: login-backdrop 220ms ease-out;
}

/* the greeter keeps the tube's texture: its own faint scanlines */
#login-form {
  position: relative;
  margin: 0;
}
#login-form::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0)    0px,
    rgba(0, 0, 0, 0)    2px,
    rgba(0, 0, 0, 0.10) 3px,
    rgba(0, 0, 0, 0)    4px
  );
  mix-blend-mode: multiply;
}
body.crt-off #login-form::after { display: none; }

/* titlebar */
.login-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1ch;
  padding: 0.55em 0.6em 0.55em 1em;
  background: color-mix(in srgb, var(--fg) 7%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--dim) 45%, transparent);
}
.login-head h2 {
  margin: 0;
  font-size: 0.9em;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--accent);
  text-shadow: 0 0 10px var(--glow);
}
#login-close {
  font: inherit;
  min-width: 32px;
  min-height: 32px;
  padding: 0;
  color: var(--dim);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
#login-close:hover,
#login-close:focus-visible {
  color: var(--crit);
  border-color: color-mix(in srgb, var(--crit) 55%, transparent);
}
#login-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* body */
.login-body {
  display: flex;
  flex-direction: column;
  padding: 1em 1.2em 1.2em;
}
.login-sub {
  margin: 0 0 1em;
  color: var(--dim);
  font-size: 0.85em;
}
.login-label {
  color: var(--dim);
  font-size: 0.8em;
  letter-spacing: 0.12em;
  margin-bottom: 0.3em;
  user-select: none;
}
#login-form input {
  font: inherit;
  font-size: max(16px, 1em); /* <16px would trigger iOS focus-zoom */
  width: 100%;
  padding: 0.5em 0.7em;
  margin-bottom: 0.9em;
  color: var(--fg);
  background: color-mix(in srgb, var(--fg) 5%, transparent);
  border: 1px solid color-mix(in srgb, var(--dim) 55%, transparent);
  border-radius: 6px;
  caret-color: var(--accent);
  transition: border-color 160ms ease-out, box-shadow 160ms ease-out;
}
#login-form input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 12px color-mix(in srgb, var(--glow) 60%, transparent);
}
/* browser autofill paints its own colors — pull it back onto the phosphor */
#login-form input:-webkit-autofill {
  -webkit-text-fill-color: var(--fg);
  -webkit-box-shadow: 0 0 0 1000px var(--bg) inset;
  caret-color: var(--accent);
  transition: background-color 999999s ease-out;
}

/* inline error — space reserved so a denial doesn't jump the layout */
.login-error {
  margin: 0 0 0.6em;
  min-height: 1.5em;
  color: var(--crit);
  font-size: 0.9em;
}

#login-submit {
  font: inherit;
  font-weight: 700;
  letter-spacing: 0.08em;
  min-height: 44px;
  padding: 0.45em 1em;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 60%, transparent);
  border-radius: 8px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 160ms ease-out, text-shadow 160ms ease-out;
}
#login-submit:hover:not(:disabled),
#login-submit:active:not(:disabled) {
  background: color-mix(in srgb, var(--accent) 24%, transparent);
  text-shadow: 0 0 8px var(--glow);
}
#login-submit:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
#login-submit:disabled {
  color: var(--dim);
  border-color: color-mix(in srgb, var(--dim) 45%, transparent);
  background: color-mix(in srgb, var(--fg) 4%, transparent);
  cursor: default;
}
#login-submit.login-granted {
  color: var(--bg);
  background: var(--accent);
  border-color: var(--accent);
  text-shadow: none;
}

/* denial shake — motion carries the state; reduced-motion gets the text only */
.login-shake {
  animation: login-shake 300ms cubic-bezier(0.36, 0.07, 0.19, 0.97);
}

@keyframes login-rise {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.985);
  }
}
@keyframes login-backdrop {
  from { opacity: 0; }
}
@keyframes login-shake {
  20% { transform: translateX(-5px); }
  40% { transform: translateX(4px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(2px); }
}

@media (prefers-reduced-motion: reduce) {
  #login-modal[open],
  #login-modal::backdrop,
  .login-shake {
    animation: none;
  }
  #login-chip,
  #login-form input,
  #login-submit {
    transition: none;
  }
}

@media (pointer: coarse) {
  #chips { display: flex; }
  /* a mounted program hides the input line — hide the dead chips with it */
  #screen:has(#input-line[hidden]) #chips { display: none; }

  /* lift the login chip clear of the quick-command bar (and the soft
     keyboard, whose inset the bar already tracks) */
  #login-chip {
    bottom: calc(
      70px + var(--kbd-inset, 0px) + max(env(safe-area-inset-bottom, 0px), 0px)
    );
  }

  /* keep the last lines + input line clear of the chip bar and keyboard */
  #term {
    padding-bottom: calc(
      78px + max(env(safe-area-inset-bottom, 0px), var(--kbd-inset, 0px))
    );
  }

  .arc-quit { display: inline-flex; }
  .arc-over-actions { display: flex; }
  .arc-over-hint { display: none; } /* R/Q means nothing to a thumb */

  .picker-actions { display: flex; }
  .picker-row { cursor: pointer; }

  /* swipes on the playfield are game input, not page scroll */
  .arc-stage { touch-action: none; }
}
