/* lanhouse: a lan house in a neon night city. The brand fuchsia is the lead light, a cold
   cyan is the second one; ultraviolet lights only the drawings of the games (img/rigs/), and a
   black-light green only the laser tag arena of PC 04. Panels are cut at 45 degrees, like the
   letters of the display face (Chakra Petch); thin lines, tick rulers and micro-labels make the
   HUD. Dark only, on purpose: the night is the brand.
   Every path is absolute from the root, because the sites module answers /games/playra and
   /games/playra/ with the same file. */

/* lets the cut edge of a panel fade between colours on hover */
@property --edge {
  syntax: "<color>";
  inherits: false;
  initial-value: #2b2338;
}

:root {
  color-scheme: dark;

  --night: #07060b;
  --panel: #100c18;
  --panel-hi: #161120;
  --line: #2b2338;
  --line-hi: #463a5c;

  /* contrast on --panel-hi, the lightest ground with text */
  --ink: #f0ebf6;         /* 15.8:1 */
  --ink-soft: #c3b9d2;    /*  9.9:1 */
  --ink-dim: #a397b5;     /*  6.7:1, labels only */

  --pink: #c43fd0;        /* brand fuchsia: lines, fills, glow; never text */
  --pink-text: #de82e6;   /* fuchsia text, 7.4:1 */
  --pink-core: #ffe4fb;   /* the white-hot core of the tube */
  --cyan: #1fd6ec;
  --cyan-text: #7ee9f7;   /* 13.1:1 */
  --violet: #8d7dff;
  --violet-text: #b2a8ff; /* 8.8:1 */

  --gutter: 16px;

  --font-body: "Barlow", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-hud: "Chakra Petch", "Bahnschrift", "DIN Alternate", "Roboto Condensed", "Arial Narrow", system-ui, sans-serif;
}

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--night);
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--night);
  color: var(--ink);
  font: 400 1.0625rem/1.6 var(--font-body);
  overflow-wrap: break-word;
}

main { flex: 1 0 auto; }

a { color: var(--pink-text); text-underline-offset: .2em; text-decoration-thickness: 1px; }
a:hover { color: var(--pink-core); }
:focus-visible { outline: 2px solid var(--cyan-text); outline-offset: 3px; }

::selection { background: var(--pink); color: var(--night); }

.wrap {
  width: 100%;
  max-width: 72rem;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

@media (min-width: 48rem) {
  .wrap { padding-inline: 2rem; }
}

/* ---------- the cut panel ----------
   Two corners cut at 45 degrees (top right, bottom left). The 1px edge follows the cut:
   the border draws the straight sides, two gradients draw the diagonals. Each panel sets
   --cut, --edge and --fill. Glow goes on a parent with drop-shadow, because the clip
   would cut a box-shadow. */

.skip,
.kicker,
.blade,
.screen,
.desk,
.status,
.tag,
.spec,
.machines a,
.bar-link,
.play {
  --cut: 12px;
  --fill: var(--panel);
  border: 1px solid var(--edge);
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, var(--cut) 100%, 0 calc(100% - var(--cut)));
  background:
    linear-gradient(225deg, var(--edge) calc(var(--cut) * .7071 + 1px), transparent 0) border-box,
    linear-gradient(45deg, var(--edge) calc(var(--cut) * .7071 + 1px), transparent 0) border-box,
    var(--fill) border-box;
  transition: --edge .2s ease;
}

.skip {
  --cut: 8px;
  --edge: var(--pink);
  --fill: var(--pink);
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
  padding: .6rem .9rem;
  color: var(--night);
  font: 600 .875rem/1.2 var(--font-hud);
  letter-spacing: .06em;
  text-transform: uppercase;
  text-decoration: none;
}
.skip:focus { left: var(--gutter); top: var(--gutter); color: var(--night); }

/* ---------- labels: the small technical type of the HUD ---------- */

.hud,
.kicker,
.osd,
.genre,
.pc,
.counter,
.status,
.tag,
.spec h2,
.spec dt,
.machines,
.bar-link,
.play,
.no-signal {
  font-family: var(--font-hud);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* a ruler: one thin line with ticks under it */
.pc::after,
.room-head::before,
.spec h2::after {
  content: "";
  display: block;
  height: 6px;
  background:
    linear-gradient(var(--line-hi), var(--line-hi)) left top / 100% 1px no-repeat,
    repeating-linear-gradient(to right, var(--line-hi) 0 1px, transparent 1px 8px) left top / 100% 4px no-repeat;
}

/* ---------- the sign ---------- */

.sign {
  font-family: var(--font-hud);
  font-weight: 700;
  line-height: .95;
  letter-spacing: -.01em;
  color: #ffd6f9;
  text-shadow:
    -.025em 0 0 rgba(31, 214, 236, .55),
    0 0 2px #fff,
    0 0 8px var(--pink-text),
    0 0 20px var(--pink),
    0 0 44px var(--pink),
    0 0 96px rgba(196, 63, 208, .7);
}

/* ---------- home: the street outside ---------- */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: clamp(1.25rem, 3vw, 2rem) clamp(9.5rem, 24vw, 17rem);
  background:
    radial-gradient(80% 60% at 50% 100%, rgba(196, 63, 208, .38), transparent 72%),
    radial-gradient(40% 45% at 92% 18%, rgba(31, 214, 236, .12), transparent 70%),
    linear-gradient(to bottom, var(--night) 0, #0d0915 60%, #170c21 100%);
}

/* the city, sitting on a fuchsia street line: a box as wide as the street (58rem at least,
   centred) and as tall as the art. city.svg is the still picture; each span draws one layer of
   lights over it at the same size (tools/city.py draws them all), and only its opacity moves */
.city {
  position: absolute;
  z-index: -1;
  bottom: 0;
  left: min(0px, 50% - 29rem);
  width: max(100%, 58rem);
  aspect-ratio: 1600 / 260;
  background: url("/img/skyline/city.svg") 0 0 / 100% 100% no-repeat;
}
.city > span {
  position: absolute;
  inset: 0;
  background-size: 100% 100%;
  background-repeat: no-repeat;
}
.lights--1 { background-image: url("/img/skyline/lights-1.svg"); }
.lights--2 { background-image: url("/img/skyline/lights-2.svg"); }
.lights--3 { background-image: url("/img/skyline/lights-3.svg"); }
.lights--4 { background-image: url("/img/skyline/lights-4.svg"); }
.lights--5 { background-image: url("/img/skyline/lights-5.svg"); }
.lights--6 { background-image: url("/img/skyline/lights-6.svg"); }
.signs--a { background-image: url("/img/skyline/signs-a.svg"); }
.signs--b { background-image: url("/img/skyline/signs-b.svg"); }
.beacons { background-image: url("/img/skyline/beacons.svg"); }
/* groups 4 to 6 are dark windows that light up now and then: off while the city stands still */
.lights--4,
.lights--5,
.lights--6 { opacity: 0; }

/* the rain, in front of the city and behind the words: three tiles of vertical drops, far
   (short, faint, steep, slow) to near (long, leaning with the wind, fast). The skew slants each
   tile, and the fall moves it down by exactly one tile, so the loop never jumps. Each layer
   starts one tile above the street and runs 10rem past each side, enough for the slant */
.rain {
  position: absolute;
  z-index: -1;
  inset: 0;
}
.rain > span {
  position: absolute;
  top: calc(-1 * var(--tile));
  bottom: 0;
  left: -10rem;
  right: -10rem;
  background-size: var(--tile) var(--tile);
}
.rain-far { --tile: 140px; background-image: url("/img/rain/far.svg"); transform: skewX(6deg); }
.rain-mid { --tile: 200px; background-image: url("/img/rain/mid.svg"); transform: skewX(9deg); }
.rain-near { --tile: 300px; background-image: url("/img/rain/near.svg"); transform: skewX(12deg); }

/* scanlines over the city and the rain */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, .28) 0 1px, transparent 1px 3px);
}

