@font-face {
  font-family: "Departure Mono";
  src: url("fonts/DepartureMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #111114;
  --panel: #18181d;
  --panel-2: #1f1f25;
  --line: #34343c;
  --fg: #f5f5f7;
  --dim: #9a9aa3;
  --faint: #55555c;
  --neon: #39ff88;
  --pink: #ff2d95;
  --cyan: #2de2ff;
  --yellow: #ffd60a;
  --pixel: "Departure Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  background-image: radial-gradient(circle at 1px 1px, #1c1c22 1px, transparent 0);
  background-size: 22px 22px;
  color: var(--fg);
  font: 16px/1.5 var(--sans);
  overflow-x: hidden;
}

code, .mono { font-family: var(--mono); font-size: 0.92em; }

button { font: inherit; color: inherit; cursor: pointer; }
button:disabled { cursor: not-allowed; opacity: 0.45; }
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

/* Header */
.top { max-width: 1120px; margin: 0 auto; padding: 28px 16px 8px; }
.kicker { margin: 0 0 6px; font: 13px/1.2 var(--pixel); color: var(--cyan); letter-spacing: 0.08em; text-transform: uppercase; }
.title {
  margin: 0;
  font: 400 clamp(34px, 9vw, 64px)/1 var(--pixel);
  color: var(--neon);
  text-shadow: 0 0 18px rgba(57, 255, 136, 0.35);
  letter-spacing: 0.02em;
}
.title-lab { color: var(--pink); margin-left: 0.3em; text-shadow: 0 0 18px rgba(255, 45, 149, 0.35); }
.lede { max-width: 62ch; margin: 12px 0 18px; color: var(--dim); }
.lede code { color: var(--fg); }

.modes { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; max-width: 420px; }
.mode {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  min-height: 56px; padding: 8px 14px;
  background: var(--panel); border: 2px solid var(--line); border-radius: 6px;
  text-align: left;
}
.mode-name { font: 20px/1.1 var(--pixel); color: var(--dim); }
.mode-tool { font: 13px/1.2 var(--mono); color: var(--faint); }
.mode[aria-pressed="true"] { border-color: var(--neon); background: #132019; box-shadow: 0 0 0 1px var(--neon) inset; }
.mode[aria-pressed="true"] .mode-name { color: var(--neon); }
.mode[aria-pressed="true"] .mode-tool { color: var(--fg); }
.mode-note { max-width: 70ch; margin: 12px 0 0; color: var(--dim); font-size: 15px; }

/* Layout: wide screens only. The knock pad is a tall column on the left, the firewall it hits (then the SSH check
   and sniffer) runs down the middle, and the server's iptables log sits on the right. Below 1100 px the lab is
   replaced by a notice. */
.top, .grid, .foot { max-width: 1360px; }
.grid {
  margin: 0 auto; padding: 16px;
  display: grid; gap: 14px; align-items: start;
  grid-template-columns: 230px minmax(0, 1fr) minmax(0, 1.35fr);
}
.col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

.too-narrow { display: none; }
@media (max-width: 1099px) {
  .top, .grid, .foot, .toast { display: none; }
  .too-narrow { display: block; max-width: 34ch; margin: 18vh auto 0; padding: 0 16px; color: var(--dim); }
  .too-narrow-title { margin: 0 0 12px; font: 28px/1.1 var(--pixel); color: var(--pink); }
}

.panel {
  min-width: 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px 14px 16px;
}
.ph { margin: 0 0 10px; font: 400 17px/1.2 var(--pixel); color: var(--cyan); letter-spacing: 0.06em; }
.ph-sub { font: 12px/1.2 var(--mono); color: var(--faint); letter-spacing: 0; margin-left: 6px; }
.fine { margin: 10px 0 0; font-size: 13.5px; color: var(--dim); }

/* Prompt marker, in the log's terminal */
.ps1 { color: var(--neon); margin-right: 0.5ch; }

/* Locks: one pixel padlock per knock, its port underneath */
.lock-row { list-style: none; margin: 4px 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.lock-row.single { grid-template-columns: minmax(0, 1fr); }
.lock { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.lock-art { width: 48px; height: 60px; image-rendering: pixelated; }
.lock-port { font: 15px/1 var(--pixel); color: var(--faint); }
.lk-shackle { fill: #6b6b75; }
.lk-body { fill: #4a4a53; }
.lk-hi { fill: #7d7d88; }
.lk-lo { fill: #2c2c33; }
.lk-hole { fill: #111114; }
.lock.open .lk-shackle { fill: var(--cyan); }
.lock.open .lk-body { fill: #1a8fa3; }
.lock.open .lk-hi { fill: var(--cyan); }
.lock.open .lk-lo { fill: #0f5966; }
.lock.open .lock-port { color: var(--cyan); }
.lock.open .lock-art { filter: drop-shadow(0 0 6px rgba(45, 226, 255, 0.55)); }
.lock-row.done .lk-shackle, .lock-row.done .lk-hi { fill: var(--neon); }
.lock-row.done .lk-body { fill: #1f9c55; }
.lock-row.done .lk-lo { fill: #11592f; }
.lock-row.done .lock-port { color: var(--neon); }
.lock-row.done .lock-art { filter: drop-shadow(0 0 8px rgba(57, 255, 136, 0.6)); }
.lock-row.broken .lk-shackle, .lock-row.broken .lk-hi { fill: var(--pink); }
.lock-row.broken .lk-body { fill: #8c1a52; }
.lock-row.broken .lock-port { color: var(--pink); }
.lock.just .lock-art { animation: bump 0.3s ease-out; }
.lock-row.shake { animation: shake 0.35s linear; }
@keyframes bump { 0% { transform: scale(1.35); } 100% { transform: scale(1); } }
@keyframes shake { 0%, 100% { transform: translateX(0); } 20%, 60% { transform: translateX(-6px); } 40%, 80% { transform: translateX(6px); } }

.timer { height: 4px; max-width: 360px; margin: 10px auto 0; background: var(--panel-2); border-radius: 2px; overflow: hidden; }
.timer-fill { display: block; height: 100%; width: 0; background: var(--cyan); }
.timer-label { min-height: 1.3em; margin: 6px 0 0; font: 12.5px/1.3 var(--mono); color: var(--faint); }

.keys { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.key {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  min-height: 64px; padding: 8px 4px;
  background: linear-gradient(#24242b, #1b1b21);
  border: 2px solid var(--line); border-bottom-width: 5px; border-radius: 8px;
  transition: transform 0.05s, border-color 0.15s;
  touch-action: manipulation;
}
.key:hover:not(:disabled) { border-color: var(--cyan); }
.key:active:not(:disabled), .key.pressed { transform: translateY(3px); border-bottom-width: 2px; margin-top: 3px; }
.key-port { font: 26px/1 var(--pixel); color: var(--fg); }
.key-sub { font: 12px/1 var(--mono); color: var(--dim); }
.key-decoy { border-style: dashed; }
.key-decoy .key-port { color: var(--dim); }
/* Port 22 is not a knock: it's the SSH connection the knocks are for, set apart below them */
.key-ssh { grid-column: 1 / -1; margin-top: 6px; border-color: #1f6b41; background: linear-gradient(#18291f, #121c16); }
.key-ssh .key-port { color: var(--neon); }
.key-ssh:hover:not(:disabled) { border-color: var(--neon); }

.spa-send {
  display: flex; flex-direction: column; align-items: center; gap: 4px; width: 100%;
  margin-bottom: 12px; min-height: 64px; padding: 10px;
  background: #11251a; border: 2px solid var(--neon); border-bottom-width: 5px; border-radius: 8px;
  touch-action: manipulation;
}
.spa-send:active:not(:disabled) { transform: translateY(3px); border-bottom-width: 2px; }
.spa-send-main { font: 22px/1 var(--pixel); color: var(--neon); }
.spa-send-sub { font: 12px/1.3 var(--mono); color: var(--dim); overflow-wrap: anywhere; }
.warn { margin: 0 0 12px; padding: 10px 12px; border: 1px solid var(--yellow); border-radius: 6px; color: var(--yellow); font: 14px/1.4 var(--mono); overflow-wrap: anywhere; }

.moment { min-height: 76px; margin-top: 14px; }
.moment-card { padding: 10px 12px; border: 2px solid currentColor; border-radius: 6px; animation: pop 0.25s ease-out; }
.moment-title { margin: 0; font: 20px/1.15 var(--pixel); letter-spacing: 0.03em; }
.moment-text { margin: 4px 0 0; color: var(--fg); font-size: 14.5px; }
.m-good { color: var(--neon); }
.m-gold { color: var(--yellow); }
.m-bad { color: var(--pink); }
.m-info { color: var(--cyan); }
.m-dim { color: var(--dim); }
@keyframes pop { from { transform: scale(0.94); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* Firewall: a 16-bit brick wall with the rule list on a dark sign set into it. The brick tile is 32x16 pixel art
   (two courses, offset half a brick, each brick with a lit top edge and a shaded bottom), drawn at 2x. */
.panel.rules { padding: 0; border: 0; background: none; }
.wall {
  padding: 34px 30px;
  border: 3px solid #1a0b07; border-radius: 4px;
  background: #2b1510 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='16' shape-rendering='crispEdges'%3E%3Crect width='32' height='16' fill='%232b1510'/%3E%3Cg fill='%239c3f26'%3E%3Crect x='0' y='0' width='15' height='7'/%3E%3Crect x='16' y='0' width='15' height='7'/%3E%3Crect x='0' y='8' width='7' height='7'/%3E%3Crect x='8' y='8' width='15' height='7'/%3E%3Crect x='24' y='8' width='8' height='7'/%3E%3C/g%3E%3Cg fill='%23c4603d'%3E%3Crect x='0' y='0' width='15' height='1'/%3E%3Crect x='16' y='0' width='15' height='1'/%3E%3Crect x='0' y='8' width='7' height='1'/%3E%3Crect x='8' y='8' width='15' height='1'/%3E%3Crect x='24' y='8' width='8' height='1'/%3E%3Crect x='3' y='3' width='1' height='1'/%3E%3Crect x='20' y='4' width='1' height='1'/%3E%3Crect x='13' y='11' width='1' height='1'/%3E%3C/g%3E%3Cg fill='%236e2817'%3E%3Crect x='0' y='6' width='15' height='1'/%3E%3Crect x='16' y='6' width='15' height='1'/%3E%3Crect x='0' y='14' width='7' height='1'/%3E%3Crect x='8' y='14' width='15' height='1'/%3E%3Crect x='24' y='14' width='8' height='1'/%3E%3Crect x='9' y='2' width='1' height='1'/%3E%3Crect x='27' y='3' width='1' height='1'/%3E%3Crect x='17' y='10' width='1' height='1'/%3E%3Crect x='4' y='12' width='1' height='1'/%3E%3C/g%3E%3C/svg%3E") 0 0 / 64px 32px;
  image-rendering: pixelated;
  box-shadow: inset 0 -6px 0 rgba(0, 0, 0, 0.35), 0 6px 0 #1a0b07;
}
.wall-sign {
  padding: 12px 12px 10px;
  background: rgba(12, 9, 9, 0.72);
  border: 3px solid #1a0b07;
  box-shadow: 0 0 0 3px #5a2a1b, 6px 6px 0 rgba(0, 0, 0, 0.55);
}
.rule.hit { background: rgba(255, 214, 10, 0.14); box-shadow: inset 3px 0 0 var(--yellow); }
.rule.hit-accept { background: rgba(57, 255, 136, 0.18); box-shadow: inset 3px 0 0 var(--neon); }
.rule.is-bad.hit-accept { background: rgba(255, 45, 149, 0.2); box-shadow: inset 3px 0 0 var(--pink); }
.rule.hit-drop { background: rgba(255, 45, 149, 0.2); box-shadow: inset 3px 0 0 var(--pink); }
.rule.hit-drop .v-drop { background: var(--pink); color: #22030f; }

/* A packet flying from the knock pad to the firewall, and a log line flying from the firewall to the console */
.fly {
  position: fixed; left: 0; top: 0; z-index: 20; pointer-events: none;
  padding: 4px 6px 3px; border: 2px solid currentColor; border-radius: 3px; background: #0c0c10;
  font: 13px/1 var(--pixel); color: var(--cyan); box-shadow: 0 0 12px currentColor;
}
.fly-bad { color: var(--pink); }
.fly-spa { color: var(--neon); }
.fly-log { color: var(--yellow); font-size: 11px; }

/* The over-9000 photo peeking in from an edge of the screen */
.peek {
  position: fixed; z-index: 30; pointer-events: none;
  border: 4px solid var(--yellow); border-radius: 6px;
  box-shadow: 0 0 0 3px #221c00, 0 0 28px rgba(255, 214, 10, 0.45);
}
.peek-bottom { bottom: 0; }
.peek-left { left: 0; }
.peek-right { right: 0; }

.rule-list, .capture, .log-list { list-style: none; margin: 0; padding: 0; }
.rule {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 4px 10px; align-items: center;
  padding: 8px 0; border-top: 1px dashed var(--line); font: 14px/1.3 var(--mono);
}
.rule:first-child { border-top: 0; }
.verdict { font: 14px/1 var(--pixel); padding: 4px 6px 3px; border-radius: 3px; }
.v-accept { background: var(--neon); color: #05200f; }
.v-drop { background: #2a2a31; color: var(--dim); }
.rule-what { overflow-wrap: anywhere; }
.rule-left { color: var(--fg); font-variant-numeric: tabular-nums; }
.rule-bar { grid-column: 1 / -1; height: 3px; background: var(--panel-2); border-radius: 2px; overflow: hidden; }
.rule-bar span { display: block; height: 100%; background: var(--neon); }
.rule.is-bad .rule-bar span { background: var(--pink); }
.rule.is-bad .v-accept { background: var(--pink); color: #22030f; }
.rule-drop { color: var(--dim); }

/* Sniffer */
.sniff-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 4px; }
.sniff-top .ph { margin: 0; }
.toggle {
  min-height: 44px; padding: 6px 12px;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 6px;
  font: 14px/1.2 var(--mono); color: var(--dim);
}
.capture { margin-top: 8px; max-height: 220px; overflow-y: auto; border: 1px solid var(--line); border-radius: 6px; background: #0c0c0f; }
.capture li { padding: 6px 10px; font: 13px/1.4 var(--mono); color: var(--fg); border-top: 1px solid #1d1d22; overflow-wrap: anywhere; }
.capture li:first-child { border-top: 0; }
.capture .cap-empty { color: var(--faint); }
.cap-blob { color: var(--dim); }
.sniff-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.act {
  min-height: 44px; padding: 8px 12px;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 6px;
  font: 14px/1.2 var(--mono); color: var(--fg); text-align: left;
}
.act-bad { border-color: var(--pink); color: var(--pink); }
.act-bad:hover:not(:disabled) { background: rgba(255, 45, 149, 0.1); }

/* iptables log: a terminal tailing the server's /var/log/messages */
.term {
  height: 560px; overflow-y: auto; margin-top: 8px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 6px; background: #08080a;
  font: 12.5px/1.45 var(--mono); color: var(--dim);
}
.term-cmd { margin: 0 0 4px; color: var(--fg); }
.term-cmd .ps1 { color: var(--neon); }
.log-list li { white-space: pre-wrap; overflow-wrap: anywhere; padding: 1px 0; }
.ls-time { color: var(--faint); }
.ls-host { color: var(--faint); }
.ls-proc { color: var(--dim); }
.ls-knockd, .ls-fwknopd { color: var(--yellow); }
.ls-lab { color: var(--pink); }
.ls-from-you { color: var(--cyan); }
.ls-from-bad { color: var(--pink); }
.ls-dpt { color: var(--fg); font-weight: 600; }
.ls-good { color: var(--neon); }
.ls-warn { color: var(--pink); }
.cursor { display: inline-block; width: 0.6em; height: 1.1em; vertical-align: text-bottom; background: var(--dim); animation: blink 1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }
.v-log { background: #2a2a31; color: var(--yellow); }

/* Quests */
.quests .ph { margin-bottom: 6px; }
.quest-name { margin: 0; font: 13px/1.3 var(--pixel); color: var(--faint); letter-spacing: 0.04em; }
.quest-all { color: var(--yellow); }
.quest-text { margin: 2px 0 0; font-size: 15px; color: var(--fg); }

/* Footer */
.foot { max-width: 1120px; margin: 8px auto 40px; padding: 16px; border-top: 1px solid var(--line); }
.honest { margin: 0 0 12px; font: 15px/1.4 var(--pixel); color: var(--fg); }
.links { display: flex; flex-wrap: wrap; gap: 8px; }
.link {
  display: inline-flex; align-items: center; min-height: 44px; padding: 8px 12px;
  border: 1px solid var(--line); border-radius: 6px; background: var(--panel);
  color: var(--cyan); text-decoration: none; font-size: 15px;
}
.link:hover { border-color: var(--cyan); }
.link-soon { color: var(--dim); border-style: dashed; }

/* Toast */
.toast {
  position: fixed; left: 50%; bottom: 18px; z-index: 10;
  width: max-content; max-width: calc(100vw - 32px);
  transform: translate(-50%, 140%); opacity: 0;
  padding: 10px 14px; border: 2px solid var(--yellow); border-radius: 8px; background: #1d1a08;
  font: 15px/1.3 var(--pixel); color: var(--yellow);
  transition: transform 0.25s, opacity 0.25s; pointer-events: none;
}
.toast.show { transform: translate(-50%, 0); opacity: 1; }
.toast small { display: block; margin-top: 3px; font: 13px/1.3 var(--sans); color: var(--fg); }

[hidden] { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
