/* ==========================================================================
   Bobby's World BBS - "Glacier" theme
   Palette lifted from the original Wildcat! ANSI screens (see /Sourceart):
   black field, electric blue box rule, cyan/white text, red used sparingly.
   Everything is meant to read as carved out of ice.
   ========================================================================== */

:root {
  /* field */
  --void:       #04070f;
  --deep:       #081222;
  --panel:      #0b1a30;
  --panel-lit:  #12294a;

  /* ice */
  --rule:       #1e4fd8;   /* the ANSI blue box-drawing rule */
  --rule-dim:   #16305f;   /* decorative only - too dim for a control edge */

  /* Border colour for things you can actually interact with. WCAG wants 3:1
     against the background for control boundaries; --rule-dim manages 1.56,
     so inputs and buttons use this instead. */
  --edge:       #3268c4;
  --cyan:       #6fe3ff;
  --frost:      #a9dcf5;
  --pale:       #cfefff;
  --white:      #f2fbff;

  /* accent - used as sparingly as the original menus used red */
  --ember:      #ff4444;
  --amber:      #ffcc55;

  --mono: "Consolas", "Lucida Console", "DejaVu Sans Mono", "Courier New", monospace;

  --glow: 0 0 6px rgba(111, 227, 255, .35);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--void);
  color: var(--pale);
  font-family: var(--mono);
  font-size: 15px;
  line-height: 1.65;
  /* nothing is ever allowed to push the page wider than the window */
  max-width: 100%;
  overflow-x: hidden;
}

/* same guard for any replaced element that slips through */
img, iframe, svg, video { max-width: 100%; }

/* Frozen-over background: a couple of cold light sources behind everything,
   plus a faint scanline so it still feels like a CRT. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(900px 600px at 15% -10%, rgba(30, 79, 216, .28), transparent 60%),
    radial-gradient(700px 500px at 90% 0%,  rgba(111, 227, 255, .12), transparent 60%),
    radial-gradient(1000px 700px at 50% 110%, rgba(20, 60, 130, .30), transparent 65%);
}
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255, 255, 255, .022) 0px,
    rgba(255, 255, 255, .022) 1px,
    transparent 1px,
    transparent 3px
  );
}

.wrap {
  max-width: 980px;
  margin: 0 auto;
  padding: 0 18px 60px;
}

/* ------------------------------------------------------------ a11y --- */

/* Available to screen readers, invisible on screen. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Lets a keyboard user jump the masthead and nav on every page. Hidden until
   focused, then it lands in the top-left like any other skip link. */
.skip {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 100;
  padding: 10px 18px;
  background: var(--panel-lit);
  color: var(--white);
  font-size: 13px;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--cyan);
  transition: top .12s;
}
.skip:focus {
  top: 12px;
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

/* A visible focus ring everywhere, not just on the nav. Keyboard users need to
   see where they are; the default ring is nearly invisible on this palette. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

/* Jumping to #content should not draw a ring around the whole page. */
main:focus { outline: none; }

/* -------------------------------------------------------------- masthead -- */
/* Full-bleed glacier plate. The bright photo would read as a sticker pasted on
   a black page, so the bottom and sides are dissolved into the page colour --
   it becomes a lit opening in the ice rather than a rectangle. */

.masthead {
  position: relative;
  width: 100%;
  line-height: 0;
  overflow: hidden;
  background: var(--void);
}

/* The plate is capped at the artwork's own width so it is never upscaled past
   native, and centred once the window is wider than that. Height follows the
   aspect ratio - no object-fit, so the lettering is never cropped. */
.masthead-inner {
  position: relative;
  width: 100%;
  max-width: 1600px;
  margin: 0 auto;
}

.masthead img {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
}

/* vertical dissolve into the page */
.masthead-inner::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to bottom,
      rgba(4, 7, 15, .25) 0%,
      rgba(4, 7, 15, 0) 22%,
      rgba(4, 7, 15, 0) 52%,
      rgba(4, 7, 15, .55) 82%,
      var(--void) 100%),
    linear-gradient(to right,
      var(--void) 0%,
      rgba(4, 7, 15, 0) 14%,
      rgba(4, 7, 15, 0) 86%,
      var(--void) 100%);
}