.hero-in { position: relative; }

/* brand names live in the HUD strip and the machine links: no upper case there */
.hud,
.machines { text-transform: none; }

.hud {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin-bottom: clamp(2.5rem, 9vw, 5.5rem);
  color: var(--ink-dim);
  font-size: .6875rem;
  line-height: 1;
  white-space: nowrap;
}
.hud-rule {
  flex: 1;
  height: 6px;
  background:
    linear-gradient(var(--line-hi), var(--line-hi)) left top / 100% 1px no-repeat,
    repeating-linear-gradient(to right, var(--line-hi) 0 1px, transparent 1px 8px) left top / 100% 4px no-repeat;
}

.kicker {
  --cut: 8px;
  --edge: rgba(31, 214, 236, .5);
  --fill: rgba(31, 214, 236, .07);
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  margin: 0;
  padding: .45rem .8rem .45rem .65rem;
  color: var(--cyan-text);
  font-size: .75rem;
  line-height: 1.3;
}
@media (max-width: 24rem) {
  .kicker { font-size: .6875rem; letter-spacing: .1em; }
}
.kicker::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  background: var(--cyan);
  box-shadow: 0 0 8px var(--cyan);
}

.sign--hero {
  position: relative;
  margin: clamp(.75rem, 2.5vw, 1.25rem) 0 clamp(1.25rem, 3.5vw, 2rem);
  font-size: clamp(3.6rem, 17vw, 10.5rem);
}

.lead {
  margin: 0;
  max-width: 34rem;
  font-size: clamp(1.125rem, 2.4vw, 1.375rem);
  font-weight: 500;
  line-height: 1.5;
}
.hero .lead {
  padding-left: 1rem;
  border-left: 2px solid var(--pink);
  text-shadow: 0 1px 12px var(--night);
}

/* the vertical blade sign on the building, wide screens only */
.blade {
  --cut: 10px;
  --edge: rgba(31, 214, 236, .55);
  --fill: linear-gradient(to bottom, rgba(31, 214, 236, .1), rgba(7, 6, 11, .9));
  display: none;
}

@media (min-width: 62rem) {
  .blade {
    display: block;
    position: absolute;
    right: 2rem;
    top: 4.75rem;
    margin: 0;
    padding: 1.1rem .7rem;
    writing-mode: vertical-rl;
    text-orientation: upright;
    color: #e3fdff;
    font: 700 2.25rem/1 var(--font-hud);
    letter-spacing: .08em;
    text-transform: uppercase;
    text-shadow: 0 0 2px #fff, 0 0 10px var(--cyan), 0 0 24px var(--cyan);
  }
}

/* the sign catching power: two stutters and a short glitch on load, then the tube (the span
   holding the word) hums and the glitch comes back now and then. The two copies come from
   data-text and are hidden from screen readers; each shows one band of the word (its clip) and
   only its opacity and transform move. One animation per element, on purpose: Chrome leaves two
   animations of the same property on one element to the main thread, every frame, so the
   power-up is on the h1 and the hum on the tube, and each copy's glitch is a single loop whose
   cycle starts with the glitch of the load. */
.sign--hero .tube { display: block; }
.sign--hero::before,
.sign--hero::after {
  content: attr(data-text);
  content: attr(data-text) / "";
  position: absolute;
  z-index: 1;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}
.sign--hero::before { color: #c8f8ff; text-shadow: 0 0 12px var(--cyan); clip-path: inset(14% 0 62% 0); }
.sign--hero::after { color: var(--pink-core); text-shadow: 0 0 14px var(--pink); clip-path: inset(66% 0 10% 0); }

@media (prefers-reduced-motion: no-preference) {
  .sign--hero { animation: ignite 1.6s steps(1, end) .2s backwards; }
  .sign--hero .tube { animation: hum 37s ease-in-out 1.8s infinite; }
  .sign--hero::before { animation: glitch-a 67s steps(1, end) .3s infinite; }
  .sign--hero::after { animation: glitch-b 67s steps(1, end) .3s infinite; }
}

@keyframes ignite {
  0%   { opacity: .1; }
  10%  { opacity: 1; }
  16%  { opacity: .2; }
  24%  { opacity: 1; }
  46%  { opacity: .65; }
  50%  { opacity: 1; }
  100% { opacity: 1; }
}

/* the glitch: in the first 3 s (the load), then once more at 58% of the 67 s cycle, so it
   comes back 38 s and 29 s apart, each time for about a quarter of a second */
@keyframes glitch-a {
  0%     { opacity: 0; transform: none; }
  1.01%  { opacity: 1; transform: translateX(-.05em); }
  1.16%  { opacity: 1; transform: translateX(.035em); }
  1.31%  { opacity: 0; transform: none; }
  2.74%  { opacity: 1; transform: translateX(-.03em); }
  2.86%  { opacity: 0; transform: none; }
  58%    { opacity: 1; transform: translateX(-.05em); }
  58.15% { opacity: 1; transform: translateX(.035em); }
  58.3%  { opacity: 0; transform: none; }
  100%   { opacity: 0; transform: none; }
}

@keyframes glitch-b {
  0%     { opacity: 0; transform: none; }
  1.09%  { opacity: 1; transform: translateX(.05em); }
  1.24%  { opacity: 1; transform: translateX(-.025em); }
  1.36%  { opacity: 0; transform: none; }
  58.07% { opacity: 1; transform: translateX(.04em); }
  58.22% { opacity: 1; transform: translateX(-.03em); }
  58.4%  { opacity: 0; transform: none; }
  100%   { opacity: 0; transform: none; }
}

/* ---------- the room: one station per game ---------- */

.room {
  position: relative;
  padding-block: clamp(2.5rem, 6vw, 3.75rem) clamp(3.5rem, 8vw, 5.5rem);
  background: linear-gradient(to bottom, rgba(196, 63, 208, .07), transparent 14rem);
}

.room-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem 1.5rem;
  margin-bottom: 2.25rem;
}
.room-head::before { flex: 1 0 100%; margin-bottom: 1rem; }

