﻿/* ============================================================================
   TINY HATS -- THE 2002 LAYER
   ============================================================================

   A stylistic pass, not a rebuild. Every page keeps its markup, its copy and
   its behaviour; this file sits on top and repaints it as a light GeoCities
   era page: tiled wallpaper, silver bevelled chrome, Comic Sans headings,
   Times body copy.

   HOW IT LOADS
   Last in the <head> of every page, after that page's own <style>, so plain
   selectors already win. `!important` is used only where a rule has to beat an
   inline style="" attribute written by JS, and each of those is marked.

   HOW TO TURN IT OFF
   Add ?retro=off to any URL, or run localStorage.setItem('retro','off') once.
   retro.js reads that before anything paints and removes this stylesheet, so
   the original terminal look comes straight back. Nothing here is destructive.

   WHAT IT DELIBERATELY DOES NOT TOUCH
   - <canvas> content. The Hat Lounge, Rundle Mall, the Courtroom and the
     Dilemma are drawn pixel art, and a stylesheet has no business inside them.
   - The game iframe on stage.html, which must stay full bleed and tappable.
   Both get a bevelled frame around the outside and are otherwise left alone.

   THE PALETTE
   Sam's six colours are unchanged and carry all the meaning: green is still
   go, amber is still the accent, red is still an error. The silver chrome
   around them is the only thing added, and it is chrome, never content.
   ========================================================================= */

/* ---- The heading face ----------------------------------------------------
   Block Blueprint, the 8-bit face Sam supplied. Served from our own origin as
   woff2 (10kb, against 68kb for the ttf) with the ttf behind it for anything
   too old to take woff2. swap, so a slow font never leaves a heading blank. */
@font-face {
  font-family: 'BlockBlueprint';
  src: url('/fonts/BlockBlueprint.woff2') format('woff2'),
       url('/fonts/BlockBlueprint.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

:root {
  /* The original six, untouched. */
  --bg: #050505;
  --text: #2CFF56;
  --accent: #FFB200;
  --dark: #111111;
  --error: #FF3333;
  --white: #FFFFFF;

  /* Chrome only. Windows 98 needs a light, a face and two shadows to fake a
     bevel, and no amount of cleverness gets that out of six dark colours. */
  --r-face:  #C0C0C0;
  --r-light: #FFFFFF;
  --r-shade: #808080;
  --r-dark:  #404040;
  --r-ink:   #000080;   /* the title-bar blue everyone remembers */
  --r-page:  #E8E8F0;

  /* Green, amber and red are luminous on black and unreadable on silver, so
     each gets one darkened form for use as text on the light chrome. Same hue,
     same meaning, enough contrast to actually read.

     These three are not eyeballed. Each was solved against the #C0C0C0 panel
     for a contrast ratio of at least 4.5:1, the point at which normal-sized
     text is legible to most people. The first attempt used lighter versions
     and measured 3.7:1, which still looked washed out on the stage cards. */
  --r-green-ink: #0A5417;   /* 5.0:1 on #C0C0C0 */
  --r-amber-ink: #5E4100;   /* 5.2:1 */
  --r-error-ink: #8B0000;   /* 5.5:1 */

  /* The originals, kept under new names for the handful of places that still
     have a genuinely dark background: the counter's LED digits, the marquee,
     the loading screen. Neon needs black behind it and nothing else. */
  --r-neon-green: #2CFF56;
  --r-neon-amber: #FFB200;
}

/* ---- The neon, retired --------------------------------------------------
   Chasing individual selectors was never going to finish. There are more than
   eighty `color: var(--text)` rules across the pages, plus inline styles the
   JS writes, and every one of them was drawn for a near-black screen. On the
   light wallpaper they came out as neon green on pale grey, which is the
   least readable combination on the page.

   So the variables themselves are redefined for the duration of the theme.
   One change, and every rule and inline style that ever referenced them
   becomes readable at once, including any written in future.

   --bg is deliberately NOT remapped. It is used as the text colour on the few
   solid-fill buttons, where near-black is exactly right. */
html.retro {
  --text: #101018;
  --accent: #000080;
  --error: #8B0000;
  --dark: #C0C0C0;
}

/* The admin panel was built on a completely separate warm-paper palette of
   its own. Half-repainting it left cream cards inside silver chrome and three
   labels down at 1.75 to 1, so its variables are remapped the same way. Sam
   asked for the look on every part of the site, and the workshop counts. */
html.retro {
  --page: var(--r-page);
  --card: #D8D8E0;
  --line: #808090;
  --row:  #CFCFD8;
  --ink:  #101018;
  --muted: #3A3A46;
  --faint: #55555F;
  --green: #0A5417;
  --green-ink: #0A5417;
  --amber: #5E4100;
  --amber-bg: #E4E4EC;
  --amber-line: #808090;
  --red: #8B0000;
}

/* ---- Wallpaper -----------------------------------------------------------
   A tiled background, because in 2002 everything was a tiled background. Drawn
   as a data URI so it costs no request and cannot 404. */
html.retro,
html.retro body {
  background: var(--r-page) url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'>\
<rect width='32' height='32' fill='%23E8E8F0'/>\
<path d='M0 0h32v1H0zM0 0v32h1V0z' fill='%23FFFFFF'/>\
<path d='M0 31h32v1H0zM31 0v32h1V0z' fill='%23D2D2DC'/>\
<circle cx='16' cy='16' r='1.5' fill='%23C8C8D4'/>\
</svg>") repeat !important;   /* beats each page's own body background */
  color: #000 !important;
}

/* The CRT scanlines and phosphor vignette belong to the old look. A 2002 page
   was a page, not a monitor. */
html.retro body::before,
html.retro body::after { display: none !important; }

/* ---- Type ----------------------------------------------------------------
   Verdana for body copy, Comic Sans for headings and accents, Times for the
   quieter prose. The pixel font stays only where the game itself uses it. */
html.retro body,
html.retro input,
html.retro textarea,
html.retro select,
html.retro button {
  font-family: var(--font-window, Verdana, Geneva, Arial, sans-serif) !important;
}

/* Every heading is Block Blueprint. It is an 8-bit face, so it needs letter
   spacing to breathe and must never be italicised or faux-bolded. */
html.retro h1,
html.retro h2,
html.retro h3,
html.retro .club-title,
html.retro .ascii-title,
html.retro .season-badge,
html.retro .stage-title,
html.retro .r-marquee span,
html.retro #r-loader .r-load-text {
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive) !important;
  font-weight: normal !important;
  font-style: normal !important;
  letter-spacing: 0.06em !important;
}

/* The chunky kind of drop shadow: a hard offset copy, no blur. */
html.retro h1,
html.retro h2,
html.retro .club-title {
  color: var(--r-ink) !important;
  text-shadow: 2px 2px 0 #FFFFFF, 3px 3px 0 var(--r-shade) !important;
  letter-spacing: 0 !important;
}

html.retro p,
html.retro .club-tagline,
html.retro .dim,
html.retro .stage-date {
  font-family: var(--font-serif, "Times New Roman", Times, serif) !important;
  color: #202020 !important;
}

/* ---- The hat itself ------------------------------------------------------
   The welcome screen's hat was five lines of ASCII art in glowing amber, which
   is the single worst thing to put on grey. It is replaced by the actual hat:
   frame 0 of hat-sheet.png, cut out and squared up by scripts/build-hat-icon.py
   into /img/hat-icon.png, so the club's hat and the hat you walk around the
   Lounge as are finally the same object.

   The ASCII stays in the markup and is simply hidden, so ?retro=off still gets
   the original screen and nothing was thrown away. */
html.retro .club-hat {
  font-size: 0 !important;          /* hides the ASCII without removing it */
  text-shadow: none !important;
  width: 96px;
  height: 96px;
  margin: 0 auto 1.2rem !important;
  background: url('/img/hat-icon.png') center / contain no-repeat;
  image-rendering: pixelated;
}

