/* ============================================================================
   Guestbook stylesheet — the same green-on-black world as IMC, built for a
   full page rather than a 425px box.

   The palette and the CRT effect at the bottom are shared with the chat so
   the two read as parts of the same machine. Everything between is different,
   because a guestbook is a different kind of thing: it has room to breathe,
   its entries are meant to be read rather than skimmed past, and nothing on
   it moves on its own.
   ============================================================================ */

:root {
  --bg: #001100;          /* page background */
  --fg: #33ff33;          /* normal text */
  --fg-dim: #1f7a1f;      /* stamps, borders, secondary text */
  --fg-bright: #7fff7f;   /* emphasis, errors, approve */
  --panel: #001a00;       /* raised surfaces */
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--fg);
  font-family: 'Menlo', 'Courier New', monospace;
  font-size: 14px;
  text-shadow: 0 0 2px currentColor;
  -webkit-font-smoothing: auto;
}

/* The readable column. Black fills the frame; the text stops at a comfortable
   measure rather than stretching across a wide monitor. */
#page {
  max-width: 780px;
  margin: 0 auto;
  padding: 0 16px 40px;
}

/* No header on the public book, so it needs its own room at the top. */
.book #page { padding-top: 22px; }

/* ---- Header -------------------------------------------------------------
   Moderation only. Not sticky: the frame grows to fit rather than scrolling,
   so there's no inner scroll to stick against. */
#header {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 40px;
  margin: 0 -16px 22px;
  padding: 0 16px;
  background: var(--bg);
  border-bottom: 1px solid var(--fg-dim);
}
#header .title {
  color: var(--fg);
  white-space: nowrap;
  letter-spacing: 1px;
}
#header .title-accent { color: var(--fg-bright); }

.fake-link {
  color: var(--fg-dim);
  text-decoration: underline;
  cursor: pointer;
  white-space: nowrap;
}
.fake-link:hover { color: var(--fg); }

/* Anything dropped into topHtml / bottomHtml in text.json lands in here.
   Centred, with images kept inside the column no matter what width the
   markup claims — a 900px-wide image pasted in from elsewhere shouldn't be
   able to force the page sideways. */
.free-html { text-align: center; margin: 0 0 22px; }
.free-html--bottom { margin: 26px 0 0; }
.free-html img {
  max-width: 100%;
  height: auto;
}

/* Broken-text-file warning. Amber rather than green so it reads as machinery
   rather than as part of the page, and so it's obvious it isn't meant to be
   there. Only ever rendered for requests from this machine. */
.text-file-warning {
  display: flex;
  flex-direction: column;
  gap: 6px;
  border: 1px solid #cc8800;
  background: #221600;
  color: #ffbb33;
  padding: 10px 12px;
  margin-bottom: 20px;
  font-size: 12px;
  line-height: 1.5;
  text-shadow: none;
}

/* ---- The signing panel ---------------------------------------------------
   Above the entries, so signing doesn't mean scrolling past everyone who
   came before you. */
.sign-panel {
  border: 1px solid var(--fg-dim);
  background: var(--panel);
  padding: 14px 16px 16px;
  margin-bottom: 28px;
}

.sign-rule {
  color: var(--fg-bright);
  text-align: center;
  letter-spacing: 0.5px;
  margin-bottom: 12px;
}
.sign-rule .rule-mark { color: var(--fg-dim); }

.sign-note {
  color: var(--fg-dim);
  margin: 0 0 14px;
  line-height: 1.5;
  text-align: center;
}
.signed-today { color: var(--fg); margin-bottom: 0; }

.sign-error {
  color: var(--fg-bright);
  border: 1px solid var(--fg-bright);
  padding: 6px 10px;
  margin: 0 0 12px;
}

/* ---- Form fields ---------------------------------------------------------- */
.field { display: block; margin-bottom: 12px; }
.field-label {
  display: block;
  color: var(--fg-dim);
  font-size: 12px;
  margin-bottom: 4px;
}

/* Label left, character counter right, on the line above the box. Baseline
   alignment so the two sit on the same line however their sizes differ. */
.field-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.field-head .field-label { margin-bottom: 4px; }

/* 16px here and nowhere else, and not a taste decision: iOS zooms the page
   when a field under 16px is focused, and doesn't zoom back out.
   See CODE-NOTES.md [G040]. */
