/* ==========================================================================
   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 */
  --rule-fade:  rgba(30, 79, 216, .5);  /* the dashes and periods a frame fades into */

  /* A window frame, top to bottom: caught light at the very top, cooling
     through grey and blue-grey into the ANSI blue by a quarter of the way
     down, then thinning away to nothing. Held here so a panel and a card
     can't drift apart, and so the whole frame is one edit. */
  --frame-fade: linear-gradient(180deg,
      var(--white)              0%,
      var(--white)              5%,
      #9fb0c4                   7%,
      #9fb0c4                  10%,
      #5c7fb5                  14%,
      var(--rule)              25%,
      var(--rule)              40%,
      rgba(30, 79, 216, .62)   58%,
      rgba(30, 79, 216, .22)   77%,
      rgba(30, 79, 216, 0)     95%);

  /* The same frame with the light left on - hover keeps the white head so a
     card doesn't lose its lit edge just for being pointed at. */
  --frame-fade-lit: linear-gradient(180deg,
      var(--white)              0%,
      var(--white)              5%,
      #cfe9f5                   8%,
      var(--cyan)              18%,
      var(--cyan)              42%,
      rgba(111, 227, 255, .55) 62%,
      rgba(111, 227, 255, .18) 80%,
      rgba(111, 227, 255, 0)   96%);

  /* 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. */

/* ── The fading frame ──────────────────────────────────────────────────
   Bobby's own border style off the Wildcat screens (see the MAIN1 capture
   in /Old Data/previews): a box opens as a double rule at the top, drops
   to a single line, then to dashes, then to periods before it gives out
   altogether - and the corners fade with it rather than staying square.

   Four stacked layers, each confined to its own band down the height:

     ::before      inner line of the double, gone by a third of the way
     border-image  the main rule, thinning as it descends
     ::after       dashes, faded in and back out across the lower middle
     background    periods along the bottom edge and the tail of each side

   All four are full rectangles, so a corner carries whichever tiers are
   still alive at that height - which is what made the originals look
   like they were dissolving rather than simply stopping. */

