@font-face {
  font-family: "Courier Prime";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/courier-prime-regular.woff2) format("woff2");
}
@font-face {
  font-family: "Courier Prime";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/courier-prime-bold.woff2) format("woff2");
}

body {
  background: #fff;
  color: #000;
  font-family: "Courier Prime", "Courier New", Courier, monospace;
  line-height: 1.5;
  max-width: 760px;
  margin: 2.5em auto;
  padding: 0 1em;
}
body.wide { max-width: 1040px; }

a:link { color: #0000EE; }
a:visited { color: #551A8B; }
code { font-family: inherit; }

nav.site {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5em;
  border-bottom: 1px solid #000;
  padding-bottom: .5em;
  margin-bottom: 1.5em;
}

h1 small { font-weight: 400; font-size: .6em; margin-left: .5em; }

dl.albums dt { margin-top: 1em; font-weight: 700; }
dl.albums dd { margin-left: 0; }

/* The viewer mirrors the Swing window: an info bar, the canvas, a row of controls. */
.info-bar {
  background: #ffb3b3;
  padding: .4em .6em;
  border: 1px solid #000;
  border-bottom: none;
}
.canvas {
  margin: 0;
  border: 1px solid #000;
  background: #fff;
  line-height: 0;
}
.canvas svg { max-width: 100%; height: auto; display: block; }
.controls {
  display: flex;
  flex-wrap: wrap;
  gap: .6em;
  align-items: center;
  justify-content: center;
  background: #f5c400;
  padding: .6em;
  border: 1px solid #000;
  border-top: none;
}
.controls a, .controls button, .paste button {
  font: inherit;
  display: inline-block;
  padding: .25em .8em;
  border: 1px solid #555;
  border-radius: 4px;
  background: #f3f3f3;
  color: #000;
  text-decoration: none;
  cursor: pointer;
}
.controls .disabled {
  opacity: .4;
  padding: .25em .8em;
  border: 1px solid #888;
  border-radius: 4px;
}
.controls form { display: inline-flex; gap: .4em; margin: 0; }
.controls select { font: inherit; max-width: 18em; }
.status { margin: .6em 0 0; font-style: italic; }
.all .canvas { margin: .5em 0 1.5em; }
.all h2 { margin-bottom: .2em; }

.paste textarea {
  width: 100%;
  box-sizing: border-box;
  font: inherit;
  font-size: .95em;
  padding: .5em;
  border: 1px solid #555;
}
.paste label { display: block; font-weight: 700; margin-top: 1em; }
.canvas-fields {
  display: flex;
  flex-wrap: wrap;
  gap: .6em;
  align-items: center;
  margin-top: .8em;
}
.canvas-fields label { display: inline; margin: 0; font-weight: 400; }
.canvas-fields input { font: inherit; width: 6em; padding: .2em .4em; }
.error { color: #b00020; font-weight: 700; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

pre {
  overflow-x: auto;
  background: #f6f6f6;
  border: 1px solid #ddd;
  padding: .8em;
  font-size: .9em;
  line-height: 1.35;
}
table { border-collapse: collapse; margin: .5em 0 1em; }
th, td { border: 1px solid #999; padding: .3em .6em; text-align: left; vertical-align: top; }

/* ---------- Lightson: the game ---------- */

/* The game window is sized from the viewport height too, so that the info bar, the canvas
   and the controls are all on screen at once and nothing jumps between moves. */
.game {
  margin: 0 auto;
  max-width: min(100%, calc((100vh - 9.5rem) * 1.6667));
  min-width: min(100%, 20rem);
  scroll-margin-top: .5rem;
}
.game .info-bar {
  display: grid;
  grid-template-columns: 1fr auto;
  column-gap: 1em;
  align-items: baseline;
}
.info-score { white-space: nowrap; }
.info-title > * { white-space: nowrap; }
.info-text { grid-column: 1 / -1; }
.game .info-text { min-height: 3em; }
.stars { color: #8a5a00; letter-spacing: .05em; font-family: "DejaVu Sans", "Segoe UI Symbol", "Apple Symbols", sans-serif; }

.game .canvas { position: relative; overflow: hidden; background: #090b22; }
.game .canvas svg { width: 100%; max-width: none; }

.banner {
  position: absolute;
  left: 50%;
  top: 4%;
  transform: translateX(-50%);
  white-space: nowrap;
  line-height: 1.3;
  font-weight: 700;
  font-size: clamp(.95rem, 2.6vw, 1.45rem);
  background: #f5c400;
  color: #000;
  border: 1px solid #000;
  padding: .2em .9em;
  animation: banner-in .5s cubic-bezier(.2, 1.4, .4, 1) 1.2s both;
}
.banner .stars { color: #000; }
@keyframes banner-in {
  from { opacity: 0; transform: translateX(-50%) translateY(-160%); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}

.controls a.go {
  background: #fff;
  border-color: #000;
  font-weight: 700;
  animation: nudge .9s ease-in-out 1.8s 3;
}
@keyframes nudge { 50% { transform: translateX(.35em); } }
.controls button:disabled { opacity: .4; cursor: default; }
/* One click selects the whole sentence, ready to copy. */
.share .copy {
  -webkit-user-select: all;
  user-select: all;
  overflow-wrap: anywhere;
  background: #f6f6f6;
  border: 1px solid #ddd;
  padding: .1em .4em;
}
.keep { margin: .8em 0 0; display: flex; flex-wrap: wrap; gap: .6em; align-items: baseline; font-size: .9em; }
.keep button {
  font: inherit;
  padding: .15em .7em;
  border: 1px solid #555;
  border-radius: 4px;
  background: #f3f3f3;
  cursor: pointer;
}

/* Each switch is a link over its window. Hovering shows what it would flip. */
svg.tower .sw { cursor: pointer; outline: none; }
svg.tower .hit { fill: #fff; fill-opacity: 0; }
svg.tower .sw:active .hit { fill-opacity: .14; }
svg.tower .pv { visibility: hidden; pointer-events: none; stroke-width: 3; }
svg.tower .pv-on { fill: #ffcf5c; fill-opacity: .3; stroke: #ffe9a0; }
svg.tower .pv-off { fill: #070a1c; fill-opacity: .55; stroke: #a9bbff; stroke-dasharray: 7 5; }
svg.tower .pv-self { stroke-width: 5; }
svg.tower .sw:focus-visible .pv { visibility: visible; }
@media (hover: hover) {
  svg.tower .sw:hover .pv { visibility: visible; }
}
svg.tower .jammed { fill-opacity: 0; cursor: not-allowed; }
svg.tower .hint {
  fill: none;
  stroke: #7dffb0;
  stroke-width: 5;
  stroke-dasharray: 11 8;
  pointer-events: none;
  transform-box: fill-box;
  transform-origin: center;
  animation: hint-turn 7s linear infinite;
}
@keyframes hint-turn { to { transform: rotate(360deg); } }

/* The last move: windows that came on flicker like a tube, windows that went off fade. */
svg.tower .on-now { animation: flick-on .55s linear both; }
@keyframes flick-on {
  0% { opacity: 0; }
  14% { opacity: 1; }
  26% { opacity: .1; }
  40% { opacity: 1; }
  52% { opacity: .5; }
  70%, 100% { opacity: 1; }
}
svg.tower .ghost { animation: fade-off .35s ease-out both; }
@keyframes fade-off { from { opacity: 1; } to { opacity: 0; } }
svg.tower .frame-now {
  transform-box: fill-box;
  transform-origin: center;
  animation: frame-pop .3s ease-out both;
}
@keyframes frame-pop { from { transform: scale(1.25); } to { transform: scale(1); } }

/* A lit tower: a ripple of white from the last switch, the moon, some fireworks. */
svg.tower .win { animation: win-wave .8s ease-in-out both; }
@keyframes win-wave { 35% { fill: #fff; } }
svg.tower .d0 { animation-delay: .15s; }
svg.tower .d1 { animation-delay: .24s; }
svg.tower .d2 { animation-delay: .33s; }
svg.tower .d3 { animation-delay: .42s; }
svg.tower .d4 { animation-delay: .51s; }
svg.tower .d5 { animation-delay: .6s; }
svg.tower .d6 { animation-delay: .69s; }
svg.tower .d7 { animation-delay: .78s; }
svg.tower .d8 { animation-delay: .87s; }
svg.tower .d9 { animation-delay: .96s; }
svg.tower .d10 { animation-delay: 1.05s; }
svg.tower .d11 { animation-delay: 1.14s; }
svg.tower .d12 { animation-delay: 1.23s; }
svg.tower .moon { animation: moonrise 2.6s cubic-bezier(.16, .8, .3, 1) .35s both; }
@keyframes moonrise { from { transform: translateY(440px); } }
svg.tower .spark { opacity: 0; animation: spark 1.3s ease-out 3 both; }
svg.tower .near { --far: .52; }
svg.tower .burst-1 { animation-delay: 1s; }
svg.tower .burst-2 { animation-delay: 1.45s; }
svg.tower .burst-3 { animation-delay: 1.9s; }
@keyframes spark {
  0% { opacity: 1; transform: translate(0, 0); }
  60% { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(var(--dx) * var(--far, 1)), calc(var(--dy) * var(--far, 1))); }
}
/* Twelve directions, thirty degrees apart, each sagging a little as if under gravity. */
svg.tower .to-0 { --dx: 84px; --dy: 12px; }
svg.tower .to-1 { --dx: 73px; --dy: 54px; }
svg.tower .to-2 { --dx: 42px; --dy: 85px; }
svg.tower .to-3 { --dx: 0px; --dy: 96px; }
svg.tower .to-4 { --dx: -42px; --dy: 85px; }
svg.tower .to-5 { --dx: -73px; --dy: 54px; }
svg.tower .to-6 { --dx: -84px; --dy: 12px; }
svg.tower .to-7 { --dx: -73px; --dy: -30px; }
svg.tower .to-8 { --dx: -42px; --dy: -61px; }
svg.tower .to-9 { --dx: 0px; --dy: -72px; }
svg.tower .to-10 { --dx: 42px; --dy: -61px; }
svg.tower .to-11 { --dx: 73px; --dy: -30px; }

/* Scenery that is always a little alive. */
svg .twinkle { animation: twinkle 3.4s ease-in-out infinite; }
svg .twinkle.late { animation-delay: 1.1s; }
svg .twinkle.later { animation-delay: 2.3s; }
@keyframes twinkle { 50% { opacity: .2; } }
svg .beacon { animation: blink 1.8s linear infinite; }
@keyframes blink { 0%, 55% { opacity: 1; } 56%, 100% { opacity: .2; } }

/* Phones zoom in on the tower and trim spare sky; how far depends on its width and height.
   A crop step is 50 canvas units, which is 5% of the canvas width before zooming. */
@media (max-width: 640px) {
  .game .canvas { --zoom: 1; --crop: 0; }
  .game .canvas.zoom-a { --zoom: 2.2; }
  .game .canvas.zoom-b { --zoom: 1.8; }
  .game .canvas.zoom-c { --zoom: 1.5; }
  .game .canvas.zoom-d { --zoom: 1.25; }
  .game .canvas.crop-1 { --crop: 1; }
  .game .canvas.crop-2 { --crop: 2; }
  .game .canvas.crop-3 { --crop: 3; }
  .game .canvas svg {
    width: calc(var(--zoom) * 100%);
    margin-left: calc((var(--zoom) - 1) * -50%);
    margin-top: calc(var(--crop) * var(--zoom) * -5%);
  }
  .game .info-bar { grid-template-columns: 1fr; }
  .game .info-text { min-height: 4.5em; }
}

@media (prefers-reduced-motion: reduce) {
  svg.tower *, svg .twinkle, svg .beacon, .banner, .controls a.go { animation: none !important; }
  svg.tower .ghost { display: none; }
}

/* ---------- Lightson: the city (front page) ---------- */

.pitch { font-size: 1.1em; max-width: 46em; }
.city > .controls { border-top: none; }
.street-name { margin: 1.3em 0 .35em; font-size: 1.15em; }
.street-name small { font-weight: 400; font-size: .8em; margin-left: .6em; }
.strip { background: #090b22; }
.strip svg { width: 100%; max-width: none; }
svg.street .spot { outline: none; cursor: pointer; }
svg.street .plot { fill: #fff; fill-opacity: 0; stroke: #fff; stroke-opacity: 0; stroke-width: 2; }
svg.street .spot:focus-visible .plot { fill-opacity: .07; stroke-opacity: .7; }
@media (hover: hover) {
  svg.street .spot:hover .plot { fill-opacity: .07; stroke-opacity: .7; }
}
svg.street .next .plot {
  stroke: #f5c400;
  stroke-opacity: 1;
  stroke-dasharray: 9 7;
  animation: beckon 1.6s ease-in-out infinite;
}
@keyframes beckon { 50% { stroke-opacity: .25; } }

.towers {
  list-style: none;
  margin: .35em 0 0;
  padding: 0;
  display: grid;
  gap: .1em .5em;
  text-align: center;
  font-size: .9em;
  line-height: 1.3;
}
.towers.cols-3 { grid-template-columns: repeat(3, 1fr); }
.towers.cols-4 { grid-template-columns: repeat(4, 1fr); }
.towers.cols-5 { grid-template-columns: repeat(5, 1fr); }
.towers .no { color: #555; }
.towers .stars { display: block; }
.rules { padding-left: 1.2em; }
.rules li { margin: .3em 0; }

@media (max-width: 640px) {
  .towers.cols-3, .towers.cols-4, .towers.cols-5 { grid-template-columns: 1fr 1fr; text-align: left; }
  .towers .stars { display: inline; }
  .street-name small { display: block; margin-left: 0; }
}
@media (prefers-reduced-motion: reduce) {
  svg.street .next .plot { animation: none; }
}