.room-head h2 {
  margin: 0;
  color: var(--pink-text);
  font: 700 clamp(1.875rem, 5vw, 2.5rem)/1.1 var(--font-hud);
  text-shadow: 0 0 18px rgba(196, 63, 208, .45);
}

.counter {
  margin: 0;
  color: var(--ink-dim);
  font-size: .75rem;
}
.counter span { white-space: nowrap; color: var(--ink-soft); }

.stations {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 2.75rem clamp(1.5rem, 3vw, 2.25rem);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
}

.stations > li { display: flex; }

/* the two thin mounts between the monitor and the desk are the station's own background */
.station {
  flex: 1;
  display: flex;
  flex-direction: column;
  color: inherit;
  text-decoration: none;
  background:
    linear-gradient(var(--line-hi), var(--line-hi)) 26% 0 / 1px 100% no-repeat,
    linear-gradient(var(--line-hi), var(--line-hi)) 74% 0 / 1px 100% no-repeat;
  transition: filter .2s ease;
}
.station:hover { color: inherit; }
/* the monitors in the room are 4:3, like the tubes of the time; a game page keeps its wide one */
.station .screen { aspect-ratio: 4 / 3; }
.station:focus-visible { outline-offset: 8px; }
.station:hover,
.station:focus-visible { filter: drop-shadow(0 0 16px rgba(196, 63, 208, .4)); }

/* the monitor */
.screen {
  --cut: 18px;
  --glow: rgba(196, 63, 208, .45);
  --hud: rgba(222, 130, 230, .75);
  --osd: var(--pink-text);
  --art: none;
  --art-size: contain;
  --art-pos: center;
  --light: radial-gradient(90% 85% at 75% 45%, var(--glow), transparent 70%);
  --edge: var(--line-hi);
  --fill: #050409;
  position: relative;
  overflow: clip;
  display: flex;
  align-items: flex-end;
  width: 100%;   /* definite, or the min-height below would widen it through the aspect ratio */
  min-height: 12rem;
  aspect-ratio: 16 / 10;
  padding: 1rem 1.25rem 1.1rem;
}

.screen::before,
.screen::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* the light of the screen: its art over its glow, one layer, so the screen hums by opacity.
   A game screen has no art here (its drawing is the .rig): only the glow behind the rig */
.screen::before {
  background: var(--art) var(--art-pos) / var(--art-size) no-repeat, var(--light);
}

/* glass: scanlines, dark corners, a shade for the title, and the two HUD brackets on the
   corners that are not cut */
.screen::after {
  background:
    linear-gradient(var(--hud), var(--hud)) left 9px top 9px / 18px 1px no-repeat,
    linear-gradient(var(--hud), var(--hud)) left 9px top 9px / 1px 18px no-repeat,
    linear-gradient(var(--hud), var(--hud)) right 9px bottom 9px / 18px 1px no-repeat,
    linear-gradient(var(--hud), var(--hud)) right 9px bottom 9px / 1px 18px no-repeat,
    repeating-linear-gradient(to bottom, rgba(255, 255, 255, .04) 0 1px, transparent 1px 3px),
    radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, .5) 100%),
    radial-gradient(70% 62% at 0 100%, rgba(5, 4, 9, .9), rgba(5, 4, 9, .55) 50%, transparent 80%);
}

.osd {
  position: absolute;
  z-index: 1;
  top: .85rem;
  left: 1.25rem;
  margin: 0;
  color: var(--osd);
  font-size: .6875rem;
  line-height: 1;
}

.screen-title {
  position: relative;
  z-index: 1;
  margin: 0;
  color: #fff;
  font: 700 clamp(2rem, 7vw, 2.5rem)/1 var(--font-hud);
  letter-spacing: -.005em;
  /* a dark edge first, so the word stays crisp where it crosses the drawing */
  text-shadow: 0 1px 3px rgba(5, 4, 9, .85), 0 0 6px var(--glow), 0 0 20px var(--glow);
}

.screen--playra {
  --glow: rgba(31, 214, 236, .3);
  --hud: rgba(126, 233, 247, .75);
  --osd: var(--cyan-text);
}

.screen--playwar {
  --glow: rgba(141, 125, 255, .34);
  --hud: rgba(178, 168, 255, .75);
  --osd: var(--violet-text);
}

.screen--labirinto {
  --glow: rgba(141, 125, 255, .3);
  --light: radial-gradient(60% 85% at 82% 50%, var(--glow), transparent 70%);
}

/* ---------- the rigs: each game drawn on the hardware it would sit on in an old lan house ----------
   A rig is a box with the ratio of its drawing (img/rigs/<game>/), standing at the right of the
   screen, with the lower left kept clear for the title. What moves in it is a span placed in
   percent of the box, so it lines up at any size. .glass is the picture tube or the phone screen,
   cut to its rounded corners; on PC 01 it is also the slot for a gameplay video (README). All our
   own drawing: no marks, no names, no art of anyone's game. */
.rig {
  position: absolute;
  right: var(--rig-right, 0%);
  bottom: var(--rig-bottom, 0%);
  height: var(--rig-height, 100%);
  aspect-ratio: var(--rig-ratio);
  background: var(--rig) 0 0 / 100% 100% no-repeat;
}
.rig span {
  position: absolute;
  display: block;
  background-position: 0 0;
  background-size: 100% 100%;
  background-repeat: no-repeat;
}
.rig .glass { overflow: hidden; }
.glass > span { inset: 0; }

/* the glass of a tube: scanlines, the bulge catching the light, dark edges */
.glass--tube::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(70% 50% at 30% 18%, rgba(255, 255, 255, .13), transparent 70%),
    repeating-linear-gradient(to bottom, rgba(0, 0, 0, .35) 0 1px, transparent 1px 3px),
    radial-gradient(ellipse at center, transparent 58%, rgba(0, 0, 0, .55) 100%);
}

/* PC 01: a grey console on a small TV; the TV shows the radar, the sweep turns, units light up */
.rig--playra {
  --rig: url("/img/rigs/playra/rig.svg");
  --rig-ratio: 1;
}
.rig--playra .glass {
  left: 22%;
  top: 27.667%;
  width: 50.667%;
  height: 38%;
  border-radius: 7.9% / 10.5%;
  background-image: url("/img/rigs/playra/minimap.svg");
}
/* a circle as wide as the glass, centred on it: the trail of light and its leading line, which
   points up at 0 degrees */
