/* ============================================================================
   IMC stylesheet — retro green-on-black terminal look.

   CSS variables (--bg, --fg, etc., defined in :root below) hold the color
   palette in one place, so the whole theme can be changed by editing just
   these four lines instead of hunting through every rule.
   ============================================================================ */

:root {
  --bg: #001100;          /* page background */
  --fg: #33ff33;           /* normal text color */
  --fg-dim: #1f7a1f;       /* timestamps, borders, secondary text */
  --fg-bright: #7fff7f;    /* mod username, error messages */
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0; height: 100%;
  background: var(--bg);
  color: var(--fg);
  font-family: 'Menlo', 'Courier New', monospace;
  font-size: 14px;
  /* the subtle glow on all text is what gives the CRT/terminal feel */
  text-shadow: 0 0 2px currentColor;
  /* From the same CRT snippet source as the effect further down this file
     (code-glow.css) — tells WebKit browsers to use the OS's normal font
     rendering instead of forcing its own antialiasing, which reads a
     little chunkier/lower-res, closer to an old display's text. Harmless
     no-op on browsers that don't support the property. */
  -webkit-font-smoothing: auto;
}

/* ---- Top bar: title, quote, logout link ----------------------------------
   Three flex children: title (left, fixed width), headerQuote (flex:1, so
   it absorbs all the extra space and right-aligns its own text — this is
   what makes the quote "end a few spaces before logout" rather than sit
   centered), then logoutLink (right, fixed width). */
#header {
  height: 28px;
  display: flex;
  align-items: center;
  padding: 0 10px;
  border-bottom: 1px solid var(--fg-dim);
  color: var(--fg-dim);
  position: relative; /* anchors #modMenu's absolute positioning below */
}
#header .title { color: var(--fg); white-space: nowrap; }
/* Opens #infoPanel below — unlike the mod-trigger username (only
   underlined/clickable for the mod), this is clickable for everyone, so it
   only gets the hover color shift, not a permanent underline, to keep the
   "IMC" wordmark looking like a title rather than a link at rest. */
#imcTitleBtn { cursor: pointer; }
#imcTitleBtn:hover { color: var(--fg-bright); }
/* Only the mod's username gets this class (added by app.js), making it
   look and act clickable; everyone else's name is plain static text. */
#usernameDisplay.mod-trigger {
  cursor: pointer;
  text-decoration: underline;
}
#usernameDisplay.mod-trigger:hover { color: var(--fg-bright); }
/* Info panel opened by clicking "IMC" — visible to everyone (logged in or
   lurking), unlike #modMenu just below which is mod-only. Same dropdown
   styling/position as #modMenu since they're visually the same kind of
   thing; kept as a separate element (rather than reusing #modMenu) since
   this one is open to all and will likely grow its own unrelated rows over
   time (the lurker/user counts and timestamp toggle below are just the
   first two). */
#infoPanel {
  display: none;
  position: absolute;
  top: 28px;
  left: 10px;
  min-width: 160px;
  background: #001a00;
  border: 1px solid var(--fg-dim);
  z-index: 1;
}
#infoPanel.open { display: block; }
#infoPanel .info-panel-row {
  color: var(--fg);
  border-bottom: 1px solid var(--fg-dim);
  font-size: 12px;
  padding: 6px 10px;
}
#infoPanel .info-panel-row:last-child { border-bottom: none; }
/* Only the timestamp toggle row is interactive — the counts above it are
   plain display text, same "not everything in a dropdown has to be a
   button" idea as #modMenu's reference-only rows. */
#infoPanel .info-panel-toggle { cursor: pointer; }
#infoPanel .info-panel-toggle:hover { color: var(--fg-bright); }
/* Dropdown of mod-only commands, opened by clicking the mod's username.
   Positioned like a normal dropdown menu, anchored just under the header —
   contrast with #emojiPicker, which anchors *above* the input row, since
   this one hangs off the top bar instead of the bottom one. */