/* a cold rule catching the light where the photo meets the terminal */
.masthead-inner::before {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  z-index: 1;
  background: linear-gradient(90deg, transparent, var(--rule) 25%, var(--cyan) 50%, var(--rule) 75%, transparent);
  opacity: .55;
}

.tagline {
  margin: 18px 0 0;
  text-align: center;
  color: var(--frost);
  font-size: 13px;
  letter-spacing: .28em;
  text-transform: uppercase;
  text-shadow: var(--glow);
}
.tagline .sep { color: var(--rule); }

@media (max-width: 700px) {
  .tagline { font-size: 11px; letter-spacing: .18em; }
}

/* ------------------------------------------------------------------- nav -- */

nav.mainnav {
  margin: 22px 0 30px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

nav.mainnav a {
  display: block;
  padding: 9px 20px;
  color: var(--frost);
  text-decoration: none;
  font-size: 13px;
  letter-spacing: .18em;
  text-transform: uppercase;
  background: linear-gradient(180deg, rgba(111, 227, 255, .10), rgba(30, 79, 216, .10));
  border: 1px solid var(--edge);
  /* the bevel: lit from above, like a block of ice */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .22),
    inset 0 -1px 0 rgba(0, 0, 0, .45);
  transition: color .12s, background .12s, box-shadow .12s;
}
nav.mainnav a:hover,
nav.mainnav a:focus-visible {
  color: var(--white);
  background: linear-gradient(180deg, rgba(111, 227, 255, .28), rgba(30, 79, 216, .22));
  border-color: var(--cyan);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .45),
    inset 0 -1px 0 rgba(0, 0, 0, .45),
    0 0 14px rgba(111, 227, 255, .38);
  /* no outline:none here - a keyboard user needs the ring, and the glow alone
     is too subtle to locate focus on this dark palette */
}
nav.mainnav a[aria-current="page"] {
  color: var(--white);
  border-color: var(--cyan);
  background: linear-gradient(180deg, rgba(111, 227, 255, .22), rgba(30, 79, 216, .28));
  text-shadow: var(--glow);
}

/* ----------------------------------------------------------------- panel -- */
/* The ANSI menus drew everything inside a labelled box. Same idea, in ice. */

.panel {
  position: relative;
  margin: 0 0 26px;
  padding: 26px 26px 22px;
  background: linear-gradient(180deg, rgba(18, 41, 74, .55), rgba(8, 18, 34, .78));
  border: 1px solid var(--rule);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .16),
    inset 0 0 40px rgba(30, 79, 216, .14),
    0 0 24px rgba(0, 0, 0, .55);
  backdrop-filter: blur(2px);
}

/* frosted inner rule, echoing the double-line box drawing */
.panel::before {
  content: "";
  position: absolute;
  inset: 3px;
  border: 1px solid rgba(111, 227, 255, .16);
  pointer-events: none;
}

/* Only the heading that opens a panel gets the notched-label treatment. A
   second heading inside the same panel is a subhead, not another label -
   which lets pages use h2 for sub-sections instead of skipping to h3. */
.panel > h2:first-child,
.panel > h1:first-child {
  margin: -38px 0 18px;
  display: inline-block;
  padding: 2px 14px;
  background: var(--void);
  color: var(--cyan);
  font-size: 15px;
  font-weight: bold;
  letter-spacing: .2em;
  text-transform: uppercase;
  text-shadow: var(--glow);
  border: 1px solid var(--rule);
}
/* The flanking rules on a panel label are decoration. They used to be literal
   box-drawing characters, which a screen reader reads out one by one ("box
   drawings light horizontal, left square bracket..."). Drawn as empty boxes
   instead: identical on screen, silent to assistive tech. */
.panel > h2:first-child::before, .panel > h1:first-child::before,
.panel > h2:first-child::after,  .panel > h1:first-child::after {
  content: "";
  display: inline-block;
  width: 13px;
  height: 1px;
  vertical-align: middle;
  background: var(--rule);
}
.panel > h2:first-child::before, .panel > h1:first-child::before { margin-right: 9px; }
.panel > h2:first-child::after,  .panel > h1:first-child::after  { margin-left: 9px; }