.glass > .sweep {
  inset: auto;
  left: 0;
  top: -16.667%;
  width: 100%;
  height: 133.333%;
  border-radius: 50%;
  background:
    linear-gradient(#c8f8ff, #c8f8ff) 50% 0 / 1px 50% no-repeat,
    conic-gradient(from 270deg, rgba(31, 214, 236, 0), rgba(31, 214, 236, .4) 90deg, transparent 90deg);
  transform: rotate(150deg);
}
.blips { opacity: .6; }
.blips--a { background-image: url("/img/rigs/playra/blips-a.svg"); }
.blips--b { background-image: url("/img/rigs/playra/blips-b.svg"); }
.blips--c { background-image: url("/img/rigs/playra/blips-c.svg"); }
.blips--d { background-image: url("/img/rigs/playra/blips-d.svg"); }
/* a gameplay video in the TV, when there is one: the radar stays under it as the fallback
   (a <video class="feed">, or a <picture class="feed"> holding an animated image; README) */
.glass > .feed,
.glass > .feed img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* PC 02: a beige tower and its monitor; the game on the monitor is blurred on purpose. The
   units walk, the day turns to night, the hard disk light blinks */
.rig--playwar {
  --rig: url("/img/rigs/playwar/rig.svg");
  --rig-ratio: 1;
}
.rig--playwar .glass {
  left: 15.333%;
  top: 19.333%;
  width: 46.667%;
  height: 35%;
  border-radius: 5.7% / 7.6%;
  background-image: url("/img/rigs/playwar/scene.svg");
}
.units { background-image: url("/img/rigs/playwar/units.svg"); }
.night {
  opacity: 0;
  background:
    radial-gradient(50% 40% at 62% 46%, rgba(255, 228, 251, .12), transparent 70%),
    rgba(9, 6, 34, .62);
}
.hdd {
  left: 79.333%;
  top: 41.667%;
  width: 2%;
  height: 2%;
  border-radius: 50%;
  background: radial-gradient(circle, #ffe4fb 0 28%, #de82e6 40%, rgba(196, 63, 208, 0) 72%);
  opacity: .9;
}

/* PC 03: a game of RPG seen from above; the d20 rolls in, the ring marks whose turn it is */
.rig--lurex {
  --rig: url("/img/rigs/lurex/rig.svg");
  --rig-ratio: 420 / 300;
}
.rig--lurex .die {
  left: 23.81%;
  top: 45.333%;
  width: 23.81%;
  height: 33.333%;
  background-image: url("/img/d20.svg");
}
.rig--lurex .turn {
  left: 67.6%;
  top: 29.17%;
  width: 6.19%;
  height: 8.667%;
  background-image: url("/img/rigs/lurex/turn.svg");
}

/* PC 04: a laser tag arena, as wide as a game page's screen and as tall as any screen, so a
   card shows its middle. The beams fire, the vests wait with their lights pulsing, the haze
   drifts */
.rig--firerange {
  --rig: url("/img/rigs/firerange/arena.svg");
  --rig-ratio: 840 / 320;
  --rig-height: 100%;
  --rig-bottom: 0;
  right: auto;
  left: 50%;
  transform: translateX(-50%);
}
.rig--firerange > span { inset: 0; }
.rig--firerange > .haze {
  left: -8%;
  right: -8%;
  background:
    radial-gradient(30% 22% at 30% 40%, rgba(178, 168, 255, .1), transparent 70%),
    radial-gradient(26% 20% at 70% 30%, rgba(222, 130, 230, .09), transparent 70%),
    radial-gradient(40% 18% at 55% 62%, rgba(126, 233, 247, .06), transparent 70%);
}
.beam { opacity: 0; }
.beam--a { background-image: url("/img/rigs/firerange/beam-a.svg"); }
.beam--b { background-image: url("/img/rigs/firerange/beam-b.svg"); }
.beam--c { background-image: url("/img/rigs/firerange/beam-c.svg"); opacity: 1; }
.pads--a { background-image: url("/img/rigs/firerange/pads-a.svg"); }
.pads--b { background-image: url("/img/rigs/firerange/pads-b.svg"); }

/* PC 05: a phone standing on the desk, the maze building itself room by room. Each room is a
   layer as big as the glass; the hero walks from room to room and the torch burns down. The
   class is .maze-room because .room is the section of the home page, whose padding and ground
   it would take */
.rig--labirinto {
  --rig: url("/img/rigs/labirinto/phone.svg");
  --rig-ratio: 200 / 340;
  --rig-height: 90%;
  --rig-right: 6%;
  --rig-bottom: 4%;
  transform: rotate(-6deg);
}
.rig--labirinto .glass {
  left: 11%;
  top: 4.706%;
  width: 78%;
  height: 90.588%;
  border-radius: 11.5% / 5.84%;
  background-image: url("/img/rigs/labirinto/screen.svg");
}
.maze-room--1 { background-image: url("/img/rigs/labirinto/room-1.svg"); transform-origin: 50% 88.312%; }
.maze-room--2 { background-image: url("/img/rigs/labirinto/room-2.svg"); transform-origin: 50% 72.727%; }
.maze-room--3 { background-image: url("/img/rigs/labirinto/room-3.svg"); transform-origin: 80.769% 72.727%; }
.maze-room--4 { background-image: url("/img/rigs/labirinto/room-4.svg"); transform-origin: 80.769% 57.143%; }
.maze-room--5 { background-image: url("/img/rigs/labirinto/room-5.svg"); transform-origin: 80.769% 41.558%; }
.maze-room--6 { background-image: url("/img/rigs/labirinto/room-6.svg"); transform-origin: 50% 41.558%; }
.maze-room--7 { background-image: url("/img/rigs/labirinto/room-7.svg"); transform-origin: 50% 25.974%; }
/* the hero starts in room 1 and steps one room (four times its size) at a time; standing still,
   it waits at the way out. The class is .player because .hero is the street of the home page */
.glass > .player {
  inset: auto;
  left: 46.154%;
  top: 86.364%;
  width: 7.692%;
  height: 3.896%;
  border-radius: 50%;
  background: radial-gradient(circle, #e3fdff 0 30%, #1fd6ec 42%, rgba(31, 214, 236, .35) 60%, rgba(31, 214, 236, 0) 72%);
  transform: translate(0, -1600%);
}
/* the outline of the room just laid, fuchsia, one room in size */
.glass > .new-room {
  inset: auto;
  left: 34.615%;
  top: 80.519%;
  width: 30.769%;
  height: 15.584%;
  box-shadow: inset 0 0 0 1.5px var(--pink-text), inset 0 0 10px rgba(196, 63, 208, .8), 0 0 10px rgba(196, 63, 208, .8);
  opacity: 0;
}
.glass > .torch {
  inset: auto;
  left: 16.667%;
  top: 9.091%;
  width: 74.359%;
  height: 1.948%;
  border-radius: 3px;
  background: repeating-linear-gradient(to right, #de82e6 0 8.6%, transparent 8.6% 10%);
  transform-origin: 0 50%;
  transform: scaleX(.3);
}

.station:hover .screen,
.station:focus-visible .screen { --edge: var(--pink); }

.station:hover .screen-title,
.station:focus-visible .screen-title {
  text-shadow:
    0 1px 3px rgba(5, 4, 9, .85),
    -2px 0 0 rgba(31, 214, 236, .8),
    2px 0 0 rgba(196, 63, 208, .8),
    0 0 20px var(--glow);
}

/* the desk card under the monitor */
.desk {
  --edge: var(--line);
  --fill: linear-gradient(to bottom, var(--panel-hi), var(--panel));
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .6rem;
  margin-top: 1.1rem;
  padding: 1rem 1.25rem 1.2rem;
}

.desk p { margin: 0; }

.genre {
  color: var(--ink-dim);
  font-size: .6875rem;
  line-height: 1.3;
}

.plates {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: auto;
  padding-top: .5rem;
}

/* the status plate: a square LED and the word */
.status {
  --cut: 7px;
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  margin: 0;
  padding: .32rem .7rem .32rem .6rem;
  font-size: .75rem;
  line-height: 1.2;
}

.led {
  flex: none;
  width: 7px;
  height: 7px;
  background: currentColor;
  box-shadow: 0 0 5px currentColor, 0 0 12px currentColor;
}

/* on the air: a steady cyan light (nothing blinks), for a game you can play now */
.status--live {
  --edge: rgba(31, 214, 236, .55);
  --fill: rgba(31, 214, 236, .08);
  color: var(--cyan-text);
}

/* work in progress: the plate carries fuchsia hazard stripes */
.status--dev {
  --edge: rgba(196, 63, 208, .65);
  --fill: repeating-linear-gradient(135deg, rgba(196, 63, 208, .16) 0 6px, transparent 6px 12px) var(--panel);
  color: var(--pink-text);
}

/* a tag says what the game is. Lower case, because a tag can hold a name (OpenRA) */
.tag {
  --cut: 7px;
  --edge: var(--line-hi);
  --fill: transparent;
  margin: 0;
  padding: .32rem .65rem;
  color: var(--ink-soft);
  font-size: .75rem;
  letter-spacing: .06em;
  line-height: 1.2;
  text-transform: none;
}

/* ---------- the play button: the one call to play, for a game on the air ----------
   Light fuchsia fill with dark text (8.1:1), cut like every panel. The glow is a
   drop-shadow on .play-slot, since the clip cuts a box-shadow, and the focus ring is drawn
   inside, in the dark ink, for the same reason. 2.75rem tall: a full touch target. */
.play-slot {
  position: relative;
  margin: 0;
  filter: drop-shadow(0 0 10px rgba(196, 63, 208, .55));
}

/* the halo behind the button: it swells and fades like an arcade cabinet calling you over */
.play-slot::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -.7rem -1rem;
  background: radial-gradient(closest-side, rgba(222, 130, 230, .6), rgba(196, 63, 208, .28) 55%, rgba(196, 63, 208, 0));
  opacity: .55;
  pointer-events: none;
}

.play {
  --cut: 10px;
  --edge: var(--pink-text);
  --fill: var(--pink-text);
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  gap: .65rem;
  min-height: 2.75rem;
  padding: 0 1.5rem 0 1.15rem;
  color: var(--night);
  font-size: .9375rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
}

/* the light that sweeps across the button every few seconds, under the word and cut with the
   button; standing still, it waits outside */
.play::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: 0;
  left: 0;
  width: 45%;
  background: linear-gradient(105deg, rgba(255, 255, 255, 0) 15%, rgba(255, 255, 255, .85) 50%, rgba(255, 255, 255, 0) 85%);
  transform: translateX(-110%);
  pointer-events: none;
}
.play:hover,
.play:focus-visible { --edge: var(--pink-core); --fill: var(--pink-core); color: var(--night); }
.play:focus-visible { outline: 2px solid var(--night); outline-offset: -5px; }

.play-icon {
  flex: none;
  width: .6rem;
  height: .7rem;
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

/* a station with a play button: the card is one link and a link cannot hold another, so
   the button sits next to it in the list item, over room kept free at the foot of the desk */
.stations > li.has-play { position: relative; }
.has-play .desk { padding-bottom: calc(1.2rem + 2.75rem + .9rem); }
.has-play .play-slot {
  position: absolute;
  z-index: 1;
  left: 1.25rem;
  bottom: 1.2rem;
}

/* words for screen readers only ("Jogar playRA" on the card); names keep their case */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
  text-transform: none;
}

/* ---------- a game's own page ---------- */

.bar {
  position: relative;
  border-bottom: 1px solid var(--line);
  background:
    repeating-linear-gradient(to bottom, rgba(0, 0, 0, .25) 0 1px, transparent 1px 3px),
    radial-gradient(60% 140% at 0% 0%, rgba(196, 63, 208, .14), transparent 70%),
    var(--night);
}
.bar::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  width: min(14rem, 40%);
  height: 1px;
  background: linear-gradient(to right, var(--pink), transparent);
}

.bar-in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .75rem 1.5rem;
  min-height: 4.25rem;
  padding-block: .6rem;
}