#modMenu {
  display: none;
  position: absolute;
  top: 28px;
  left: 10px;
  min-width: 180px;
  background: #001a00;
  border: 1px solid var(--fg-dim);
  z-index: 1;
}
#modMenu.open { display: block; }
/* Plain reference text, deliberately not interactive — no cursor:pointer,
   no hover state — since this menu only reminds the mod what commands
   exist and their syntax; nothing in it should be clickable, especially
   since /clearchat is destructive enough that a stray click shouldn't be
   able to fire it. */
#modMenu .mod-menu-item {
  color: var(--fg);
  border-bottom: 1px solid var(--fg-dim);
  font-size: 12px;
  padding: 6px 10px;
}
#modMenu .mod-menu-item:last-child { border-bottom: none; }
#headerQuote {
  flex: 1;
  text-align: right;
  margin-right: 12px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis; /* a quote too long for the bar truncates with "..." rather than wrapping/overflowing */
  font-style: italic;
  color: var(--fg-dim);
}
/* Mod-only editable replacement for #headerQuote — app.js shows exactly
   one of the two depending on who's logged in. */
#headerQuoteEditWrap {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  margin-right: 12px;
  min-width: 0; /* lets the input below shrink instead of overflowing the header */
}
#headerQuoteInput {
  flex: 1;
  min-width: 0;
  text-align: right;
  background: transparent;
  border: none;
  border-bottom: 1px dashed var(--fg-dim);
  color: var(--fg-dim);
  font-family: inherit;
  font-size: inherit;
  font-style: italic;
  outline: none;
}
#headerQuoteBold, #headerQuoteReset {
  background: none;
  border: none;
  color: var(--fg-dim);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0;
  font-family: inherit;
}
#headerQuoteBold:hover, #headerQuoteReset:hover { color: var(--fg); }
/* app.js adds this when the pinned override is currently set to render
   bold, so the toggle button visibly reflects its own current state. */
#headerQuoteBold.active { color: var(--fg-bright); }
#logoutLink {
  color: var(--fg-dim);
  cursor: pointer;
  text-decoration: underline;
  white-space: nowrap;
  /* Pushes this to the far right edge of #header. Normally #headerQuote's
     flex:1 does that job by absorbing the space between title and logout,
     but it's hidden right now (quotes disabled — see the rule above), so
     without this, logoutLink would sit right up against the title. */
  margin-left: auto;
}
#logoutLink:hover { color: var(--fg); }
/* Shares the same top-right corner as #logoutLink — the two are never
   visible at the same time (this only shows during step 2 of the logged-
   out login flow; [x] only shows once logged in), so the same margin-left:
   auto trick works here too. */
#changeUsernameLink {
  color: var(--fg-dim);
  cursor: pointer;
  text-decoration: underline;
  font-size: 12px;
  white-space: nowrap;
  margin-left: auto;
}
#changeUsernameLink:hover { color: var(--fg); }

/* ---- Chat log ------------------------------------------------------------ */
#chat {
  /* fills all remaining vertical space: full viewport height, minus the
     28px header and the 50px input row */
  height: calc(100vh - 28px - 50px);
  overflow-y: auto;
  padding: 10px;
  white-space: pre-wrap;
  word-break: break-word;
}
.line { margin: 0 0 2px 0; }
.line.own { font-weight: bold; } /* the logged-in user's own messages, bold for them only */
.ts { color: var(--fg-dim); } /* [HH:MM] timestamp prefix */
/* Set on <body> by app.js when the "Hide timestamps" toggle (in #infoPanel)
   is on — a purely local display preference (saved in localStorage, never
   sent to the server), so it just hides the existing .ts spans rather than
   changing anything about how messages are rendered or stored. */
body.hide-timestamps .ts { display: none; }
.mod-name { color: var(--fg-bright); font-weight: bold; } /* the mod's username */
.name { color: var(--fg); } /* everyone else's username */
.deleted { color: var(--fg-dim); font-style: italic; } /* "message deleted" placeholder */
.error { color: var(--fg-bright); font-weight: bold; } /* rejection notices sent only to you */
/* A username with a personal status set renders bold (no underline —
   underline is reserved for things that look like links/commands
   elsewhere in this app) as the only visual hint that there's something
   to see if you click it. */