/* The scan page's easter-egg hat gets the same treatment, smaller. */
html.retro #skip-egg .egg-hat {
  font-size: 0 !important;
  width: 56px;
  height: 56px;
  margin: 0.4rem auto !important;
  background: url('/img/hat-icon.png') center / contain no-repeat;
  image-rendering: pixelated;
}
html.retro #skip-egg .egg-hat br { display: none; }

/* The banner used to be two blocks of ASCII art spelling TINY HATS. At the
   sizes a phone gives it the letters broke into loose strokes and stopped
   reading as words at all. Now the <pre> is emptied and the title is set as
   real text in Block Blueprint, which is the same idea done properly: still
   blocky, still pixel, but legible and it scales.

   The markup keeps its ASCII, hidden, so ?retro=off restores the old banner. */
html.retro .ascii-title {
  font-size: 0 !important;              /* swallows the ASCII */
  text-shadow: none !important;
  background: none !important;
  border: none !important;
  padding: 0 !important;
  margin: 0 auto 1.6rem !important;
  white-space: normal !important;
  text-align: center;
}

html.retro .ascii-title::after {
  content: 'TINY HATS';
  display: block;
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive);
  font-size: clamp(2rem, 9vw, 3.6rem);
  line-height: 1.05;
  letter-spacing: 0.08em;
  color: var(--r-ink);
  /* The chunky 2002 drop shadow: hard offsets, no blur. */
  text-shadow: 2px 2px 0 var(--r-light), 4px 4px 0 var(--r-shade);
}

/* ---- Neon on silver ------------------------------------------------------
   The six colours were picked to glow on near-black. Put #2CFF56 on a #C0C0C0
   panel and it measures 1.01:1 against its background, which is not "low
   contrast", it is invisible: the first build of this theme had stage titles
   nobody could read. Anything that sits on the silver chrome is remapped to
   the darkened ink form of the same colour, so the meaning survives (green is
   still go, amber is still the accent) and the words come back.

   The glows go with them. A text-shadow built to bloom on black turns into a
   smear on light grey. */
html.retro .stage-title,
html.retro .completed .stage-title,
html.retro .stage-card .stage-title { color: #000 !important; text-shadow: none !important; }

html.retro .completed .cb { color: var(--r-ink) !important; text-shadow: none !important; }
html.retro .completed .stage-date { color: #3A3A3A !important; text-shadow: none !important; }

/* Amber never touches the silver. It is a glow colour, built for the black
   terminal, and as text on grey chrome it reads as a smudge however far it is
   darkened. Everything that was amber on a panel is navy instead, which is the
   period-correct accent and the one this layer already uses for headings and
   links. Amber survives wherever the background is still dark: the marquee,
   the loading bar, the canvas rooms, the fire. */
html.retro .current .cb,
html.retro .current .stage-title,
html.retro .season-badge,
html.retro .club-sub,
html.retro .hat-name,
html.retro .checkpoint-label,
html.retro .back,
html.retro .back-link a,
html.retro .toggle-link a,
html.retro #clue-modal-label,
html.retro #privacy-box h3,
html.retro #final-end,
html.retro #skip-egg .egg-amber,
html.retro .choice-btn.amber { color: var(--r-ink) !important; text-shadow: none !important; }

/* The welcome hat's ASCII is hidden behind font-size:0 but its colour is still
   amber, which makes it look like a leftover to anything auditing the page.
   Blanked so a sweep for yellow-on-light comes back genuinely empty. */
html.retro .club-hat,
html.retro #skip-egg .egg-hat { color: transparent !important; }

html.retro .season-badge {
  background: var(--r-face);
  border: 2px solid !important;
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark) !important;
  box-shadow: none !important;
  font-weight: bold;
}

html.retro .stage-num,
html.retro .player-name { color: #3A3A3A !important; text-shadow: none !important; }

/* The level badge: a pressed-in well with the number in it, like a score
   readout on a cabinet. */
html.retro .level-badge {
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive) !important;
  font-size: 0.85rem !important;
  color: var(--r-ink) !important;
  background: var(--r-face) !important;
  border: 2px solid !important;
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark) !important;
  text-shadow: none !important;
  padding: 4px 12px !important;
  margin-top: 0.3rem;
}

/* The pages use #555 and #6a6a6a for quiet text. Those were chosen to sit
   just above a near-black background; on the silver panels they land between
   4.1 and 4.4 to 1, which is under the bar. Nudged to a grey that clears it
   while still reading as secondary. */
html.retro .lede,
html.retro .form-box .lede,
html.retro .hat-desc,
html.retro .sub,
html.retro .hint,
html.retro .muted,
html.retro .faint { color: #3A3A3A !important; }

html.retro .error-msg,
html.retro .danger { color: var(--r-error-ink) !important; text-shadow: none !important; }

/* The checkbox square keeps the bevel rather than the neon outline. */
html.retro .cb {
  background: var(--white);
  border: 2px solid !important;
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark) !important;
  font-weight: bold;
}

/* Nothing on a silver panel should still be glowing. Catch-all for the inline
   text-shadows the pages write directly onto elements. */
html.retro .stage-card *,
html.retro .form-box *,
html.retro .season-badge { text-shadow: none !important; }

/* ---- Overlays ------------------------------------------------------------
   The three full-screen panels (privacy, "operative registered", and the
   returning-player welcome) were written with their colours in style=""
   attributes on the elements themselves, so the theme walked straight past
   them and they stayed pure 1998 terminal in the middle of a 2002 page. Every
   rule here needs !important for that reason, and only for that reason.

   The scrim goes from near-black to a light wash, and the panel inside it
   becomes the same bevelled silver box as everything else. */
html.retro #privacy-overlay,
html.retro #assigned-overlay {
  background: rgba(40, 40, 60, 0.55) !important;
}

html.retro #assigned-overlay > div,
html.retro #privacy-box,
html.retro #welcome-screen {
  background: var(--r-face) !important;
  border: 2px solid !important;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light) !important;
  box-shadow: 1px 1px 0 var(--r-shade) inset,
              -1px -1px 0 var(--r-light) inset,
              4px 4px 0 rgba(0, 0, 0, 0.3) !important;
  color: #000 !important;
}

/* #welcome-screen is a full-bleed panel rather than a card, so it keeps the
   wallpaper behind it and only its contents get the silver treatment. */
html.retro #welcome-screen {
  background: var(--r-page) !important;
  border: none !important;
  box-shadow: none !important;
}

/* Everything inside an overlay: kill the neon and the glow, and give the
   labels a colour that exists on grey. The #555 greys the pages use are fine
   on black and nearly invisible on silver. */
html.retro #assigned-overlay div,
html.retro #privacy-box div,
html.retro #privacy-box p,
html.retro #welcome-screen div {
  color: #2A2A2A !important;
  text-shadow: none !important;
  opacity: 1 !important;
}

/* The two values the player has to write down are the whole point of that
   screen, so they stay the loudest things on it. */
html.retro #assigned-callsign-display {
  color: var(--r-ink) !important;
  font-family: var(--font-display, 'BlockBlueprint', monospace) !important;
  letter-spacing: 0.04em !important;
}
html.retro #assigned-num-display {
  color: var(--r-ink) !important;
  font-family: var(--font-display, 'BlockBlueprint', monospace) !important;
  letter-spacing: 0.04em !important;
}

/* The headings in those overlays, in the site's heading face. */
html.retro #assigned-overlay > div > div:first-child,
html.retro #welcome-hello {
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive) !important;
  color: var(--r-ink) !important;
}

/* The solid green "LET'S GO" button becomes a bevel like every other button.
   Its inline background and border have to be overridden by name. */
html.retro #assigned-ok,
html.retro #privacy-ok {
  background: var(--r-face) !important;
  color: #000 !important;
  border: 2px solid !important;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light) !important;
  border-left: 6px solid var(--r-green-ink) !important;
  font-family: var(--font-window, Verdana, Geneva, sans-serif) !important;
  font-weight: bold !important;
  letter-spacing: 0 !important;
}