.bar-sign {
  font-size: 1.875rem;
  text-decoration: none;
  text-shadow:
    -.025em 0 0 rgba(31, 214, 236, .5),
    0 0 2px #fff,
    0 0 7px var(--pink-text),
    0 0 16px var(--pink),
    0 0 30px rgba(196, 63, 208, .6);
}
.bar-sign:hover,
.bar-sign:focus-visible {
  color: #fff;
  text-shadow:
    -.06em 0 0 rgba(31, 214, 236, .8),
    .04em 0 0 rgba(196, 63, 208, .9),
    0 0 7px var(--pink-text),
    0 0 18px var(--pink);
}

.bar-link {
  --cut: 7px;
  --edge: rgba(31, 214, 236, .5);
  --fill: rgba(31, 214, 236, .06);
  padding: .45rem .8rem;
  color: var(--cyan-text);
  font-size: .75rem;
  line-height: 1.2;
  text-decoration: none;
}
.bar-link:hover,
.bar-link:focus-visible { --edge: var(--cyan); color: #e3fdff; }

/* the clip would cut a focus ring drawn outside the panel, so a cut link draws it inside */
.bar-link:focus-visible,
.machines a:focus-visible {
  outline: 2px solid var(--cyan-text);
  outline-offset: -5px;
}

.game {
  padding-block: 1.75rem clamp(3.5rem, 8vw, 5.5rem);
  background:
    radial-gradient(60% 26rem at 85% 0, rgba(31, 214, 236, .06), transparent 70%),
    radial-gradient(70% 30rem at 10% 0, rgba(196, 63, 208, .09), transparent 70%);
  background-repeat: no-repeat;
}

/* "PC 01" followed by a ruler */
.pc {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin: 0;
  color: var(--ink-dim);
  font-size: .75rem;
  line-height: 1;
}
.pc::after { flex: 1; transform: translateY(1px); }

.game .screen {
  --cut: 26px;
  margin-block: 1rem 1.5rem;
  min-height: 13rem;
  padding: clamp(1.1rem, 3vw, 2rem);
}

@media (min-width: 48rem) {
  .game .screen { --rig-right: 5%; aspect-ratio: 21 / 8; }
}

.game .screen-title {
  font-size: clamp(3rem, 12vw, 6rem);
  text-shadow:
    0 1px 4px rgba(5, 4, 9, .85),
    -.02em 0 0 rgba(31, 214, 236, .45),
    0 0 8px var(--glow),
    0 0 28px var(--glow);
}

.game-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem;
  margin-bottom: 2.25rem;
}
.game-meta .play-slot { margin-right: .6rem; }