.name.has-status, .mod-name.has-status { font-weight: bold; }
/* Your own username (always, so you can add/edit a status even if you
   don't have one yet) and anyone else's *if* they have a status set (see
   has-status above) get a pointer cursor — the only other visual cue that
   clicking does something, since the bold styling alone might not read as
   "clickable" to everyone. */
.clickable-name { cursor: pointer; }
/* Auto-linkified http(s):// URLs — only ever appears in the mod's own
   chat messages and the pinned announcement, per the admin-only scope. */
.line a, #headerQuote a {
  color: var(--fg-bright);
  text-decoration: underline;
}
/* Mod-only inline delete button, appended after each message line by
   app.js. Deliberately always visible (not hover-only) so it still works
   for a mod on a touch device, which has no concept of hover. */
.del-btn {
  background: none;
  border: none;
  color: var(--fg-dim);
  cursor: pointer;
  text-decoration: underline;
  font-family: inherit;
  font-size: inherit;
  margin-left: 8px;
  padding: 0;
}
.del-btn:hover { color: var(--fg-bright); }

/* ---- Bottom strip: holds exactly one of #loginBar / #chatControls -------
   #inputRow itself never changes size; app.js just toggles which of its
   two children is display:flex vs display:none, so the rest of the page
   layout (#chat's height calc below) never has to shift. */
#inputRow {
  height: 50px;
  border-top: 1px solid var(--fg-dim);
  position: relative; /* anchors the emoji picker's absolute positioning below */
}
#loginBar, #chatControls {
  display: flex;
  align-items: center;
  height: 100%;
  width: 100%;
  gap: 8px;
  padding: 0 10px;
}
/* The login bar's contents stay right-justified across both steps — empty
   space sits on the left instead of the right — so the group occupies the
   same screen position throughout, rather than visibly relocating as
   fields appear/disappear between step 1 and step 2. #chatControls is
   intentionally left at the default (flex-start); it doesn't need this
   since #msgInput's flex:1 already consumes all the space regardless. */
#loginBar { justify-content: flex-end; }
#loginBar input, #chatControls #msgInput {
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--fg-dim);
  outline: none;
  padding: 4px 8px;
  font-family: inherit;
  font-size: inherit;
  text-shadow: 0 0 2px currentColor;
}
/* Placeholder text ("username", "password", "Create a password") doesn't
   inherit the `color` rule above — placeholders are styled independently
   by browsers, defaulting to a grayish tone, which is why these needed
   their own explicit rule to actually render in the app's green. */
#loginBar input::placeholder {
  color: var(--fg-dim);
  opacity: 1; /* Firefox dims placeholder text by default; this keeps it consistent across browsers */
}
/* The message box specifically has no visible border (matches the old
   look — just background + blinking caret, no boxed-in feel), unlike the
   login fields which do look like normal fields since they're new/unknown
   to a first-time visitor and benefit from looking more obviously
   fillable. */
#chatControls #msgInput {
  flex: 1;
  border: none;
  padding: 0 10px;
}
#loginBar input { flex: 1; min-width: 0; }
#loginBar input:disabled { color: var(--fg-dim); } /* the username field, once locked in during step 2 */
/* Both fields capped to the same 17 characters (roughly the 15-character
   password limit — the larger of the two field limits, username's is 12 —
   plus a little padding) instead of stretching to fill the bar — keeps the
   whole group compact and stable rather than one field ballooning to
   consume whatever space is left. Selector is
   "#loginBar #usernameInput" rather than just "#usernameInput" specifically
   to out-rank the "#loginBar input { flex: 1; ... }" rule above — a
   single-ID selector is actually *less* specific than an ID plus an
   element type, so plain "#usernameInput" silently lost to it. */