/* The divider inside the overlays, as a 3D groove. */
html.retro #assigned-overlay hr,
html.retro #privacy-box hr {
  border: none !important;
  border-top: 2px solid var(--r-shade) !important;
  border-bottom: 2px solid var(--r-light) !important;
}

html.retro #logout-link { color: var(--r-error-ink) !important; opacity: 1 !important; }

/* ---- Legibility ----------------------------------------------------------
   2002 pages were full of 10px Verdana. That was a mistake then and it is a
   mistake on a phone, so the small print comes up to a readable size. */
html.retro .stage-num { font-size: 0.72rem !important; letter-spacing: 1px !important; }
html.retro .stage-date { font-size: 0.8rem !important; }
html.retro .player-name { font-size: 0.9rem !important; }
html.retro .season-badge { font-size: 0.78rem !important; }

/* ---- The bevel -----------------------------------------------------------
   Two borders and nothing else, exactly as Windows drew it: light on the top
   and left, dark on the bottom and right, with the face between. `.r-out`
   stands proud, `.r-in` is pressed in. */
html.retro .form-box,
html.retro .stage-card,
html.retro #privacy-box,
html.retro #welcome-club,
html.retro .card,
html.retro .panel,
html.retro .tbl {
  background: var(--r-face) !important;
  border: 2px solid !important;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light) !important;
  box-shadow: 1px 1px 0 var(--r-shade) inset,
              -1px -1px 0 var(--r-light) inset,
              3px 3px 0 rgba(0, 0, 0, 0.25) !important;
  border-radius: 0 !important;
  color: #000 !important;
}

/* Inputs are pressed INTO the page, the mirror of a button. */
html.retro input[type="text"],
html.retro input[type="password"],
html.retro input[type="email"],
html.retro input[type="number"],
html.retro textarea,
html.retro select {
  background: var(--white) !important;
  color: #000 !important;
  border: 2px solid !important;
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark) !important;
  border-radius: 0 !important;
  box-shadow: 1px 1px 0 var(--r-shade) inset !important;
  font-size: 1rem !important;
  padding: 5px 6px !important;
}

html.retro input:focus,
html.retro textarea:focus,
html.retro select:focus {
  outline: 1px dotted #000 !important;
  outline-offset: -4px;
}

/* ---- Buttons -------------------------------------------------------------
   Raised, and genuinely pressed on :active, which is the whole joy of it. */
html.retro button,
html.retro .btn,
html.retro a.btn {
  background: var(--r-face) !important;
  color: #000 !important;
  font-family: var(--font-window, Verdana, Geneva, sans-serif) !important;
  font-weight: bold !important;
  font-size: 0.85rem !important;
  letter-spacing: 0 !important;
  border: 2px solid !important;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light) !important;
  border-radius: 0 !important;
  box-shadow: 1px 1px 0 var(--r-shade) inset, -1px -1px 0 var(--r-light) inset !important;
  padding: 6px 14px !important;
  text-shadow: none !important;
  cursor: pointer;
  min-height: 34px;
}

/* Anything driven by a finger gets a 44px target, at EVERY width. Keying this
   off a narrow viewport was wrong: an iPad is 768 to 1024 across and is all
   finger, and that is the device Sam actually plays on. */
@media (pointer: coarse) {
  html.retro button,
  html.retro .btn,
  html.retro a.btn,
  html.retro .nav-links a,
  html.retro .toggle-link a {
    min-height: 44px !important;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    padding: 10px 16px !important;
  }

  /* Every OTHER link too. The site is full of bare anchors that are really
     buttons: "Not you? Log out", "[ BACK TO LOGIN ]", "[ REQUEST A NEW LINK ]".
     They measured 15 to 19px tall, which is a third of a fingertip.
     Links sitting inside a sentence are left alone, because padding them out
     would break the line they live in. */
  html.retro a:not(.btn):not(p a):not(.r-marquee a) {
    display: inline-block;
    min-height: 44px;
    line-height: 2.6;
    padding: 0 6px;
  }

  /* Fields want a thumb-sized hit area as much as buttons do. */
  html.retro input[type="text"],
  html.retro input[type="password"],
  html.retro input[type="email"],
  html.retro input[type="number"],
  html.retro select {
    min-height: 44px !important;
  }
}

/* The header links are bare text on every device, which makes them the
   smallest targets on the page. Give them room to be hit. */
html.retro .nav-links { gap: 1rem !important; }
html.retro .nav-links a,
html.retro .toggle-link a {
  display: inline-block;
  padding: 8px 10px;
  min-height: 34px;
}

html.retro button:active,
html.retro .btn:active,
html.retro a.btn:active {
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark) !important;
  box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3) inset !important;
  padding: 7px 13px 5px 15px !important;   /* the label shifts down and right */
}

html.retro button:disabled,
html.retro .btn:disabled {
  color: var(--r-shade) !important;
  text-shadow: 1px 1px 0 var(--r-light) !important;
}

/* The one button on each screen that matters keeps its colour, as a stripe
   down the left rather than a fill, so the bevel survives. The secondary
   stripe is the dark green rather than amber: a yellow edge against silver
   just looks like a printing error. */
html.retro .btn-play,
html.retro #club-enter,
html.retro #continue-btn {
  border-left: 6px solid var(--r-green-ink) !important;
}
html.retro .btn-clue,
html.retro .btn-replay {
  border-left: 6px solid var(--r-ink) !important;
}

/* ---- Links, with the sparkle --------------------------------------------
   Blue and underlined, as the web intended. The star is a pseudo-element that
   only appears on hover, so it costs nothing and never sits in the way. */
html.retro a {
  color: var(--r-ink) !important;
  text-decoration: underline !important;
  text-shadow: none !important;
}
html.retro a:visited { color: #551A8B !important; }
html.retro a:hover { color: var(--r-error-ink) !important; }

html.retro a:not(.btn):hover::after {
  content: ' \2726';
  color: var(--r-amber-ink);
  animation: r-twinkle 0.6s steps(3, end) infinite;
}

@keyframes r-twinkle {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.4; transform: scale(1.4); }
}

/* ---- The hat cursor ------------------------------------------------------
   The pointer is the hat. Hotspot at 15 31, the centre of the brim, so the
   point you are aiming with is the bottom of the hat rather than its crown.

   Only on a fine pointer: a touch screen has no cursor, and forcing one would
   just cost every visitor a download for nothing.

   Fields keep the text caret and disabled things keep the arrow, because a
   cursor that never changes stops telling you anything. */
@media (pointer: fine) {
  html.retro,
  html.retro body,
  html.retro a,
  html.retro button,
  html.retro .btn,
  html.retro canvas {
    cursor: url('/img/hat-cursor.png') 15 31, auto;
  }

  html.retro input[type="text"],
  html.retro input[type="password"],
  html.retro input[type="email"],
  html.retro input[type="number"],
  html.retro textarea { cursor: text; }

  html.retro button:disabled,
  html.retro .btn:disabled { cursor: default; }
}

/* ---- The ghosting trail --------------------------------------------------
   Hats fall behind the pointer and fade. Spawned by retro.js, one <img> each,
   removed when the animation ends so nothing accumulates.

   pointer-events: none is not optional here. A trail of hats sitting over the
   page that could swallow a click would break every button on the site. */
.r-ghost {
  position: fixed;
  width: 28px;
  height: 28px;
  margin: -14px 0 0 -14px;    /* centred on the point it was dropped at */
  pointer-events: none;
  z-index: 99990;
  image-rendering: pixelated;
  animation: r-ghost-fade 620ms ease-out forwards;
}

@keyframes r-ghost-fade {
  from { opacity: 0.55; transform: scale(1) rotate(0deg); }
  to   { opacity: 0;    transform: scale(0.55) rotate(-14deg) translateY(10px); }
}