.panel {
  position: relative;
  margin: 0 0 26px;
  padding: 26px 26px 22px;
  background:
    repeating-linear-gradient(90deg,  var(--rule-fade) 0 2px, transparent 2px 7px) left bottom  / 100% 1px no-repeat,
    repeating-linear-gradient(180deg, var(--rule-fade) 0 2px, transparent 2px 7px) left bottom  / 1px 20%  no-repeat,
    repeating-linear-gradient(180deg, var(--rule-fade) 0 2px, transparent 2px 7px) right bottom / 1px 20%  no-repeat,
    linear-gradient(180deg, rgba(18, 41, 74, .55), rgba(8, 18, 34, .78));
  /* after the shorthand, which would otherwise reset it: the periods must
     line up with the border box, not the padding box */
  background-origin: border-box;
  border: 1px solid var(--rule);
  border-image-source: var(--frame-fade);
  border-image-slice: 1;
  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 - the second line of the double, masked off before it
   reaches the middle so the box reads as double at the top and single below */
.panel::before {
  content: "";
  position: absolute;
  inset: 3px;
  border: 1px solid rgba(111, 227, 255, .16);
  pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 14%, transparent 38%);
          mask-image: linear-gradient(180deg, #000 0%, #000 14%, transparent 38%);
}

/* The dashed tier, between the single line and the periods. Guarded: without
   masking this would be a dashed box around the whole panel, so browsers that
   can't mask simply go single-line straight to periods. */
@supports (mask-image: linear-gradient(#000, #000)) or (-webkit-mask-image: linear-gradient(#000, #000)) {
  .panel::after {
    content: "";
    position: absolute;
    inset: -1px;
    border: 1px dashed var(--rule-fade);
    pointer-events: none;
    -webkit-mask-image: linear-gradient(180deg, transparent 44%, #000 64%, #000 84%, transparent 97%);
            mask-image: linear-gradient(180deg, transparent 44%, #000 64%, #000 84%, transparent 97%);
  }
}

/* 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);
}
/* Every panel label is flanked the same way: -- == LABEL == --. Set here once
   rather than typed into each heading, so a heading added later can't come out
   undecorated.

   The "==" is typed; the "--" is a painted 13px x 1px line rather than literal
   box-drawing characters, which a screen reader reads out one by one ("box
   drawings light horizontal, left square bracket..."). The second `content`
   carries an empty alternative text, which silences the "==" for assistive
   tech too; the plain declaration above it is the fallback for browsers that
   don't support the alt-text syntax, and it costs them only a spoken
   "equals equals". */
.panel > h2:first-child::before, .panel > h1:first-child::before,
.panel > h2:first-child::after,  .panel > h1:first-child::after {
  content: "==";
  content: "==" / "";
  display: inline-block;
  background-image: linear-gradient(var(--rule), var(--rule));
  background-repeat: no-repeat;
  background-size: 13px 1px;
}
.panel > h2:first-child::before, .panel > h1:first-child::before {
  margin-right: 9px;
  padding-left: 22px;
  background-position: left center;
}
.panel > h2:first-child::after,  .panel > h1:first-child::after {
  margin-left: 9px;
  padding-right: 22px;
  background-position: right center;
}

.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; }
/* Handles on services that no longer exist — kept on the page, dimmed so
   nobody wastes an afternoon trying them. */
.contact .gone { color: var(--frost); opacity: .8; }

@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"],
input[type="password"],
input:not([type]),
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; }

/* Login form error line - polite red, only visible when it has text. */
.form-err { color: #ff6b6b; min-height: 1.2em; margin: 4px 0; }

/* The caller strip: one quiet line under the nav on game pages saying who the
   board thinks you are. Filled in by js/caller.js. */
.callerbar {
  margin: 10px 0 0;
  padding: 6px 12px;
  border: 1px solid var(--rule-dim);
  background: rgba(8, 18, 34, .6);
  color: var(--pale);
  font-size: 13px;
  letter-spacing: .04em;
}
.callerbar b { color: var(--white); }
.callerbar a { color: var(--cyan); }

.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;
}

/* Same dissolving frame as a panel, over a shorter drop. No inner double
   line on these - they're cards inside a window, not windows themselves. */
.game {
  display: flex;
  flex-direction: column;
  position: relative;
  padding: 18px;
  background:
    repeating-linear-gradient(90deg,  var(--rule-fade) 0 2px, transparent 2px 7px) left bottom  / 100% 1px no-repeat,
    repeating-linear-gradient(180deg, var(--rule-fade) 0 2px, transparent 2px 7px) left bottom  / 1px 22%  no-repeat,
    repeating-linear-gradient(180deg, var(--rule-fade) 0 2px, transparent 2px 7px) right bottom / 1px 22%  no-repeat,
    linear-gradient(rgba(8, 18, 34, .7), rgba(8, 18, 34, .7));
  background-origin: border-box;
  border: 1px solid var(--rule);
  border-image-source: var(--frame-fade);
  border-image-slice: 1;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12);
}

/* Hover re-lights the whole frame in cyan - border-color can't do it once
   border-image is in play, so the gradient itself is swapped. */
.game:hover {
  border-image-source: var(--frame-fade-lit);
}

@supports (mask-image: linear-gradient(#000, #000)) or (-webkit-mask-image: linear-gradient(#000, #000)) {
  .game::after {
    content: "";
    position: absolute;
    inset: -1px;
    border: 1px dashed var(--rule-fade);
    pointer-events: none;
    -webkit-mask-image: linear-gradient(180deg, transparent 48%, #000 68%, #000 86%, transparent 98%);
            mask-image: linear-gradient(180deg, transparent 48%, #000 68%, #000 86%, transparent 98%);
  }
}

.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 */
}

/* The Pit runs in js-dos (DOSBox in the browser); the DOS screen is 4:3 and
   the emulator letterboxes inside whatever frame it gets, so this is sized to
   show the 640x480 screen crisply at 2x-ish with the player's side controls. */
.game-frame.g-thepit {
  max-width: 1020px;
  height: 720px;
  background: #000;      /* DOS black, no flash */
}

/* Pimp Wars is a text-mode door (720x400, so 9:5) rather than a graphics-mode
   game like The Pit - shorter frame, or js-dos letterboxes it with a fat black
   band top and bottom. */
.game-frame.g-pimpwars {
  max-width: 1020px;
  height: 640px;
  background: #000;
}

/* Trade Wars is text-mode too, but it draws full 80x25 ANSI star maps and
   sector displays that get hard to read letterboxed - give it a little more
   room than Pimp Wars. */
.game-frame.g-tw {
  max-width: 1020px;
  height: 680px;
  background: #000;
}

/* LORD is text-mode 80x25 like Trade Wars, and it fills the screen with ANSI
   town and forest art, so it wants the same taller frame. */
.game-frame.g-lord {
  max-width: 1020px;
  height: 680px;
  background: #000;
}

/* 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; }
}