#loginBar #usernameInput, #loginBar #passwordInput {
  flex: none;
  width: 17ch;
}
#loginBar button, #chatControls button {
  background: #002200;
  color: var(--fg);
  border: 1px solid var(--fg-dim);
  padding: 0 14px;
  height: 30px;
  cursor: pointer;
  font-family: inherit;
  white-space: nowrap;
}
#loginBar button:hover, #chatControls button:hover { background: #003300; }
/* Floats just above the bottom strip instead of taking up space inside it,
   so an error message appearing/disappearing never shifts the layout. */
#loginError {
  position: absolute;
  bottom: 50px;
  left: 0;
  right: 0;
  padding: 4px 10px;
  background: #001a00;
  color: var(--fg-bright);
  font-size: 12px;
  min-height: 0;
}
#loginError:empty { display: none; }

/* ---- Emoji picker button + popup grid ------------------------------------
   #emojiBtn is a normal child of #chatControls, so it already gets the
   shared background/border/padding from the "#chatControls button" rule
   above — this just shrinks its font slightly, since the kaomoji glyph is
   wider than typical button text. */
#emojiBtn { font-size: 12px; }
#emojiPicker {
  display: none; /* hidden by default; app.js toggles the .open class below */
  position: absolute;
  bottom: 50px; /* sits just above the input row */
  right: 0;
  width: 260px;
  /* max-height + overflow-y together make this automatically scrollable if
     the emoticon list (assets/data/emoticons.json) grows past this height —
     no code changes needed when adding more entries. */
  max-height: 220px;
  overflow-y: auto;
  background: #001a00;
  border: 1px solid var(--fg-dim);
  padding: 6px;
  grid-template-columns: repeat(5, 1fr); /* 5 buttons per row */
  gap: 4px;
}
#emojiPicker.open { display: grid; } /* app.js adds/removes this class to show/hide the picker */
#emojiPicker button {
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--fg-dim);
  padding: 6px 2px;
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis; /* longer kaomoji get truncated with "..." rather than overflowing the button */
}
#emojiPicker button:hover { background: #003300; }

/* ---- Personal status popup ------------------------------------------------
   Unlike #emojiPicker/#modMenu, which always anchor to the same fixed spot,
   this one can pop up next to a username anywhere in the scrolling chat
   log — so it uses position:fixed with its top/left set directly by app.js
   from the clicked element's on-screen position, rather than relying on a
   positioned ancestor the way the others do. */
#statusPopup {
  position: fixed;
  max-width: 240px;
  background: #001a00;
  border: 1px solid var(--fg-dim);
  padding: 8px;
  z-index: 2;
}
#statusPopupInput {
  width: 220px;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--fg-dim);
  outline: none;
  padding: 4px 6px;
  font-family: inherit;
  font-size: 12px;
}
#statusPopupText {
  color: var(--fg);
  font-size: 12px;
  white-space: pre-wrap;
  word-break: break-word;
}

/* ============================================================================
   CRT effect 
   ============================================================================ */

@keyframes crtFlicker {
  0% { opacity: 0.0975; }
  5% { opacity: 0.1217; }
  10% { opacity: 0.0826; }
  15% { opacity: 0.3172; }
  20% { opacity: 0.0634; }
  25% { opacity: 0.2936; }
  30% { opacity: 0.2295; }
  35% { opacity: 0.2373; }
  40% { opacity: 0.093; }
  45% { opacity: 0.2964; }
  50% { opacity: 0.3361; }
  55% { opacity: 0.0301; }
  60% { opacity: 0.0711; }
  65% { opacity: 0.252; }
  70% { opacity: 0.1871; }
  75% { opacity: 0.1305; }
  80% { opacity: 0.25; }
  85% { opacity: 0.2465; }
  90% { opacity: 0.2451; }
  95% { opacity: 0.1264; }
  100% { opacity: 0.0854; }
}