/* ---- Rules ---------------------------------------------------------------
   The 3D groove, drawn the way a <hr> looked before anyone styled one. */
html.retro hr,
html.retro .r-hr {
  height: 0 !important;
  border: none !important;
  border-top: 2px solid var(--r-shade) !important;
  border-bottom: 2px solid var(--r-light) !important;
  margin: 1.2rem 0 !important;
}

/* ---- Marquee -------------------------------------------------------------
   Injected by retro.js at the top of the page. CSS animation rather than the
   <marquee> tag, so it stays honest markup and respects reduced motion. */
.r-marquee {
  position: relative;
  overflow: hidden;
  background: var(--r-ink);
  border: 2px solid;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light);
  padding: 4px 0;
  margin-bottom: 0.8rem;
  white-space: nowrap;

  /* The bar is the first child of <body>, and several pages make <body> a
     centred flex column. A nowrap flex item sizes to its text, so without
     these the bar grew to the full length of the announcement (1600px in a
     730px window) and pushed the whole page sideways. Pinned to the viewport
     instead, which also keeps it out of every page's own layout. */
  box-sizing: border-box;
  flex: 0 0 auto;
  align-self: stretch;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  max-width: 100%;
  z-index: 9997;
  margin: 0;
}

/* Room for the fixed bar, so it never sits over the first line of the page. */
html.retro body { padding-top: 2.4rem !important; }

.r-marquee span {
  display: inline-block;
  padding-left: 100%;
  color: var(--r-neon-amber);   /* on the navy bar, so the real amber */
  font-family: var(--font-silly, "Comic Sans MS", cursive);
  font-size: 0.85rem;
  /* Slow. At 22s the text went past faster than it could be read, which
     defeats the point of an announcement. */
  animation: r-scroll 55s linear infinite;
}

@keyframes r-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}

/* ---- The stage screens ---------------------------------------------------
   The cutscene, the Courtroom, the Dilemma and the Waiting Game each throw up
   a full-screen root of their own, built in JS with the colours written into
   a style="" string: background var(--bg), colour var(--text).

   That combination broke when the palette was remapped. --text became the
   dark green ink so it could be read on silver, but --bg was deliberately
   left near-black, so these four screens ended up dark green on black at
   2.2:1, which is no contrast at all. Nobody would have seen it from the
   dashboard, because these screens only exist part way through a stage.

   They are pages, not game canvases, so they join the rest of the site: the
   same wallpaper, the same dark text. The pixel art inside them keeps its own
   black canvas and gets a bevel round it, exactly as the Hat Lounge does. */
html.retro #stage-ui,
html.retro #find-the-hat,
html.retro #ct-root,
html.retro #dl-root,
html.retro #wg-root {
  background: var(--r-page) url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'>\
<rect width='32' height='32' fill='%23E8E8F0'/>\
<path d='M0 0h32v1H0zM0 0v32h1V0z' fill='%23FFFFFF'/>\
<path d='M0 31h32v1H0zM31 0v32h1V0z' fill='%23D2D2DC'/>\
<circle cx='16' cy='16' r='1.5' fill='%23C8C8D4'/>\
</svg>") repeat !important;
  color: #101018 !important;
  font-family: var(--font-window, Verdana, Geneva, Arial, sans-serif) !important;
}

/* Everything they write into those roots: narration, prompts, clue text. The
   pages set these colours inline, so each one has to be named. */
html.retro #stage-ui *,
html.retro #ct-root *,
html.retro #dl-root *,
html.retro #wg-root * {
  text-shadow: none !important;
}

html.retro #cutscene-text,
html.retro #clue-note,
html.retro #stage-done {
  color: #101018 !important;
}

/* The line that says you finished. On this theme the page is light, so it
   takes the dark ink above rather than the amber it uses on black. */
html.retro #stage-done {
  font-weight: bold !important;
}

/* The narration is the closest thing this game has to prose, so it reads as
   prose rather than as terminal output. Only the dashboard's replay panel
   still has a #cutscene-text; the stage page no longer runs one. */
html.retro #cutscene-text {
  font-family: var(--font-serif, "Times New Roman", Times, serif) !important;
  font-size: clamp(1rem, 3.4vw, 1.25rem) !important;
  line-height: 1.7 !important;
}

/* The clue is the thing they walked across town for. It gets the panel. */
html.retro #clue-note {
  background: var(--r-face) !important;
  border: 2px solid !important;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light) !important;
  border-left: 6px solid var(--r-green-ink) !important;
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.25) !important;
  padding: 1rem !important;
  font-family: var(--font-serif, "Times New Roman", Times, serif) !important;
}

html.retro #stage-done,
html.retro .dl-line {
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive) !important;
  color: var(--r-ink) !important;
}

/* ---- TEXT ON TOP OF THE PAINTED COURTROOM --------------------------------
   The theme paints every one of these screens with the wallpaper and dark
   navy ink, which is right for a page and wrong for the inside of a dark
   painted room. .ct-speech was navy on a dim floor and .ct-name and .ct-role
   lost the shadows they are drawn with, because the blanket rule above
   strips text-shadow off everything under #ct-root.
   Anything sitting ON the picture is light, with a shadow, so it reads
   against whatever it happens to be over.

   EVERY SELECTOR HERE CARRIES #ct-root. The rule that strips the shadows is
   `html.retro #ct-root *`, and an ID beats any number of classes no matter
   how many !importants are stacked on them: the first version of this fix
   set the colours correctly and lost every shadow, which is the half that
   matters over a painting with light and dark patches in it. */
html.retro #ct-root .ct-speech {
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive) !important;
  color: #FFE9A8 !important;                    /* 9.8:1 on the room's floor */
  text-shadow: 0 1px 2px #000, 0 0 10px rgba(0,0,0,0.9) !important;
}

html.retro #ct-root .ct-name {
  color: #FFE9A8 !important;
  text-shadow: 0 1px 2px #000, 0 0 4px #000 !important;
}
html.retro #ct-root .ct-accused-name { color: #FF9B9B !important; }
html.retro #ct-root .ct-witness-name { color: #FFD98A !important; }

html.retro #ct-root .ct-role {
  color: #E4D6B8 !important;
  text-shadow: 0 1px 2px #000, 0 0 4px #000 !important;
}

/* The log sits UNDER the picture on the wallpaper, so it is the opposite
   problem: it was grey ink on a pale panel. Dark on silver, like every other
   panel on the site. */
html.retro #ct-root .ct-log {
  background: var(--r-face) !important;
  border: 2px solid !important;
  border-color: var(--r-shade) var(--r-light) var(--r-light) var(--r-shade) !important;
  color: #101018 !important;
}

/* The heading above the room, which is on the wallpaper and was drawn in the
   theme's own accent at 0.7rem: technically visible, practically not. */
html.retro #ct-root > div:first-of-type {
  color: var(--r-ink) !important;
  font-weight: bold;
}

/* The canvases inside those screens keep their own dark world behind a bevel,
   the same treatment the rooms get everywhere else.

   THE BEVEL GOES ON EVERYTHING HERE. The black background does NOT go on
   .ct-room: that one is not a canvas, it is Sam's painted courtroom, and
   this rule was painting over it. The whole room rendered as a black
   rectangle with hats floating in the dark. Anything that draws its own
   picture must be left alone to draw it. */
html.retro #ct-root canvas,
html.retro #dl-root canvas,
html.retro #wg-root canvas,
html.retro .ct-room,
html.retro .dl-world {
  border: 2px solid !important;
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark) !important;
}

html.retro #ct-root canvas,
html.retro #dl-root canvas,
html.retro #wg-root canvas,
html.retro .dl-world {
  background: #000 !important;
}

/* ---- Just unlocked -------------------------------------------------------
   The band that appears above a stage the moment its code is scanned. Green
   is the one colour the theme keeps for "go", so this is the darkened green
   ink on the silver, with the stage number in navy. */