.panel h3,
.panel > h2:not(:first-child) {
  margin: 26px 0 10px;
  color: var(--white);
  font-size: 14px;
  letter-spacing: .14em;
  text-transform: uppercase;
}
/* Triangle bullet drawn with borders rather than the "\25B8" character, which
   is announced as "black right-pointing small triangle". */
.panel h3::before,
.panel > h2:not(:first-child)::before {
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  margin-right: 9px;
  vertical-align: middle;
  border-left: 6px solid var(--cyan);
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
}

.panel p { margin: 0 0 14px; }
.panel p:last-child { margin-bottom: 0; }

a { color: var(--cyan); }
a:hover { color: var(--white); text-shadow: var(--glow); }

hr {
  border: 0;
  height: 1px;
  margin: 24px 0;
  background: linear-gradient(90deg, transparent, var(--rule), transparent);
}

/* Contact pairs. A definition list so the label and its value are actually
   associated, rather than being one run-on paragraph full of <br>. */
.contact {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 8px 20px;
  margin: 0 0 8px;
}
.contact dt {
  color: var(--cyan);
  font-size: 12px;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding-top: 2px;
}
.contact dd { margin: 0; }
.contact .aka { color: var(--frost); font-size: 13px; }

@media (max-width: 520px) {
  .contact { grid-template-columns: 1fr; gap: 2px; }
  .contact dd { margin-bottom: 10px; }
}

.sig {
  margin-top: 22px;
  color: var(--frost);
  font-size: 13px;
  letter-spacing: .12em;
}
.sig::before {
  content: "";
  display: inline-block;
  width: 30px;
  height: 1px;
  margin-right: 10px;
  vertical-align: middle;
  background: var(--rule);
}

/* ------------------------------------------------------------------ home -- */

.hero {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 30px;
  align-items: start;
}

/* Portrait framed like a block of ice, with a highlight raking across it */
.portrait {
  position: relative;
  padding: 8px;
  background: linear-gradient(160deg, rgba(207, 239, 255, .30), rgba(30, 79, 216, .18) 45%, rgba(4, 7, 15, .55));
  border: 1px solid var(--rule);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .40),
    0 0 26px rgba(30, 79, 216, .30);
}
.portrait img {
  display: block;
  width: 100%;
  height: auto;
  filter: saturate(.85) contrast(1.05);
}
.portrait::after {
  content: "";
  position: absolute;
  inset: 8px;
  pointer-events: none;
  background: linear-gradient(150deg, rgba(255, 255, 255, .26) 0%, transparent 38%);
}
.portrait figcaption {
  margin-top: 8px;
  color: var(--cyan);
  font-size: 12px;
  letter-spacing: .18em;
  text-align: center;
  text-transform: uppercase;
}

/* ---------------------------------------------------------------- roster -- */

.roster {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}

.member {
  padding: 14px;
  background: rgba(8, 18, 34, .7);
  border: 1px solid var(--rule-dim);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12);
}
.member:hover { border-color: var(--cyan); }
.member img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border: 1px solid var(--rule-dim);
  margin-bottom: 10px;
}
.member .handle {
  color: var(--white);
  font-weight: bold;
  letter-spacing: .1em;
}
/* The angle brackets around a handle were read as "less than / greater than"
   before every name. The handle is already bold and white, which carries the
   same emphasis without the noise. */
.member .real { color: var(--frost); font-size: 13px; }
.member .aka  { color: var(--frost); font-size: 12px; opacity: .8; }
.member .links { margin-top: 8px; font-size: 12px; display: flex; flex-wrap: wrap; gap: 10px; }

.empty {
  color: var(--frost);
  opacity: .75;
  font-style: italic;
}

/* ------------------------------------------------------------------ form -- */

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px 18px;
}
.field { display: flex; flex-direction: column; gap: 5px; }
.field.wide { grid-column: 1 / -1; }

label {
  color: var(--cyan);
  font-size: 12px;
  letter-spacing: .16em;
  text-transform: uppercase;
}
label .opt { color: var(--frost); opacity: .6; text-transform: none; letter-spacing: 0; }