.sign-form input[type="text"],
.sign-form input[type="password"],
.sign-form textarea {
  width: 100%;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--fg-dim);
  outline: none;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 16px;
  line-height: 1.5;
  text-shadow: 0 0 2px currentColor;
}
.sign-form textarea { resize: vertical; }
.sign-form textarea::placeholder { color: var(--fg-dim); opacity: 1; }
.sign-form input:focus,
.sign-form textarea:focus { border-color: var(--fg); }

/* Off-screen rather than display:none — some tools skip explicitly hidden
   fields but fill one they can still "see". [G011] */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Links left, counter and button right. margin-right:auto splits them, and
   holds up when the right-hand side is empty. */
.sign-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 14px;
}

/* Nothing to balance against once the form is gone, so centred. */
.sign-actions--centred { justify-content: center; }
.sign-actions--centred .panel-links { margin-right: 0; padding-left: 0; }

.panel-links {
  margin-right: auto;
  font-size: 12px;
  /* Nudged inside the corner rather than hard against it. */
  padding-left: 4px;
}
.panel-links a { color: var(--fg); text-decoration: underline; }
.panel-links a:hover { color: var(--fg-bright); }
.panel-links .sep { margin: 0 8px; color: var(--fg-dim); }
.char-count { color: var(--fg-dim); font-size: 12px; }
.char-count.near-limit { color: var(--fg-bright); }

.sign-form button {
  background: #002200;
  color: var(--fg);
  border: 1px solid var(--fg-dim);
  padding: 0 20px;
  height: 30px;
  cursor: pointer;
  font-family: inherit;
  font-size: inherit;
  letter-spacing: 1px;
}
.sign-form button:hover { background: #003300; border-color: var(--fg); }

/* ---- Entries ------------------------------------------------------------
   Generous space and a dashed rule: the visual opposite of the chat log. */
.entry {
  padding: 0 0 18px;
  margin-bottom: 18px;
  border-bottom: 1px dashed var(--fg-dim);
}
.entry:last-child { border-bottom: none; }

/* Timestamp above; name and message run together beneath. */
.entry-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 3px;
  flex-wrap: wrap;
}
.entry-stamp { color: var(--fg-dim); font-size: 12px; }

.entry-body {
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.6;
}

/* Inline, the way a name does in a transcript: the colon is part of it. */
.entry-name { color: var(--fg-bright); font-weight: bold; }

/* Dimmed and labelled, so it can't be mistaken for something public. */
/* Indented under the entry it answers, so it reads as a reply rather than a
   second entry. Nothing is drawn unless there's a reply. */
.entry-reply {
  margin: 8px 0 0 18px;
  padding-left: 10px;
  border-left: 1px solid var(--fg-dim);
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.6;
  color: var(--fg-dim);
}
.entry-reply .reply-name {
  color: var(--fg);
  font-weight: bold;
}

.entry--pending { opacity: 0.55; }
.pending-flag {
  color: var(--fg-bright);
  font-size: 11px;
  letter-spacing: 0.5px;
  border: 1px solid var(--fg-dim);
  padding: 1px 6px;
}

.empty-note { color: var(--fg-dim); font-style: italic; }

/* ---- Pager ---------------------------------------------------------------
   Shown only when the book runs to more than one page. "Newer" and "older"
   rather than "previous" and "next", since the book reads newest-first and a
   page of it is a place in time. */
.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 26px;
  padding-top: 14px;
  border-top: 1px solid var(--fg-dim);
  font-size: 12px;
}
.pager-link { color: var(--fg); text-decoration: underline; white-space: nowrap; }

/* Never a link: there's no single page it could go to. */
.pager-gap { color: var(--fg-dim); padding: 0 2px; }
.pager-link:hover { color: var(--fg-bright); }

/* The ends of the run. Still occupy their place so the page indicator stays
   centred, but there's nothing to click. */
.pager-link.is-end {
  color: var(--fg-dim);
  text-decoration: none;
  opacity: 0.5;
}

/* The run of page numbers, centred between newer and older. Allowed to wrap
   onto a second line rather than pushing the page sideways — a very long book
   will eventually list a lot of numbers, and a wrapped row is better than a
   horizontal scrollbar. */
.pager-nums {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px 10px;
}
.pager-num { color: var(--fg); text-decoration: underline; }
.pager-num:hover { color: var(--fg-bright); }

/* Where you are. Not a link, and brightened so it's findable at a glance in
   a long row of numbers. */
.pager-num.is-current {
  color: var(--fg-bright);
  text-decoration: none;
  font-weight: bold;
}

/* ============================================================================
   Moderation page — same furniture, different job.
   ============================================================================ */