html.retro .unlock-banner {
  background: var(--r-face) !important;
  border: 2px solid !important;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light) !important;
  border-left: 6px solid var(--r-green-ink) !important;
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.25) !important;
}

html.retro .ub-head {
  font-family: var(--font-code, "Courier New", monospace) !important;
  color: var(--r-ink) !important;
  font-weight: bold;
}

html.retro .ub-sub {
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive) !important;
  color: var(--r-ink) !important;
  text-shadow: 1px 1px 0 var(--r-light) !important;
}

/* ---- "That hat is taken" -------------------------------------------------
   The refusal on the hat picker. A warning plate, not an error: nothing has
   gone wrong, somebody else simply got there first. */
html.retro #taken-note {
  max-width: 420px;
  margin: 0 auto 1rem;
  padding: 0.7rem 0.9rem;
  background: var(--r-face);
  border: 2px solid;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light);
  border-left: 6px solid var(--r-error-ink) !important;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.25);
  text-align: left;
}

html.retro .taken-head {
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive);
  font-size: 0.9rem;
  color: var(--r-error-ink);
  margin-bottom: 0.3rem;
}

html.retro .taken-body {
  font-family: var(--font-serif, "Times New Roman", Times, serif);
  font-size: 0.9rem;
  line-height: 1.5;
  color: #202020;
}

/* ---- The first-login welcome ---------------------------------------------
   Built by welcome.js with only layout inline, so the look lives here and
   follows the theme rather than being frozen into the JS.
   The wt- prefix is left alone deliberately: these rules outlived the tour
   they were named after, and renaming them would touch the JS for nothing. */
html.retro .wt-box {
  background: var(--r-face);
  border: 2px solid;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light);
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.3);
  color: #000;
}

html.retro .wt-title {
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive);
  font-size: clamp(1.1rem, 4.5vw, 1.5rem);
  color: var(--r-ink);
  text-shadow: 2px 2px 0 var(--r-light);
  margin-bottom: 0.4rem;
}

html.retro .wt-para {
  font-family: var(--font-serif, "Times New Roman", Times, serif);
  color: #202020;
  font-size: 0.95rem;
}

html.retro .wt-bubble {
  background: var(--r-face);
  border: 2px solid;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light);
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.35);
  padding: 0.8rem 0.9rem;
  color: #000;
}

html.retro .wt-text {
  font-family: var(--font-window, Verdana, Geneva, sans-serif);
  font-size: 0.85rem;
  line-height: 1.55;
}

html.retro .wt-count {
  font-family: var(--font-code, "Courier New", monospace);
  font-size: 0.72rem;
  color: #3A3A3A;
}

/* The highlight ring is amber, and here that is fine: it sits on a dark scrim,
   not on silver. */
html.retro .wt-ring { border-color: var(--r-neon-amber) !important; }

html.retro .wt-skip { border-left: 6px solid var(--r-shade) !important; }
html.retro .wt-ok   { border-left: 6px solid var(--r-green-ink) !important; }

/* ---- The unlock spotlight ----
   Same chrome as the tour bubble it grew out of, plus a heading, because an
   unlock announces WHAT it is before it explains it. See
   public/js/unlock-spotlight.js. */

html.retro .ul-bubble {
  background: var(--r-face);
  border: 2px solid;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light);
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.35);
  padding: 0.8rem 0.9rem;
  color: #000;
}

html.retro .ul-head {
  font-family: var(--font-code, "Courier New", monospace);
  font-weight: bold;
  font-size: 0.9rem;
  letter-spacing: 1px;
  margin-bottom: 0.35rem;
  color: #000;
}

html.retro .ul-text {
  font-family: var(--font-window, Verdana, Geneva, sans-serif);
  font-size: 0.85rem;
  line-height: 1.55;
}

html.retro .ul-count {
  font-family: var(--font-code, "Courier New", monospace);
  font-size: 0.72rem;
  color: #3A3A3A;
}

/* Amber ring, which is fine here: it sits on a dark scrim, not on silver. */
html.retro .ul-ring { border-color: var(--r-neon-amber) !important; }

/* The ring slides between targets. Somebody who has asked for less movement
   should get the same spotlight without the travel. */
@media (prefers-reduced-motion: reduce) {
  .ul-ring { transition: none !important; }
}

/* ---- The weather bar -----------------------------------------------------
   Sits directly under the marquee, same fixed strip, same chrome. The glyph is
   drawn as hard-edged squares in an SVG so it matches the pixel art rather
   than importing a smooth weather icon set. */
.r-weather {
  position: fixed;
  /* A starting value only. retro.js measures the marquee and sets the real
     offset, because this one is a guess and was leaving a stripe of wallpaper
     showing between the two bars. */
  top: 2.4rem;
  left: 0;
  width: 100%;
  box-sizing: border-box;
  z-index: 9996;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 3px 8px;
  background: var(--r-face);
  border: 2px solid;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light);
  border-top: none;
  font-family: var(--font-display, 'BlockBlueprint', "Comic Sans MS", cursive);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--r-ink);
  white-space: nowrap;
  overflow: hidden;
}

.r-weather svg {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  shape-rendering: crispEdges;   /* keeps the pixels square */
}

.r-weather .r-temp { color: var(--r-error-ink); }
.r-weather .r-city { color: #3A3A3A; }

/* A FALLBACK ONLY, for the moment between the bars appearing and being
   measured. retro.js's restackBars() sets the real value inline once it knows
   the actual heights.

   No !important. It used to have one, and it silently beat the measured value
   the whole time: with the advert added the bars ran to 108px and the page
   still started at 72, so the top of every page sat underneath an advert. */
html.retro body.r-has-weather { padding-top: 4.5rem; }

@media (max-width: 640px) {
  .r-weather { font-size: 0.62rem; gap: 6px; }
  .r-weather .r-city { display: none; }   /* it is always Adelaide */
  html.retro body.r-has-weather { padding-top: 4.2rem; }
}

/* ---- The hit counter -----------------------------------------------------
   An odometer in a pressed-in well, digits in the old LED green on black.

   The wrapper has to survive being dropped into any of these pages' layouts,
   and they are not consistent: the homepage and the ethics page make <body> a
   flex COLUMN, the dashboard and lobby leave it a block, and the hat-choosing
   page makes it a flex ROW. In that last one the counter became a sibling
   column beside the content and shoved the entire page 159px off the left
   edge. flex-basis:100% plus wrap on the body drops it onto its own line
   instead; in a column or a block it changes nothing. */
html.retro body { flex-wrap: wrap !important; }

.r-counter-wrap {
  width: 100%;
  max-width: 100%;
  flex: 0 0 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin: 1.2rem 0 0.4rem;
  padding: 0 0.5rem;
}

.r-counter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-code, "Courier New", Courier, monospace);
  font-size: 0.75rem;
  color: #303030;
  background: var(--r-face);
  border: 2px solid;
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark);
  padding: 3px 7px;
}

.r-counter b {
  background: #000;
  color: var(--r-neon-green);   /* the real neon: this one IS on black */
  padding: 2px 5px;
  letter-spacing: 3px;
  border: 1px solid var(--r-dark);
}

/* ---- Under construction --------------------------------------------------
   One nod, on one page, exactly as asked. The stripes are CSS, not a GIF. */
.r-construction {
  display: inline-block;
  font-family: var(--font-silly, "Comic Sans MS", cursive);
  font-size: 0.7rem;
  color: #000;
  padding: 3px 10px;
  background: repeating-linear-gradient(
    45deg, var(--r-neon-amber) 0 8px, #000 8px 16px);
  border: 2px solid;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light);
}
.r-construction span {
  background: var(--r-neon-amber);
  padding: 1px 5px;
}

/* ---- The loading screen --------------------------------------------------
   Dial-up era: a blocky bar that fills in steps, a spinning starburst, and a
   line of Comic Sans. Gone inside two seconds, and skipped entirely on a
   repeat visit within the hour so it never becomes a toll. */