input[type="text"],
input[type="email"],
input[type="url"],
input[type="file"],
textarea {
  width: 100%;
  padding: 9px 11px;
  background: rgba(4, 7, 15, .8);
  color: var(--white);
  font-family: var(--mono);
  font-size: 14px;
  border: 1px solid var(--edge);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, .6);
}
input:focus, textarea:focus {
  border-color: var(--cyan);
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, .6), 0 0 12px rgba(111, 227, 255, .30);
}
textarea { min-height: 90px; resize: vertical; }

.btn {
  display: inline-block;
  margin-top: 18px;
  padding: 11px 30px;
  color: var(--white);
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: .2em;
  text-transform: uppercase;
  cursor: pointer;
  background: linear-gradient(180deg, rgba(111, 227, 255, .26), rgba(30, 79, 216, .32));
  border: 1px solid var(--cyan);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .40),
    inset 0 -1px 0 rgba(0, 0, 0, .45);
}
.btn:hover { box-shadow: inset 0 1px 0 rgba(255,255,255,.55), 0 0 18px rgba(111, 227, 255, .45); }
.btn:disabled { opacity: .5; cursor: default; box-shadow: none; }

.notice {
  margin-top: 16px;
  padding: 12px 14px;
  border: 1px solid var(--rule);
  background: rgba(30, 79, 216, .14);
  color: var(--pale);
  font-size: 14px;
}
.notice.err { border-color: var(--ember); background: rgba(255, 68, 68, .10); color: #ffd6d6; }
.notice.ok  { border-color: var(--cyan);  background: rgba(111, 227, 255, .12); }

/* ---------------------------------------------------------------- quotes -- */
/* Lines lifted straight out of the old message base, with the colours the
   original @XX@ codes gave them. */

.quotebox {
  min-height: 132px;                /* keeps the panel from jumping on rotate */
  display: flex;
  flex-direction: column;
}

.quote-body {
  flex: 1;
  font-size: 15px;
  line-height: 1.7;
}
.quote-line { display: block; }
.quote-line:empty { display: none; }

.quote-by {
  margin-top: 14px;
  color: var(--cyan);
  font-size: 12px;
  letter-spacing: .18em;
  text-transform: uppercase;
  font-style: normal;
}
/* the -=≡ NAME ≡=- flourish from the original, drawn so it is not read out */
.quote-by::before,
.quote-by::after {
  content: "";
  display: inline-block;
  width: 18px;
  height: 1px;
  vertical-align: middle;
  background: var(--rule);
}
.quote-by::before { margin-right: 10px; }
.quote-by::after  { margin-left: 10px; }

.quote-controls {
  margin-top: 14px;
  display: flex;
  gap: 8px;
}
.quote-controls button {
  padding: 5px 16px;
  background: transparent;
  color: var(--frost);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
  border: 1px solid var(--edge);
  cursor: pointer;
}
.quote-controls button:hover {
  color: var(--white);
  border-color: var(--cyan);
}

/* ----------------------------------------------------------------- games -- */

.games {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px;
}

.game {
  display: flex;
  flex-direction: column;
  padding: 18px;
  background: rgba(8, 18, 34, .7);
  border: 1px solid var(--rule);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12);
}
.game:hover { border-color: var(--cyan); }

.game h2 {
  margin: 0 0 4px;
  color: var(--white);
  font-size: 16px;
  letter-spacing: .1em;
}
.game .tag {
  margin: 0 0 10px;
  color: var(--cyan);
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.game p { margin: 0 0 14px; font-size: 14px; }

/* push the button to the bottom so cards line up regardless of text length */
.game .play {
  margin-top: auto;
  align-self: flex-start;
  padding: 9px 26px;
  color: var(--white);
  text-decoration: none;
  font-size: 12px;
  letter-spacing: .2em;
  text-transform: uppercase;
  background: linear-gradient(180deg, rgba(111, 227, 255, .22), rgba(30, 79, 216, .30));
  border: 1px solid var(--cyan);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .35),
    inset 0 -1px 0 rgba(0, 0, 0, .45);
}
.game .play:hover {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), 0 0 16px rgba(111, 227, 255, .42);
}