.game-body {
  display: grid;
  gap: 2.5rem;
  align-items: start;
}

@media (min-width: 54rem) {
  .game-body { grid-template-columns: minmax(0, 1fr) 19rem; gap: 4rem; }
}

.prose { max-width: 38rem; }
.prose > * { margin-block: 0 1.1rem; }
.prose .lead { margin-bottom: 1.5rem; }

.prose h2 {
  margin: 2.25rem 0 1rem;
  color: var(--pink-text);
  font: 700 1.625rem/1.2 var(--font-hud);
}
.prose h2::before {
  content: "// ";
  content: "// " / "";
  color: var(--cyan-text);
  font-weight: 500;
}

.prose ul { list-style: none; padding-left: 0; }
.prose li {
  position: relative;
  margin-bottom: .5rem;
  padding-left: 1.4rem;
}
.prose li::before {
  content: "";
  position: absolute;
  left: .15rem;
  top: .62em;
  width: 7px;
  height: 7px;
  background: var(--pink);
  clip-path: polygon(0 0, 100% 0, 100% 100%, 30% 100%, 0 70%);
}
.prose strong { color: #fff; font-weight: 600; }

/* the spec sheet on the side of the machine */
.spec {
  --cut: 16px;
  --edge: var(--line-hi);
  --fill: linear-gradient(to bottom, var(--panel-hi), var(--panel));
  padding: 1.1rem 1.25rem 1.2rem;
  font-size: .9375rem;
}

.spec h2 {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin: 0 0 .5rem;
  color: var(--cyan-text);
  font-size: .75rem;
  line-height: 1;
}
.spec h2::after { flex: 1; transform: translateY(1px); }

.spec dl { margin: 0; }

.spec dl > div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding-block: .6rem;
  border-top: 1px dashed var(--line);
}
.spec dl > div:first-child { border-top: 0; }

.spec dt {
  flex: none;
  padding-top: .2em;
  color: var(--ink-dim);
  font-size: .6875rem;
  line-height: 1.4;
}
.spec dd { margin: 0; text-align: right; }
.nowrap { white-space: nowrap; }

.machines {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: .75rem 1.5rem;
  margin-top: 3.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: .8125rem;
  letter-spacing: .06em;
}

.machines a {
  --cut: 9px;
  --edge: var(--line-hi);
  --fill: var(--panel);
  padding: .7rem 1rem;
  color: var(--pink-text);
  text-decoration: none;
}
.machines a:hover,
.machines a:focus-visible { --edge: var(--pink); color: var(--pink-core); }

/* ---------- 404: a machine with no signal ---------- */

/* a screen that is off: the glow stays on the glass, the static is still and dim */
.screen--off {
  --glow: rgba(70, 58, 92, .5);
  --hud: rgba(163, 151, 181, .6);
  --art: url("/img/static.svg");
  --art-size: 240px 240px;
  --art-pos: 0 0;
  --fill: var(--light) #050409;
  align-items: center;
  justify-content: center;
}
.screen--off::before { background: var(--art) var(--art-pos) / var(--art-size) repeat; opacity: .55; }

.no-signal {
  position: relative;
  z-index: 1;
  margin: 0;
  padding: .4rem .8rem;
  background: rgba(5, 4, 9, .85);
  color: var(--ink);
  font-size: .875rem;
  letter-spacing: .3em;
  text-shadow: -2px 0 0 rgba(31, 214, 236, .7), 2px 0 0 rgba(196, 63, 208, .7);
}

.lost h1 {
  margin: 0 0 .75rem;
  color: var(--pink-text);
  font: 700 clamp(2.25rem, 8vw, 3.5rem)/1.1 var(--font-hud);
  text-shadow: 0 0 18px rgba(196, 63, 208, .45);
}

.lost ul { list-style: none; padding: 0; }
.lost li { margin-bottom: .5rem; }
.lost .pc { display: inline-block; min-width: 4.5rem; }
.lost .pc::after { content: none; }

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

.site-foot {
  flex: none;
  position: relative;
  padding-block: 2rem 2.5rem;
  border-top: 1px solid var(--line);
  background: linear-gradient(to bottom, rgba(196, 63, 208, .05), transparent);
  color: var(--ink-soft);
  font-size: .9375rem;
}
.site-foot::before {
  content: "";
  position: absolute;
  top: -1px;
  right: 0;
  width: min(14rem, 40%);
  height: 1px;
  background: linear-gradient(to left, var(--cyan), transparent);
}

.site-foot .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem 2rem;
}

.site-foot p { margin: 0; }

.foot-sign {
  color: var(--pink-text);
  font: 700 1.5rem/1 var(--font-hud);
  text-shadow: 0 0 12px rgba(196, 63, 208, .6);
}

/* ---------- the street moves ----------
   The rain falls, the signs hum, the windows of the city go on and off. Every loop moves only
   opacity or transform, so the browser runs it on the compositor: no layout, no paint and no
   filter per frame, and it stops while the tab is hidden. The long cycles are all different
   prime numbers of seconds, started at negative delays, so nothing ticks like a metronome. A
   flicker has at most two dark beats in a second (WCAG 2.3.1 allows three flashes). The LED of
   the "no ar" plate is not here: it is a steady light. */

@media (prefers-reduced-motion: no-preference) {
  .rain-far { animation: rain-far .6s linear infinite; }
  .rain-mid { animation: rain-mid .38s linear infinite; }
  .rain-near { animation: rain-near .3s linear infinite; }

  .lights--1 { animation: out-long 31s linear -9s infinite; }
  .lights--2 { animation: out-twice 43s linear -27s infinite; }
  .lights--3 { animation: out-long 53s linear -40s infinite; }
  .lights--4 { animation: on-long 41s linear -4s infinite; }
  .lights--5 { animation: on-twice 47s linear -18s infinite; }
  .lights--6 { animation: on-long 59s linear -33s infinite; }
  .signs--a { animation: buzz 11s ease-in-out -3s infinite; }
  .signs--b { animation: buzz 19s ease-in-out -12s infinite; }
  .beacons { animation: beacon 2.6s ease-in-out infinite; }

  .blade { animation: hum 29s ease-in-out -11s infinite; }
  .bar-sign { animation: hum 43s ease-in-out -17s infinite; }
  .bar-sign:hover,
  .bar-sign:focus-visible { animation: none; }

  .screen:not(.screen--off)::before { animation: glow 13s ease-in-out infinite; }
  .stations > li:nth-child(3n + 2) .screen::before { animation-duration: 17s; animation-delay: -6s; }
  .stations > li:nth-child(3n) .screen::before { animation-duration: 23s; animation-delay: -15s; }
}