#r-loader {
  position: fixed;
  inset: 0;
  z-index: 100000;
  background: var(--r-page);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  transition: opacity 0.45s ease;
}

#r-loader.r-done { opacity: 0; pointer-events: none; }

#r-loader .r-star {
  font-size: 2.4rem;
  color: var(--r-amber-ink);   /* the loader panel is light, so ink */
  text-shadow: 2px 2px 0 var(--r-shade);
  animation: r-spin 1.1s steps(8, end) infinite;
}

@keyframes r-spin { to { transform: rotate(360deg); } }

#r-loader .r-load-text {
  font-family: var(--font-silly, "Comic Sans MS", cursive);
  font-size: 1.05rem;
  color: var(--r-ink);
  text-shadow: 1px 1px 0 var(--r-light);
}

#r-loader .r-bar {
  width: min(260px, 70vw);
  height: 22px;
  background: var(--white);
  border: 2px solid;
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark);
  padding: 3px;
}

/* Blocks, not a smooth fill: the bar is a row of little chunks marching. */
#r-loader .r-bar i {
  display: block;
  height: 100%;
  width: 0;
  background: repeating-linear-gradient(
    90deg, var(--r-ink) 0 10px, transparent 10px 13px);
  transition: width 0.22s steps(4, end);
}

#r-loader .r-dial {
  font-family: var(--font-code, "Courier New", monospace);
  font-size: 0.65rem;
  color: var(--r-shade);
}

/* ---- Canvas and iframes: framed, never touched --------------------------- */
html.retro canvas,
html.retro .wr-canvas {
  border: 2px solid !important;
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark) !important;
  border-radius: 0 !important;
  background: #000 !important;
}

/* stage.html's game fills the screen and must stay that way. No frame, no
   padding, nothing that could put a dead strip between a thumb and the game. */
html.retro #game-frame {
  border: none !important;
}

/* The rooms still print their own text over a dark canvas, so the panels that
   hold them keep dark innards while their frame goes silver. */
html.retro .wr-log {
  background: #000 !important;
  color: var(--r-neon-green) !important;   /* black box, so the real neon */
  font-family: var(--font-code, "Courier New", monospace) !important;
  border: 2px solid !important;
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark) !important;
}

/* ---- Mobile --------------------------------------------------------------
   Bevels are 2px at every size, which is the point of them, but the chrome
   thins out and the type grows so a phone is still comfortable. */
@media (max-width: 640px) {
  html.retro body { padding: 0.75rem !important; }

  /* The stage card is a three column grid, and Verdana is a good deal wider
     than the pixel font it replaced, so on a phone the third column squeezed
     the title until "The Courtroom" lost 47px off its end. Below 640px the
     buttons drop to their own full-width row and the title gets to wrap
     instead of being cut off. */
  html.retro .stage-card {
    grid-template-columns: 40px 1fr !important;
    row-gap: 0.6rem !important;
  }
  html.retro .stage-card .stage-action {
    grid-column: 1 / -1 !important;
    flex-direction: row !important;
    flex-wrap: wrap !important;
    justify-content: flex-start !important;
    gap: 0.5rem !important;
  }
  html.retro .stage-title {
    white-space: normal !important;
    overflow: visible !important;
    text-overflow: clip !important;
    line-height: 1.3 !important;
  }

  html.retro .form-box,
  html.retro .stage-card,
  html.retro #privacy-box,
  html.retro #welcome-club {
    box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.25) !important;
  }

  /* 16px stops iOS zooming the page the moment a field is focused. */
  html.retro input,
  html.retro textarea,
  html.retro select { font-size: 16px !important; }

  /* The rooms' chat row is an input and a SEND button side by side. A flex
     item will not shrink below its content by default, so on a 320px screen
     the pair was 7px wider than the phone and pushed the page sideways.
     The input is allowed to shrink and the button loses its wide padding. */
  html.retro .wr-say { gap: 0.35rem !important; }
  html.retro .wr-input { min-width: 0 !important; }
  html.retro .wr-send { padding: 10px 10px !important; flex: 0 0 auto; }

  html.retro button,
  html.retro .btn,
  html.retro a.btn { min-height: 44px; padding: 10px 16px !important; }

  /* Still slow on a phone: the bar is narrower, so a shorter duration would
     actually make it whip past faster than on a desktop. */
  .r-marquee span { animation-duration: 38s; }
}

/* ---- Reduced motion ------------------------------------------------------
   The sparkle, the marquee and the spinning star are all decoration. Anyone
   who has asked for less movement gets the page without them. */
@media (prefers-reduced-motion: reduce) {
  .r-marquee span,
  #r-loader .r-star,
  html.retro a:not(.btn):hover::after { animation: none !important; }
  .r-marquee span { padding-left: 0; }
  /* The trail is pure decoration and it follows the eye, so it is the first
     thing to go. retro.js checks the same query and stops spawning. */
  .r-ghost { display: none !important; }
}


/* ---- Leftovers from the terminal ----------------------------------------
   The pages draw a blinking green block caret inside every text field with
   .cursor-wrap::after. On a black terminal that was the charm; sitting in a
   white Windows 98 input it is a green rectangle in the way of what you are
   typing. The real caret does the job. */
html.retro .cursor-wrap::after { display: none !important; }

/* ---- Dialogs, not rectangles ---------------------------------------------
   Seen on screen, the panels were reading as plain grey boxes: bevelled, but
   nothing about them said 1999. The one thing every window on that desktop
   had was a title bar, so the form panels get one, drawn rather than added to
   the markup so no page has to change.

   The bar takes its words from the heading already inside the panel, hidden
   and reprinted, so it can never disagree with what the panel is for. */
html.retro .form-box,
html.retro #privacy-box,
html.retro #assigned-overlay > div {
  position: relative;
  padding-top: 2.6rem !important;
}

html.retro .form-box::before,
html.retro #privacy-box::before,
html.retro #assigned-overlay > div::before {
  content: '';
  position: absolute;
  top: 3px; left: 3px; right: 3px;
  height: 1.7rem;
  background: linear-gradient(90deg, #000080, #1084d0);
}

/* The close and minimise buttons. They do nothing, because there is nothing
   for them to do; they are the furniture that makes it a window. */
html.retro .form-box::after,
html.retro #privacy-box::after,
html.retro #assigned-overlay > div::after {
  content: '_ □ ✕';
  position: absolute;
  top: 3px;
  right: 8px;
  height: 1.7rem;
  display: flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-window, Verdana, Geneva, sans-serif);
  font-size: 0.72rem;
  color: #FFFFFF;
  letter-spacing: 3px;
  pointer-events: none;
}

/* The panel's own heading becomes the title-bar text.
   A descendant selector, not a child one: on the front page the heading sits
   inside #login-form or #register-form rather than directly in the panel, so
   the child selector matched nothing and the bar came out empty. Only one of
   those forms is ever on screen, so only one heading is ever positioned. */
html.retro .form-box h2,
html.retro #privacy-box h3 {
  position: absolute;
  top: 3px; left: 10px;
  height: 1.7rem;
  display: flex;
  align-items: center;
  margin: 0 !important;
  font-family: var(--font-window, Verdana, Geneva, sans-serif) !important;
  font-size: 0.76rem !important;
  font-weight: bold !important;
  letter-spacing: 0 !important;
  color: #FFFFFF !important;
  text-shadow: none !important;
  text-align: left !important;
}

/* ---- Two things only visible on a narrow screen -------------------------
   Caught by actually looking at the dashboard at phone width.

   1. The nav links were breaking mid-label, leaving the closing bracket of
      "[ CONTINUE MISSION ]" stranded on its own line. They are labels, not
      prose, so they never break; the ROW wraps instead and each link keeps
      itself in one piece. */
html.retro .nav-links {
  flex-wrap: wrap;
  justify-content: center;
}
html.retro .nav-links a {
  white-space: nowrap;
}