.credits {
  color: var(--frost);
  font-size: 12px;
  opacity: .85;
}

/* ------------------------------------------------------------------ chat -- */

.chat-frame {
  width: 100%;
  height: 620px;
  border: 1px solid var(--rule);
  background: var(--void);
  box-shadow: inset 0 0 40px rgba(30, 79, 216, .18);
}

/* A game running inside the site chrome. A Dark Room is NOT responsive: its
   layout is a fixed 920px-wide (700px play area + 220px notification column)
   by ~760px-tall box. The frame is sized to contain that exactly so neither
   scrollbar appears. See .wrap-wide / .game-panel below - the normal content
   column is too narrow to hold it. */
.game-frame {
  display: block;
  width: 100%;
  height: 784px;
  margin: 0 auto;
  border: 1px solid var(--rule);
  background: #000;
  box-shadow: inset 0 0 40px rgba(30, 79, 216, .18);
}

/* This page's column is widened so the 920px game fits without clipping. */
.wrap-wide { max-width: 1010px; }
.game-panel { padding-left: 12px; padding-right: 12px; }

/* 2048 is a narrow 500px game; the window hugs it and shows the whole grid.
   Width stays above the game's 520px mobile breakpoint so the desktop layout
   is used. */
.game-frame.g-2048 {
  max-width: 530px;
  height: 812px;
  background: #faf8ef;   /* 2048's own cream, so no dark flash before it loads */
}

/* Hextris fills its canvas to the window and scales the hexagon to the smaller
   side, so a near-square window gives the largest play area. Fully responsive,
   so this is just a comfortable frame. */
.game-frame.g-hextris {
  max-width: 840px;
  height: 720px;
  background: #ecf0f1;   /* Hextris's own light background */
}

/* DopeWars (Bootstrap) shows its two-column desktop layout at >=992px wide, so
   this page is widened enough to give the frame that room; below that it
   gracefully stacks. */
.wrap-xwide { max-width: 1080px; }
.game-frame.g-dopewars {
  max-width: 1020px;
  height: 720px;
  background: #fff;      /* Bootstrap's white body */
}

/* Collapsible how-to-play, folded away until wanted. */
.howto {
  margin-top: 18px;
  border: 1px solid var(--rule-dim);
  background: rgba(8, 18, 34, .6);
}
.howto > summary {
  padding: 12px 16px;
  color: var(--cyan);
  font-size: 13px;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
}
.howto > summary::-webkit-details-marker { display: none; }
.howto > summary::before { content: "\25B8"; margin-right: 10px; display: inline-block; }
.howto[open] > summary::before { transform: rotate(90deg); }
.howto > summary:hover { color: var(--white); }
.howto .howto-body { padding: 0 18px 16px; }
.howto .howto-body p { margin: 0 0 12px; font-size: 14px; }
.howto .howto-body ol { margin: 0 0 12px; padding-left: 20px; }
.howto .howto-body li { margin-bottom: 8px; font-size: 14px; }
.howto .howto-body strong { color: var(--white); }

.cmdlist { list-style: none; margin: 0; padding: 0; columns: 2; column-gap: 30px; }
.cmdlist li { break-inside: avoid; margin-bottom: 6px; font-size: 13px; }
.cmdlist code {
  color: var(--amber);
  background: rgba(0, 0, 0, .4);
  padding: 1px 6px;
  border: 1px solid var(--rule-dim);
}

/* ---------------------------------------------------------------- footer -- */

footer.site {
  margin-top: 40px;
  padding-top: 18px;
  border-top: 1px solid var(--rule-dim);
  color: var(--frost);
  font-size: 12px;
  letter-spacing: .1em;
  text-align: center;
  opacity: .8;
}
footer.site .ember { color: var(--ember); }

/* ----------------------------------------------------------------- small -- */

@media (max-width: 700px) {
  .hero { grid-template-columns: 1fr; }
  .portrait { max-width: 260px; margin: 0 auto; }
  .cmdlist { columns: 1; }
  nav.mainnav a { padding: 8px 14px; font-size: 12px; }
  .panel { padding: 24px 16px 18px; }
}