/* each tile falls by exactly its own height, slanted by its own skew */
@keyframes rain-far {
  from { transform: skewX(6deg) translateY(0); }
  to   { transform: skewX(6deg) translateY(140px); }
}
@keyframes rain-mid {
  from { transform: skewX(9deg) translateY(0); }
  to   { transform: skewX(9deg) translateY(200px); }
}
@keyframes rain-near {
  from { transform: skewX(12deg) translateY(0); }
  to   { transform: skewX(12deg) translateY(300px); }
}

/* a neon tube: it breathes, and twice a cycle it stutters */
@keyframes hum {
  0%    { opacity: 1; }
  9%    { opacity: .92; }
  17%   { opacity: 1; }
  21%   { opacity: 1; }
  21.2% { opacity: .35; }
  21.4% { opacity: .9; }
  21.7% { opacity: .5; }
  22%   { opacity: 1; }
  33%   { opacity: .9; }
  45%   { opacity: .98; }
  52%   { opacity: .92; }
  64%   { opacity: 1; }
  64.2% { opacity: .45; }
  64.5% { opacity: 1; }
  77%   { opacity: .9; }
  88%   { opacity: 1; }
  94%   { opacity: .94; }
  100%  { opacity: 1; }
}

/* the light of a game screen: a deeper breath and one stutter */
@keyframes glow {
  0%    { opacity: 1; }
  23%   { opacity: .78; }
  41%   { opacity: .95; }
  57%   { opacity: .82; }
  57.4% { opacity: .4; }
  57.8% { opacity: .9; }
  58.3% { opacity: .55; }
  59%   { opacity: .95; }
  78%   { opacity: .8; }
  100%  { opacity: 1; }
}

/* the small signs on the towers */
@keyframes buzz {
  0%    { opacity: 1; }
  30%   { opacity: .7; }
  52%   { opacity: 1; }
  70%   { opacity: 1; }
  70.5% { opacity: .15; }
  71%   { opacity: 1; }
  71.6% { opacity: .25; }
  72.2% { opacity: 1; }
  88%   { opacity: .75; }
  100%  { opacity: 1; }
}

/* the warning lights on the antennas */
@keyframes beacon {
  0%, 100% { opacity: .15; }
  12%, 40% { opacity: 1; }
  58%      { opacity: .15; }
}

/* lit windows that go dark for a while */
@keyframes out-long {
  0%, 46%     { opacity: 1; }
  46.4%, 79%  { opacity: 0; }
  79.4%, 100% { opacity: 1; }
}

/* lit windows that go dark twice, briefly */
@keyframes out-twice {
  0%, 17%     { opacity: 1; }
  17.4%, 31%  { opacity: 0; }
  31.4%, 70%  { opacity: 1; }
  70.4%, 77%  { opacity: 0; }
  77.4%, 100% { opacity: 1; }
}

/* dark windows that light up for a while, the tube stuttering as it catches */
@keyframes on-long {
  0%, 38%     { opacity: 0; }
  38.3%       { opacity: .7; }
  38.6%       { opacity: .1; }
  39%, 71%    { opacity: 1; }
  71.4%, 100% { opacity: 0; }
}

/* dark windows that light up twice */
@keyframes on-twice {
  0%, 12%     { opacity: 0; }
  12.4%, 33%  { opacity: 1; }
  33.4%, 61%  { opacity: 0; }
  61.4%, 84%  { opacity: 1; }
  84.4%, 100% { opacity: 0; }
}

/* ---------- the rigs move, the Jogar button calls ----------
   The same rules as the street: only opacity and transform, one animation per element, and a
   flicker never has more than two dark beats in a second. Standing still (reduced motion), each
   rig is its finished picture: the radar caught mid-turn, the day on PC 02, the d20 resting on
   20, one beam across the arena, the whole maze laid with the hero at the way out. */

@media (prefers-reduced-motion: no-preference) {
  /* PC 01: the sweep turns in 4 s and each group of units lights up as the leading line passes
     it (groups a to d sit at 39, 124, 213 and 309 degrees, so each delay is its angle's share of
     4 s, minus 4 s) */
  .glass > .sweep { animation: radar 4s linear infinite; }
  .blips { animation: blip 4s linear infinite; }
  .blips--a { animation-delay: -3.567s; }
  .blips--b { animation-delay: -2.622s; }
  .blips--c { animation-delay: -1.633s; }
  .blips--d { animation-delay: -.567s; }

  /* PC 02 */
  .units { animation: walk 7s ease-in-out infinite alternate; }
  .night { animation: night 29s ease-in-out -4s infinite; }
  .hdd { animation: disk 3.7s steps(1, end) infinite; }

  /* PC 03 */
  .rig--lurex .die { animation: roll 11s ease-out -9.5s infinite; }
  .rig--lurex .turn { animation: turn 9s linear infinite; }

  /* PC 04 */
  .beam--a { animation: shot 5s ease-out -1s infinite; }
  .beam--b { animation: burst 7s ease-out -3.4s infinite; }
  .beam--c { animation: shot 11s ease-out -5.5s infinite; }
  .pads--a { animation: pulse 2.6s ease-in-out infinite; }
  .pads--b { animation: pulse 2.6s ease-in-out -1.3s infinite; }
  .rig--firerange > .haze { animation: drift 19s ease-in-out infinite alternate; }

  /* PC 05: one 17 s game, room by room */
  .maze-room--1 { animation: room-1 17s ease-out infinite; }
  .maze-room--2 { animation: room-2 17s ease-out infinite; }
  .maze-room--3 { animation: room-3 17s ease-out infinite; }
  .maze-room--4 { animation: room-4 17s ease-out infinite; }
  .maze-room--5 { animation: room-5 17s ease-out infinite; }
  .maze-room--6 { animation: room-6 17s ease-out infinite; }
  .maze-room--7 { animation: room-7 17s ease-out infinite; }
  .glass > .player { animation: steps-out 17s ease-in-out infinite; }
  .glass > .new-room { animation: laid 17s linear infinite; }
  .glass > .torch { animation: burn 17s ease-out infinite; }

  /* the Jogar button: the halo breathes and a light sweeps across it */
  .play-slot::before { animation: halo 2.4s ease-in-out infinite; }
  .play::before { animation: shine 4.2s ease-in-out 1.2s infinite; }
}