@keyframes crtTextShadow {
  0% { text-shadow: 0.219px 0 1px rgba(0, 30, 255, 0.5), -0.219px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  5% { text-shadow: 1.396px 0 1px rgba(0, 30, 255, 0.5), -1.396px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  10% { text-shadow: 0.015px 0 1px rgba(0, 30, 255, 0.5), -0.015px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  15% { text-shadow: 0.201px 0 1px rgba(0, 30, 255, 0.5), -0.201px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  20% { text-shadow: 1.74px 0 1px rgba(0, 30, 255, 0.5), -1.74px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  25% { text-shadow: 0.806px 0 1px rgba(0, 30, 255, 0.5), -0.806px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  30% { text-shadow: 0.351px 0 1px rgba(0, 30, 255, 0.5), -0.351px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  35% { text-shadow: 1.948px 0 1px rgba(0, 30, 255, 0.5), -1.948px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  40% { text-shadow: 1.935px 0 1px rgba(0, 30, 255, 0.5), -1.935px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  45% { text-shadow: 1.116px 0 1px rgba(0, 30, 255, 0.5), -1.116px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  50% { text-shadow: 0.04px 0 1px rgba(0, 30, 255, 0.5), -0.04px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  55% { text-shadow: 1.188px 0 1px rgba(0, 30, 255, 0.5), -1.188px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  60% { text-shadow: 1.101px 0 1px rgba(0, 30, 255, 0.5), -1.101px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  65% { text-shadow: 1.432px 0 1px rgba(0, 30, 255, 0.5), -1.432px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  70% { text-shadow: 0.244px 0 1px rgba(0, 30, 255, 0.5), -0.244px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  75% { text-shadow: 0.947px 0 1px rgba(0, 30, 255, 0.5), -0.947px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  80% { text-shadow: 0.042px 0 1px rgba(0, 30, 255, 0.5), -0.042px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  85% { text-shadow: 0.049px 0 1px rgba(0, 30, 255, 0.5), -0.049px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  90% { text-shadow: 1.722px 0 1px rgba(0, 30, 255, 0.5), -1.722px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  95% { text-shadow: 1.092px 0 1px rgba(0, 30, 255, 0.5), -1.092px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
  100% { text-shadow: 1.31px 0 1px rgba(0, 30, 255, 0.5), -1.31px 0 1px rgba(255, 0, 80, 0.3), 0 0 3px; }
}

body { overflow: hidden; } /* body itself never needs to scroll — only #chat does — this just keeps the fixed overlays below from ever creating a stray scrollbar */

/* Scanlines: TWO layered gradients, stacked in one background (each with
   its own background-size entry, in the same order), both from
   read-code-screen.css:
     1. A fine 2px band (a hard 50/50 split) — the actual "screen door"
        scanline texture.
     2. An RGB subpixel fringe — faint repeating red/green/blue columns,
        3px pitch, mimicking an aperture-grille CRT/LCD's individual
        subpixels.

   Both remaining layers are static. */

body::before {
  content: " ";
  position: fixed;
  inset: 0;
  background:
    linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.2) 50%),
    linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
  background-size: 100% 2px, 3px 100%;
  z-index: 999;
  pointer-events: none;
}

/* Flicker: a dark layer whose opacity is animated by crtFlicker above,
   sitting on top of everything else (still non-interactive). */
body::after {
  content: " ";
  position: fixed;
  inset: 0;
  background: rgba(18, 16, 16, 0.1);
  opacity: 0;
  z-index: 999;
  pointer-events: none;
  animation: crtFlicker 0.5s infinite;
}

/* Chromatic-fringe text jitter, applied to the whole page — text-shadow
   inherits, so this cascades to the header, quote, chat log, and buttons.
   The two live text inputs (#loginBar input, #chatControls #msgInput)
   deliberately keep their own static glow instead of inheriting this
   animation — see their rules above — so text doesn't visibly jitter right
   where someone's actively typing/reading their own cursor. */
body { animation: crtTextShadow 1.6s infinite; }