/* 2. The heading carried both its own glow and the theme's hard drop shadow,
      and on a wide pixel letterform the two read as the text printed twice.
      One offset, in the light only, which is the effect that was wanted. */
html.retro header h1,
html.retro .gf-title {
  text-shadow: 2px 2px 0 #FFFFFF !important;
}

/* ---- THE ADVERT ----------------------------------------------------------
   Unlocked at level 2. A banner across the top of every page, which is what
   the internet gave you in 2002 for sticking around, presented here entirely
   straight. See public/js/ads.js and src/unlocks.js.

   Sits under the weather strip. retro.js measures and positions all three
   fixed bars in restackBars(); nothing here guesses an offset, because the
   last thing that did left a stripe of wallpaper showing between two bars. */
/* IN THE PAGE FLOW, not fixed. A 468x60 banner sitting at the top of the
   content with a blue underlined line beneath it, which is where and how an
   advert sat on a page in 1996. It scrolls away with everything else, and it
   needs no positioning arithmetic at all. */
.r-ad {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  margin: 0 auto 14px;
  padding: 6px 8px 8px;
  max-width: 500px;
  text-align: center;

  /* Nine of the player pages centre themselves with display:flex on the body,
     so the advert arrived as a second COLUMN and pushed the whole page to one
     side. Taking a full row puts it back above the content where it belongs.
     The hit counter needed exactly this same fix, for exactly this reason. */
  flex: 0 0 100%;
  width: 100%;
  align-self: flex-start;
  order: -1;                 /* first, whatever order the page uses */
}
/* And the body has to be allowed to wrap, or a 100% item on a nowrap row
   simply squashes everything else instead of moving it down. */
html.retro body { flex-wrap: wrap; }

.r-ad-label {
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 8px;
  letter-spacing: 1px;
  color: #5A5A5A;             /* 4.6:1 on the pale wallpaper */
  text-transform: uppercase;
  align-self: flex-start;
}

/* The line under the banner. Standard 1996 hyperlink: blue and underlined,
   because that is what a link looked like before anybody decided otherwise. */