#header .queue-count {
  margin-left: auto;
  color: var(--fg-bright);
  font-size: 12px;
  white-space: nowrap;
}

.queue-heading {
  color: var(--fg-dim);
  font-size: 12px;
  font-weight: normal;
  letter-spacing: 1px;
  text-transform: uppercase;
  margin: 26px 0 14px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--fg-dim);
}

/* A queued entry is boxed rather than merely ruled off, so the things
   awaiting a decision are obviously a different kind of object from the
   ones already in the book. */
.entry--queued {
  border: 1px solid var(--fg-dim);
  background: var(--panel);
  padding: 12px 14px;
}

.queue-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
}
.queue-actions form { display: inline; margin: 0; }
.queue-actions button {
  background: #002200;
  border: 1px solid var(--fg-dim);
  color: var(--fg);
  font-family: inherit;
  font-size: 12px;
  padding: 4px 14px;
  cursor: pointer;
  letter-spacing: 0.5px;
}
.btn-approve:hover { background: #004400; border-color: var(--fg-bright); color: var(--fg-bright); }
.btn-delete:hover { background: #330000; border-color: #ff6666; color: #ff9999; }
/* This page only; the public book never shows where an entry came from. */
.queue-ip { margin-left: auto; color: var(--fg-dim); font-size: 11px; }

/* Above Delete: answering is the ordinary action, removing the exception. */
.reply-form {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 8px 0 0 18px;
}
.reply-form textarea {
  flex: 1;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--fg-dim);
  outline: none;
  padding: 6px 8px;
  font-family: inherit;
  /* Same reason as the signing form: under 16px, iOS zooms on focus. */
  font-size: 16px;
  line-height: 1.5;
  resize: vertical;
}
.reply-form textarea::placeholder { color: var(--fg-dim); opacity: 1; }
.reply-form textarea:focus { border-color: var(--fg); }
.btn-reply {
  background: #002200;
  color: var(--fg);
  border: 1px solid var(--fg-dim);
  padding: 0 12px;
  height: 30px;
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  white-space: nowrap;
}
.btn-reply:hover { background: #003300; border-color: var(--fg); }

/* Marks an entry in the queue that already carries an answer. */
.replied-flag {
  color: var(--fg-dim);
  font-size: 11px;
  letter-spacing: 0.5px;
  border: 1px solid var(--fg-dim);
  padding: 1px 6px;
}

/* ---- Narrow screens ------------------------------------------------------ */
@media (max-width: 520px) {
  #header { gap: 8px; }

  /* Wraps rather than squeezing the button to nothing. Deliberately does NOT
     set justify-content: the base rule already puts links left and button
     right, and overriding it here also hit .sign-actions--centred — same
     specificity, later in the file — which left the post-signing links stuck
     against the left edge instead of centred. [G039] */
  .sign-actions { flex-wrap: wrap; }

  .queue-actions { flex-wrap: wrap; }
  .queue-ip { margin-left: 0; width: 100%; }

  /* A thumb is not a pointer: padding makes these hittable. */
  .pager { flex-wrap: wrap; justify-content: center; row-gap: 8px; }
  .pager-num, .pager-link {
    padding: 6px 8px;
    display: inline-block;
  }

  /* Under the box: side by side the textarea is too narrow to read. */
  .reply-form { flex-direction: column; margin-left: 0; }
  .reply-form textarea { width: 100%; }
  .btn-reply { align-self: flex-start; }

  .entry-reply { margin-left: 0; }
}

/* ============================================================================
   CRT effect — carried over from IMC so both surfaces sit behind the same
   piece of glass.
   ============================================================================ */

@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::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;
}

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;
}

/* Applied to a named list, never to body: an animated text-shadow renders
   softly in Chrome and Safari, which reads as shimmer on large bright text
   and as out-of-focus on small dim text. Anything added later is sharp until
   it opts in. [G041] */
#header .title,
.sign-rule,
.entry-name,
.entry-body {
  animation: crtTextShadow 1.6s infinite;
}

/* Dim text nested inside the elements above would otherwise inherit the
   animation along with everything else. */
.sign-rule .rule-mark,
.entry--queued .entry-name {
  animation: none;
  text-shadow: 0 0 2px currentColor;
}

@media (prefers-reduced-motion: reduce) {
  #header .title,
  .sign-rule,
  .entry-name,
  .entry-body { animation: none; }
  body::after { animation: none; opacity: 0.08; }
}