@keyframes radar {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* a unit lights up under the leading line and fades until the next pass */
@keyframes blip {
  0%, 6% { opacity: 1; }
  60%    { opacity: .22; }
  100%   { opacity: .22; }
}

@keyframes walk {
  from { transform: translate(-3%, -1.5%); }
  to   { transform: translate(4%, 2%); }
}

/* the day turns to night and back */
@keyframes night {
  0%, 28%  { opacity: 0; }
  46%, 78% { opacity: 1; }
  96%      { opacity: 0; }
  100%     { opacity: 0; }
}

/* the hard disk at work: two short reads, a pause, a longer one */
@keyframes disk {
  0%   { opacity: 1; }
  6%   { opacity: .12; }
  12%  { opacity: 1; }
  16%  { opacity: .12; }
  40%  { opacity: 1; }
  44%  { opacity: .12; }
  71%  { opacity: 1; }
  79%  { opacity: .12; }
  100% { opacity: .12; }
}

/* the d20 comes in tumbling, bounces once and rests on 20, then fades for the next throw */
@keyframes roll {
  0%        { opacity: 0; transform: translate(-70%, -40%) rotate(-430deg) scale(.82); }
  2%        { opacity: 1; }
  8%        { transform: translate(7%, 3%) rotate(16deg) scale(1); }
  10%       { transform: translate(-2%, -1%) rotate(-6deg) scale(1); }
  11.5%     { transform: none; }
  92%       { opacity: 1; transform: none; }
  97%, 100% { opacity: 0; transform: none; }
}

@keyframes turn {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* a tagger fires: the beam flashes and fades */
@keyframes shot {
  0%, 100% { opacity: 0; }
  1%       { opacity: 1; }
  5%       { opacity: .85; }
  9%       { opacity: 0; }
}

/* two shots in a row: two dark beats in under a second */
@keyframes burst {
  0%, 100% { opacity: 0; }
  1%       { opacity: 1; }
  3.5%     { opacity: 0; }
  5%       { opacity: 1; }
  9%       { opacity: 0; }
}

@keyframes pulse {
  0%, 100% { opacity: .3; }
  50%      { opacity: 1; }
}

@keyframes drift {
  from { transform: translateX(-4%); }
  to   { transform: translateX(4%); }
}

/* the rooms: each one pops in when the hero reaches the door before it (every 12% of the 17 s,
   from 6%); all fade together at the end and the entrance comes back */
@keyframes room-1 {
  0%, 86%   { opacity: 1; transform: none; }
  90%       { opacity: 0; transform: none; }
  94%       { opacity: 0; transform: scale(.6); }
  97%       { opacity: 1; transform: scale(1.06); }
  98%, 100% { opacity: 1; transform: none; }
}
@keyframes room-2 {
  0%, 6%   { opacity: 0; transform: scale(.6); }
  8%       { opacity: 1; transform: scale(1.06); }
  9%, 86%  { opacity: 1; transform: none; }
  90%, 100% { opacity: 0; transform: none; }
}
@keyframes room-3 {
  0%, 18%  { opacity: 0; transform: scale(.6); }
  20%      { opacity: 1; transform: scale(1.06); }
  21%, 86%  { opacity: 1; transform: none; }
  90%, 100% { opacity: 0; transform: none; }
}
@keyframes room-4 {
  0%, 30%  { opacity: 0; transform: scale(.6); }
  32%      { opacity: 1; transform: scale(1.06); }
  33%, 86%  { opacity: 1; transform: none; }
  90%, 100% { opacity: 0; transform: none; }
}
@keyframes room-5 {
  0%, 42%  { opacity: 0; transform: scale(.6); }
  44%      { opacity: 1; transform: scale(1.06); }
  45%, 86%  { opacity: 1; transform: none; }
  90%, 100% { opacity: 0; transform: none; }
}
@keyframes room-6 {
  0%, 54%  { opacity: 0; transform: scale(.6); }
  56%      { opacity: 1; transform: scale(1.06); }
  57%, 86%  { opacity: 1; transform: none; }
  90%, 100% { opacity: 0; transform: none; }
}
@keyframes room-7 {
  0%, 66%  { opacity: 0; transform: scale(.6); }
  68%      { opacity: 1; transform: scale(1.06); }
  69%, 86%  { opacity: 1; transform: none; }
  90%, 100% { opacity: 0; transform: none; }
}

/* the hero steps into each new room 5% after it is laid, waits at the way out, fades and
   starts again */
@keyframes steps-out {
  0%, 11%   { opacity: 1; transform: translate(0, 0); }
  13%, 23%  { transform: translate(0, -400%); }
  25%, 35%  { transform: translate(400%, -400%); }
  37%, 47%  { transform: translate(400%, -800%); }
  49%, 59%  { transform: translate(400%, -1200%); }
  61%, 71%  { transform: translate(0, -1200%); }
  73%, 86%  { opacity: 1; transform: translate(0, -1600%); }
  90%       { opacity: 0; transform: translate(0, -1600%); }
  93%       { opacity: 0; transform: translate(0, 0); }
  97%, 100% { opacity: 1; transform: translate(0, 0); }
}

/* the outline of the room just laid: it lights up on the room and fades, then moves, unseen,
   to the next one */
@keyframes laid {
  0%, 6%    { opacity: 0; transform: translate(0, -100%); }
  7%        { opacity: 1; transform: translate(0, -100%); }
  12%       { opacity: 0; transform: translate(0, -100%); }
  18%       { opacity: 0; transform: translate(100%, -100%); }
  19%       { opacity: 1; transform: translate(100%, -100%); }
  24%       { opacity: 0; transform: translate(100%, -100%); }
  30%       { opacity: 0; transform: translate(100%, -200%); }
  31%       { opacity: 1; transform: translate(100%, -200%); }
  36%       { opacity: 0; transform: translate(100%, -200%); }
  42%       { opacity: 0; transform: translate(100%, -300%); }
  43%       { opacity: 1; transform: translate(100%, -300%); }
  48%       { opacity: 0; transform: translate(100%, -300%); }
  54%       { opacity: 0; transform: translate(0, -300%); }
  55%       { opacity: 1; transform: translate(0, -300%); }
  60%       { opacity: 0; transform: translate(0, -300%); }
  66%       { opacity: 0; transform: translate(0, -400%); }
  67%       { opacity: 1; transform: translate(0, -400%); }
  72%, 100% { opacity: 0; transform: translate(0, -400%); }
}

/* the torch burns down a step every time the hero moves */
@keyframes burn {
  0%, 12%   { transform: scaleX(1); }
  13%, 24%  { transform: scaleX(.86); }
  25%, 36%  { transform: scaleX(.72); }
  37%, 48%  { transform: scaleX(.58); }
  49%, 60%  { transform: scaleX(.44); }
  61%, 72%  { transform: scaleX(.3); }
  73%, 92%  { transform: scaleX(.16); }
  96%, 100% { transform: scaleX(1); }
}

@keyframes halo {
  0%, 100% { opacity: .35; transform: scale(.92); }
  50%      { opacity: 1; transform: scale(1.06); }
}

/* the sweep crosses in about a second, then waits outside the button */
@keyframes shine {
  0%        { transform: translateX(-110%); }
  24%, 100% { transform: translateX(240%); }
}

/* ---------- no motion when asked ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }
  /* a gameplay video in a TV stands aside, and the still drawing under it shows */
  .glass > .feed { display: none; }
}