.r-ad-link {
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: 11px;
  color: #0000CC;             /* 8.9:1 on the wallpaper */
  text-decoration: underline;
  margin-top: 2px;
  padding: 6px 2px;           /* a real tap target without moving anything */
  display: inline-block;
}
.r-ad-link:visited { color: #551A8B; }   /* purple, as it should be */
.r-ad-link:hover { color: #CC0000; }

/* THE BANNER, 468x60, built from the real thing.
   ==================================================================
   Copied off the archive at banner-depot-2000.net rather than from memory.
   The moves that show up on nearly every 1996 banner:

     a solid saturated background, never a gradient
     a hard 1px border and sharp corners
     three sizes of text crammed into 60 pixels
     a row of one little picture repeated as decoration
     a CLICK HERE that is its own button on the right
     fine print nobody reads

   Yellow because it is the loudest thing a banner can be and it was
   everywhere. Black on this yellow is 14:1, so the loudest option is also
   the most readable one, which is not usually how that goes. */
.r-ad-banner {
  display: flex;
  align-items: stretch;
  gap: 0;
  width: 100%;
  max-width: 468px;
  height: 60px;
  padding: 0;
  text-decoration: none;
  background: #FFD400;
  border: 1px solid #000;
  overflow: hidden;
  font-family: var(--font-window, Arial, Helvetica, sans-serif);
}

.r-ad-left {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 2px 6px;
  text-align: left;
}

/* The little red line above the name, in the tone of "Rated Ultimate
   E-Mail!" over the top of the e-mail connection banner. */
.r-ad-kicker {
  font-size: 9px;
  font-weight: bold;
  letter-spacing: 0.04em;
  color: #C00000;              /* 4.2:1 on the yellow: bold only, never body */
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.r-ad-name {
  font-family: var(--font-display, BlockBlueprint, Arial, sans-serif);
  font-size: 15px;
  color: #000;                 /* 14:1 */
  line-height: 1.15;
  margin: 1px 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The fine print. Every one of these banners had a line like it. */
.r-ad-tag {
  font-size: 9px;
  color: #221A00;              /* 12:1 */
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The row of repeated hats, where the beer glasses and the cows went. */
.r-ad-hats {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 1px;
  padding: 0 4px;
}
.r-ad-hats i {
  width: 18px;
  height: 18px;
  background-image: url('/img/hat-sheet.png');
  background-size: 300% 300%;
  background-position: 0% 0%;
  background-repeat: no-repeat;
  image-rendering: pixelated;
}
/* Each one a different frame, so the row reads as a little crowd rather
   than one hat stamped five times. */
.r-ad-hats i:nth-child(2) { background-position: 50% 0%; }
.r-ad-hats i:nth-child(3) { background-position: 100% 0%; }
.r-ad-hats i:nth-child(4) { background-position: 0% 50%; }
.r-ad-hats i:nth-child(5) { background-position: 50% 50%; }

/* CLICK HERE as its own block on the right, which is where it always was. */
.r-ad-cta {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 8px;
  background: #C00000;
  color: #fff;                 /* 5.9:1 on the red */
  font-size: 12px;
  font-weight: bold;
  line-height: 1.05;
  text-align: center;
  letter-spacing: 0.04em;
  border-left: 1px solid #000;
  animation: r-ad-blink 1.1s steps(2) infinite;
}
/* Blinks between two READABLE states. A CTA that vanishes for half a second
   at a time is a CTA nobody can read on a moving bus. */
@keyframes r-ad-blink {
  0%, 49%   { background: #C00000; color: #fff; }
  50%, 100% { background: #000000; color: #FFD400; }
}

@media (prefers-reduced-motion: reduce) {
  .r-ad-cta { animation: none; }
}

@media (max-width: 480px) {
  .r-ad-label { display: none; }   /* the banner itself says what it is */
  .r-ad-name { font-size: 12px; }
  .r-ad-kicker, .r-ad-tag { font-size: 8px; }
  /* The row of hats is decoration, and decoration is the first thing to go
     when 468 pixels has to fit in 320. */
  .r-ad-hats { display: none; }
}

/* ---- While a game is on ---------------------------------------------------
   Every piece of site furniture gets out of the way. The fixed bars sit above
   the game overlay in the stacking order, so without this the weather strip
   is drawn across the top of whatever is being played. */
html.retro body.r-playing .r-marquee,
html.retro body.r-playing .r-weather,
html.retro body.r-playing .r-ad,
html.retro body.r-playing .r-counter-wrap,
html.retro body.r-playing .r-sound,
html.retro body.r-playing #r-loader {
  display: none !important;
}

/* ---- The speaker ----------------------------------------------------------
   One bevelled corner button controlling sound for the whole site. Bottom
   left, because the bottom right belongs to iOS's link preview thumb and the
   dashboard's own content. 44px so a thumb can actually hit it. */
.r-sound {
  position: fixed;
  left: 8px;
  bottom: calc(8px + env(safe-area-inset-bottom, 0px));
  z-index: 9995;
  min-width: 44px;
  min-height: 44px;
  background: var(--r-face);
  color: var(--r-ink);
  border: 2px solid;
  border-color: var(--r-light) var(--r-dark) var(--r-dark) var(--r-light);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}
.r-sound:active {
  border-color: var(--r-dark) var(--r-light) var(--r-light) var(--r-dark);
}

/* ---- Error flicker ---------------------------------------------------------
   The whole body blinks once when something is refused. Lifted from
   scan.html so every page's error branch can use the same one. step-end,
   like everything else here. */
@keyframes r-flicker {
  0%, 100% { opacity: 1; }
  25% { opacity: 0.55; }
  50% { opacity: 1; }
  75% { opacity: 0.7; }
}
.flicker { animation: r-flicker 0.4s step-end; }

/* The default iOS grey tap rectangle is replaced by our own feedback: the
   ghost hat bloom, the click and the buzz. Both kinds at once looks broken. */
html.retro { -webkit-tap-highlight-color: transparent; }

/* ============================================================================
   THE WINDOWS PASS
   ============================================================================

   Added after everything above, so it lands last and wins without any of the
   231 rules before it needing an edit.

   THE PROBLEM IT FIXES. Three bevel conventions had grown up side by side:
   this file and gotcha.css drew the dark edge at #404040, hub.css and
   clippy.css at #808080, win95.css at #000000. Three shades of the same
   supposedly identical chrome, on pages that sit one click apart. And the
   panels were bevelled boxes rather than WINDOWS: no title bar, which is the
   one thing that makes a rectangle read as a program rather than a card.

   So: one bevel, and a title bar for any panel that asks for one.
   ========================================================================= */

:root {
  /* THE ONE BEVEL. Every silver edge on this site is drawn from these four,
     and the dark edge is #808080 rather than #404040: the hard black edge
     read as a drawn border rather than a raised face, and the softer one is
     what the hunt dialogs and the TinyHat 95 desktop already used. */
  --w-face:   #C0C0C0;
  --w-light:  #FFFFFF;
  --w-shade:  #808080;
  --w-inner:  #DFDFDF;   /* the inner highlight, one step down from white */
  --w-inset:  #6D6D6D;   /* the inner shadow, one step up from the shade */
  --w-title:  #000080;
  --w-title2: #1084d0;   /* the gradient's far end */
}

/* A window from nothing: for the handful of pages whose content sits loose
   on the wallpaper with no panel around it at all. Note .form-box and its
   friends already have a face and border from the bevel section, and already
   turn their own h2 into a title bar, so they must never be given a second
   one here. */
html.retro .win {
  background: var(--w-face) !important;
  border: 2px solid !important;
  border-radius: 0 !important;
  color: #000 !important;
  padding: 0.9rem;
}

/* Raised: light on the top and left, shade on the bottom and right. */
html.retro .form-box,
html.retro .stage-card,
html.retro #privacy-box,
html.retro #welcome-club,
html.retro .card,
html.retro .panel,
html.retro .tbl,
html.retro #assigned-overlay > div,
html.retro .win {
  border-color: var(--w-light) var(--w-shade) var(--w-shade) var(--w-light) !important;
  box-shadow: 1px 1px 0 var(--w-inner) inset,
              -1px -1px 0 var(--w-inset) inset,
              2px 2px 0 rgba(0, 0, 0, 0.35) !important;
}

html.retro button,
html.retro .btn,
html.retro a.btn {
  border-color: var(--w-light) var(--w-shade) var(--w-shade) var(--w-light) !important;
  box-shadow: 1px 1px 0 var(--w-inner) inset, -1px -1px 0 var(--w-inset) inset !important;
}

html.retro button:active,
html.retro .btn:active,
html.retro a.btn:active {
  border-color: var(--w-shade) var(--w-light) var(--w-light) var(--w-shade) !important;
  box-shadow: 1px 1px 0 var(--w-inset) inset !important;
}

/* Sunken: the mirror of the above, for anything you type into or scroll. */
html.retro input[type="text"],
html.retro input[type="password"],
html.retro input[type="email"],
html.retro input[type="number"],
html.retro textarea,
html.retro select,
html.retro canvas,
html.retro .wr-canvas {
  border-color: var(--w-shade) var(--w-light) var(--w-light) var(--w-shade) !important;
  box-shadow: 1px 1px 0 var(--w-inset) inset !important;
}

/* ---- The title bar -------------------------------------------------------
   Any element carrying data-win="Something" becomes a window with that name
   in its bar. One attribute per panel, no markup restructuring, and the bar
   is drawn entirely by CSS so nothing has to remember to render it.

   The close box is decorative on purpose: there is nothing to close, and a
   dialog you cannot dismiss is the most 1995 thing on this site. */
html.retro [data-win] {
  position: relative;
  padding-top: 2rem !important;
}

html.retro [data-win]::before {
  content: attr(data-win);
  position: absolute;
  top: 2px;
  left: 2px;
  right: 2px;
  height: 1.45rem;
  background: linear-gradient(90deg, var(--w-title), var(--w-title2));
  color: #FFFFFF;
  font-family: var(--font-window, Verdana, Geneva, Arial, sans-serif);
  font-size: 0.75rem;
  font-weight: bold;
  letter-spacing: 0;
  text-shadow: none;
  display: flex;
  align-items: center;
  padding: 0 0.4rem;
  box-sizing: border-box;
}

/* The âœ• box, floated over the right end of the bar. */
html.retro [data-win]::after {
  content: '\2715';
  position: absolute;
  top: 5px;
  right: 6px;
  width: 1rem;
  height: 0.95rem;
  background: var(--w-face);
  color: #000;
  border: 1px solid;
  border-color: var(--w-light) var(--w-inset) var(--w-inset) var(--w-light);
  font-family: var(--font-window, Verdana, Geneva, Arial, sans-serif);
  font-size: 0.55rem;
  line-height: 0.85rem;
  text-align: center;
  text-shadow: none;
}

/* ---- Type ----------------------------------------------------------------
   THE READABILITY FIX. Every heading was Block Blueprint, an 8-bit face, with
   a two-layer hard drop shadow (white then grey) behind it. At a real heading
   size that reads as designed; at the size a step title or a card heading
   actually is, the shadow doubles every stem and the letters smear into each
   other. It was the single most complained-about thing on the site.

   The wordmark keeps the pixel face, because that is the brand and it is set
   big enough to carry it. Everything below h1 becomes Verdana bold, which is
   what the dialogs use and what Windows put in a title bar. */
html.retro h2,
html.retro h3,
html.retro .stage-title,
html.retro .season-badge {
  font-family: var(--font-window, Verdana, Geneva, Arial, sans-serif) !important;
  font-weight: bold !important;
  letter-spacing: 0 !important;
  text-shadow: none !important;
}

/* The wordmark keeps its face but loses the doubled shadow: one hard offset
   is a 1995 heading, two is a printing fault. */
html.retro h1 {
  text-shadow: 2px 2px 0 var(--w-light) !important;
}

/* ---- The shell hosts us --------------------------------------------------
   Inside TinyHat 95 the window around this page already has a title bar with
   a close box and a taskbar button. Anything here that ALSO offers a way out
   is the same door drawn twice, so it stands down. Opened on its own the page
   keeps its link, because then it is the only door there is. */
html.th-embedded a.link-btn,
html.th-embedded #flow-back,
html.th-embedded #check-back { display: none !important; }

/* THE SITE FURNITURE STANDS DOWN TOO. The marquee, the weather strip, the
   visitor counter and the sound button are the 2002 site's own chrome, and
   inside a TinyHat 95 window they were all drawn AGAIN, inside a machine
   that already carries the weather and a speaker in its tray: every window
   opened as a little website wearing two sets of clothes. The banner ADS
   stay, because they are a joke on the page, not chrome around it.
   The body's padding-top made room for the two fixed bars, so it goes back
   to a working margin when they go. */
html.th-embedded .r-marquee,
html.th-embedded .r-weather,
html.th-embedded .r-sound,
html.th-embedded .r-counter-wrap { display: none !important; }
html.retro.th-embedded body { padding-top: 0.8rem !important; }

/* THE DECORATIVE CLOSE BOX IS GONE. A drawn X that does nothing is worse than
   no X at all: it is the first thing anybody presses. The windows that can
   really be closed draw a real button instead, see hunt-ui.js. */
html.retro [data-win]::after { content: none !important; }

/* A heading sitting inside a title bar is the bar's text, so it must not be
   a second heading underneath it. */
html.retro [data-win] > h1:first-child,
html.retro [data-win] > h2:first-child,
html.retro [data-win] > h3:first-child { margin-top: 0 !important; }

/* The 16px field rule above only covers narrow screens; a phone turned sideways is wider and still zooms. */
@media (pointer: coarse) {
  html.retro input,
  html.retro textarea,
  html.retro select { font-size: 16px !important; }
}
