/* Laru Brothers — shared styles for every page.
   Each page sets its own neon pair with --neon-a / --neon-b (see README). */

/* Each font comes in two files. The -ext one holds the Latin Extended letters
   (ą, č, ő, ș, ğ…) that Polish, Czech, Hungarian, Romanian and Turkish need, and
   a browser fetches it only for a page that uses one of them. Where the two
   ranges overlap, the file declared last is asked first.
   Russian, Ukrainian, Greek, Japanese, Korean and Chinese are in neither font,
   and are set in the system's own. */

/* Archivo at its widest (125%) setting, weights 500 to 800. */
@font-face {
  font-family: "Archivo Expanded";
  src: url("/assets/fonts/archivo-expanded-ext.woff2") format("woff2");
  font-weight: 500 800;
  font-display: block;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Archivo Expanded";
  src: url("/assets/fonts/archivo-expanded.woff2") format("woff2");
  font-weight: 500 800;
  font-display: block;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Instrument Sans";
  src: url("/assets/fonts/instrument-sans-ext.woff2") format("woff2");
  font-weight: 400 600;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Instrument Sans";
  src: url("/assets/fonts/instrument-sans.woff2") format("woff2");
  font-weight: 400 600;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --void: #000;
  --ink: #f4f4f4;
  --ash: #8f8f8f;
  --line: #3a3a3a;
  --glass: #262626; /* a neon tube that is switched off */

  /* Monochrome by default; a game page or game card overrides these. */
  --neon-a: #fff;
  --neon-b: #fff;
  --fog-gain: 0.5;

  --display: "Archivo Expanded", system-ui, sans-serif;
  --text: "Instrument Sans", system-ui, sans-serif;
  --gutter: clamp(1.25rem, 5vw, 4.5rem);
  --wide: 82rem;

  /* The navigation is a bar along the bottom on small screens
     and a rail down the left side on wide ones. */
  --dock: 3.5rem;
  --rail: 0rem;

  color-scheme: dark;
}

@media (min-width: 62rem) {
  :root {
    --dock: 0rem;
    --rail: clamp(10.5rem, 15vw, 13.5rem);
  }
}

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

html {
  background: var(--void);
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--void);
  color: var(--ink);
  font: 400 1.0625rem/1.6 var(--text);
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
  border-radius: 2px;
}

::selection {
  background: var(--ink);
  color: var(--void);
}

.skip {
  position: absolute;
  left: var(--gutter);
  top: -4rem;
  z-index: 6;
  padding: 0.6rem 1rem;
  background: var(--ink);
  color: var(--void);
  text-decoration: none;
}

.skip:focus {
  top: 1rem;
}

/* Page content sits in this column, clear of the rail. */
.wrap {
  max-width: var(--wide);
  margin-inline: auto;
  padding-left: var(--rail);
}

/* ---------- Navigation rail ---------- */

.rail {
  position: fixed;
  inset: auto 0 0;
  z-index: 5;
  padding-bottom: env(safe-area-inset-bottom);
  border-top: 1px solid var(--line);
  background: rgb(0 0 0 / 0.82);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  animation: fade-in 1s 0.2s both;
}

.rail__body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  height: var(--dock);
  padding-inline: var(--gutter);
  overflow-x: auto;
  scrollbar-width: none;
}

.rail__body::-webkit-scrollbar {
  display: none;
}

.rail ul {
  display: flex;
  gap: clamp(1rem, 4vw, 1.75rem);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* On the bar, a game sits in line with the sections. */
.rail__games,
.rail__games ul {
  display: contents;
}

.rail a {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  color: var(--ash);
  font: 500 0.8125rem/1 var(--display);
  white-space: nowrap;
  text-decoration: none;
  transition: color 0.2s, text-shadow 0.2s;
}

.rail a:hover,
.rail a[aria-current] {
  color: var(--ink);
}

.rail a[aria-current] {
  text-shadow: 0 0 14px rgb(255 255 255 / 0.7);
}

/* The logo, small. It takes you home. */
.rail__home {
  flex: none;
}

.rail__home svg {
  display: block;
  width: 1.375rem;
  height: auto;
  fill: currentColor;
}

/* A game's button wears that game's colours. */
.rail__game span {
  background-image: linear-gradient(90deg, var(--neon-a) 30%, var(--neon-b) 70%);
  background-image: linear-gradient(90deg in oklab, var(--neon-a) 30%, var(--neon-b) 70%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: saturate(0.75) brightness(0.8);
  transition: filter 0.2s;
}

.rail__game:hover span,
.rail__game[aria-current] span {
  filter: none;
}

.rail a.rail__game[aria-current] {
  text-shadow: none;
}

@media (min-width: 62rem) {
  /* The rail floats over the left column, level with the middle of the window. */
  .rail {
    inset: 0;
    display: grid;
    align-items: center;
    padding: 0 var(--gutter);
    border: 0;
    background: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    pointer-events: none;
  }

  .rail__body {
    display: block;
    width: 100%;
    max-width: var(--wide);
    height: auto;
    margin-inline: auto;
    padding: 0;
    overflow: visible;
  }

  .rail__body > * {
    width: fit-content;
    pointer-events: auto;
  }

  .rail ul {
    display: block;
  }

  .rail__games,
  .rail__games ul {
    display: block;
  }

  .rail a {
    padding-block: 0.55rem;
    font-size: 0.875rem;
  }

  /* Each link has a short tube beside it that lights when you are there. */
  .rail li > a::before {
    content: "";
    flex: none;
    width: 2px;
    height: 1.15rem;
    margin-block: -0.2rem;
    border-radius: 1px;
    background: var(--glass);
    transition: background-color 0.2s, box-shadow 0.2s, opacity 0.2s;
  }

  .rail li > a:hover::before,
  .rail li > a[aria-current]::before {
    background: var(--ink);
    box-shadow: 0 0 6px rgb(255 255 255 / 0.9), 0 0 16px rgb(255 255 255 / 0.5);
  }

  .rail__games ul a {
    gap: 1.6rem;
  }

  .rail li > a.rail__game::before {
    background: linear-gradient(var(--neon-a), var(--neon-b));
    opacity: 0.4;
  }

  .rail li > a.rail__game:hover::before,
  .rail li > a.rail__game[aria-current]::before {
    background: linear-gradient(var(--neon-a), var(--neon-b));
    box-shadow: 0 -5px 12px var(--neon-a), 0 5px 12px var(--neon-b);
    opacity: 1;
  }

  .rail__home {
    margin: 0 0 1.5rem -0.125rem;
    padding-block: 0;
  }

  .rail__home svg {
    width: 2.5rem;
  }
}

/* ---------- Language picker ---------- */

/* A small tube in the top corner of every page, level with the right edge of
   the content, in the page's two colours. It burns low until it is pointed at.
   i18n.js builds it. */
.lang {
  position: absolute;
  top: max(1.25rem, env(safe-area-inset-top));
  right: max(var(--gutter), (100% - var(--wide)) / 2);
  z-index: 4;
  display: grid;
  border-radius: 999px;
  color: var(--ash);
  font: 500 0.75rem/1.2 var(--display);
  transition: color 0.25s;
  animation: fade-in 1s 0.2s both;
}

/* The tube, and the little light it throws. Only its brightness ever changes. */
.lang::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid transparent;
  border-radius: inherit;
  background: linear-gradient(var(--void), var(--void)) padding-box,
    linear-gradient(90deg, var(--neon-a), var(--neon-b)) border-box;
  box-shadow: -8px 0 18px -10px var(--neon-a), 8px 0 18px -10px var(--neon-b);
  opacity: 0.5;
  transition: opacity 0.25s;
}

.lang::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 1.25em;
  width: 0.4em;
  height: 0.4em;
  border: solid currentColor;
  border-width: 0 1.5px 1.5px 0;
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}

.lang select {
  position: relative;
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
  padding: 0.75em 2.75em 0.75em 1.25em;
  border: 0;
  border-radius: inherit;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

/* Where the list of languages is the system's own, it is at least dark. */
.lang option {
  background: #0b0b0b;
  color: var(--ink);
}

.lang:hover,
.lang:has(:focus-visible) {
  color: var(--ink);
}

.lang:hover::before,
.lang:has(:focus-visible)::before {
  opacity: 1;
}

/* Kept apart from the rule above: not every browser knows :open. */
.lang:has(select:open) {
  color: var(--ink);
}

.lang:has(select:open)::before {
  opacity: 1;
}

/* Where a browser lets the list itself be styled, the list is a sign too: the
   languages in two columns of twelve, hung under the tube, the current one lit. */
@supports (appearance: base-select) {
  .lang select,
  .lang select::picker(select) {
    appearance: base-select;
  }

  .lang select::picker-icon {
    display: none;
  }

  .lang select::picker(select) {
    position-area: block-end span-inline-start;
    margin-top: 0.5rem;
    padding: 0.375rem;
    border: 1px solid transparent;
    border-radius: 6px;
    background: linear-gradient(#050505, #050505) padding-box,
      linear-gradient(90deg, var(--neon-a), var(--neon-b)) border-box;
    box-shadow: -14px 0 40px -18px var(--neon-a), 14px 0 40px -18px var(--neon-b),
      0 1.5rem 3rem var(--void);
  }

  .lang select:open::picker(select) {
    display: grid;
    grid-template-rows: repeat(12, auto);
    grid-auto-flow: column;
    column-gap: 0.25rem;
  }

  .lang option {
    padding: 0.7em 0.9em;
    border-radius: 4px;
    background: none;
    color: var(--ash);
    transition: color 0.2s, background-color 0.2s;
  }

  .lang option::checkmark {
    display: none;
  }

  .lang option:hover,
  .lang option:focus-visible {
    background: #161616;
    color: var(--ink);
  }

  .lang option:focus-visible {
    outline: 1px solid var(--line);
    outline-offset: -1px;
  }

  .lang option:checked {
    color: var(--ink);
    text-shadow: 0 0 14px rgb(255 255 255 / 0.7);
  }
}

/* Korean breaks its lines between words, and Japanese between phrases where the
   browser can tell them apart. Their characters, and Chinese ones, stand taller
   than Latin lower case, and need more room between the lines of a large sentence. */
:lang(ko) {
  word-break: keep-all;
}

:lang(ja) {
  word-break: auto-phrase;
}

:is(:lang(ja), :lang(ko), :lang(zh)) .hero__statement {
  line-height: 1.35;
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  isolation: isolate;
  display: grid;
  align-items: center;
  min-height: 100svh;
  padding: 4rem var(--gutter) calc(4.5rem + var(--dock));
  overflow: hidden;
}

.hero--game {
  min-height: 88svh;
}

.hero > .wrap {
  width: 100%;
}

.hero__inner {
  container-type: inline-size;
}

.hero__lede {
  max-width: 31rem;
  margin: clamp(1.5rem, 3vw, 2.5rem) 0 0;
  color: #c2c2c2;
  font-size: 1.1875rem;
  line-height: 1.5;
  text-shadow: 0 0 4px var(--void), 0 0 14px var(--void);
  animation: fade-in 1s 1.5s both;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.75rem;
  margin: 2rem 0 0;
  animation: fade-in 1s 1.7s both;
}

.hero--game .hero__lede {
  animation-delay: 0.3s;
}

.hero--game .hero__actions {
  animation-delay: 0.5s;
}

/* A game that is out says so above its title: one lit pixel beside the words,
   steady, in the game's first colour. */
.hero__status {
  display: flex;
  align-items: center;
  gap: 0.7em;
  margin: 0 0 clamp(1rem, 2vw, 1.5rem);
  color: var(--ink);
  font: 500 0.875rem/1.3 var(--display);
  text-shadow: 0 0 4px var(--void), 0 0 14px var(--void);
  animation: fade-in 1s 0.3s both;
}

.hero__lamp {
  flex: none;
  width: 0.625em;
  height: 0.625em;
  background: var(--neon-a);
  box-shadow: 0 0 3px var(--neon-a), 0 0 10px var(--neon-a), 0 0 24px var(--neon-a);
}

/* The buy button and its price stay side by side when the row wraps. */
.hero__buy {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
}

.hero__price {
  color: var(--ink);
  font: 500 1rem/1 var(--display);
  text-shadow: 0 0 4px var(--void), 0 0 14px var(--void);
}

.hero__note {
  margin: 1rem 0 0;
  color: #ababab;
  font-size: 0.9375rem;
  text-shadow: 0 0 4px var(--void), 0 0 14px var(--void);
  animation: fade-in 1s 0.5s both;
}

/* The home hero: the studio's sign, and beside it a column as tall as the sign,
   with who we are at the top and the newest game's own sign at the bottom.
   Everything here is sized from --sign, the width of the big sign's lettering:
   as wide as the window allows, and never taller than it. */
.hero__sign {
  --sign: min(24rem, 66vw, (100svh - 14rem - var(--dock)) * 0.5);
  --tube: max(1.5px, var(--sign) * 0.008);
  display: grid;
  gap: clamp(1.75rem, 4vw, 4rem);
}

.hero__side {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: clamp(1.5rem, var(--sign) * 0.1, 2.5rem);
  min-width: 0;
}

.hero__statement {
  max-width: 40rem;
  margin: 0;
  font: 500 clamp(1.25rem, var(--sign) * 0.085, 2rem) / 1.16 var(--display);
  text-wrap: balance;
  text-shadow: 0 0 4px var(--void), 0 0 14px var(--void);
  animation: fade-in 1s 1.5s both;
}

@media (min-width: 62rem) {
  .hero__sign {
    grid-template-columns: auto minmax(0, 1fr);
  }

  /* Larger beside the sign, and pulled up so the capitals of its first line
     sit level with the sign's top edge. */
  .hero__statement {
    margin-top: -0.19em;
    font-size: clamp(1.375rem, var(--sign) * 0.125, 3rem);
  }
}

/* The dithered fog. site.js sizes the canvas and draws into it. It is pinned to
   the window, so its pixels hold still while the page scrolls over them. */
.fog {
  position: fixed;
  top: 0;
  left: 0;
  z-index: -1;
  image-rendering: pixelated;
  animation: fade-in 2s 0.1s both;
}

.no-gl .hero {
  background: radial-gradient(120% 55% at 50% 108%, #2b2b2b, transparent 70%);
}

/* ---------- The neon sign (studio logo) ---------- */

.sign {
  position: relative;
  align-self: center;
  width: calc(var(--sign) * 1.24);
  margin: 0;
  padding: calc(var(--sign) * 0.12);
  /* The black backing ends at the border tube; nothing shows outside it. */
  border-radius: calc(var(--sign) * 0.035);
  background: radial-gradient(closest-side, #0b0b0b, #020202);
}

.sign__logo {
  position: relative;
  display: block;
  aspect-ratio: 590 / 888;
}

.sign svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: none;
  stroke-width: 5.5;
  stroke-linejoin: round;
}

/* The glass tubes, visible whenever the light dips. */
.sign__glass {
  stroke: var(--glass);
}

/* BROTHERS is too fine to be an outline: its letters are solid tube, through and through. */
.sign__glass use:last-child {
  fill: var(--glass);
}

.sign__lit {
  stroke: var(--ink);
  filter: drop-shadow(0 0 calc(var(--sign) * 0.006) rgb(255 255 255 / 0.9))
    drop-shadow(0 0 calc(var(--sign) * 0.035) rgb(255 255 255 / 0.4))
    drop-shadow(0 0 calc(var(--sign) * 0.16) rgb(255 255 255 / 0.22));
  animation: tube-on 1.5s linear both, tube-hum 13s 4s linear infinite;
}

.sign__lit:nth-of-type(3) {
  animation-delay: 0.4s, 7s;
}

.sign .sign__lit--small {
  fill: var(--ink);
  animation-delay: 1s, 10.5s;
}

/* The border tube around the lettering. */
.sign::before {
  content: "";
  position: absolute;
  inset: 0;
  border: var(--tube) solid var(--ink);
  border-radius: inherit;
  box-shadow: 0 0 calc(var(--sign) * 0.02) rgb(255 255 255 / 0.55),
    inset 0 0 calc(var(--sign) * 0.02) rgb(255 255 255 / 0.55),
    0 0 calc(var(--sign) * 0.12) rgb(255 255 255 / 0.2),
    inset 0 0 calc(var(--sign) * 0.12) rgb(255 255 255 / 0.14);
  animation: tube-on 1.5s 1.3s linear both;
}

/* ---------- The marquee (a game's sign in the home hero) ---------- */

/* The newest game hangs beside the studio's sign on a sign of its own, in its own
   two colours. As on the big sign, the glass is always there and the light
   strikes on over it. The whole sign is the link.
   It is only hung where there is room beside the big sign. On a narrower screen
   the hero is the sign and the statement, and the game's card comes right after. */
.marquee {
  position: relative;
  isolation: isolate;
  container-type: inline-size;
  display: none;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: 0.9rem 1.75rem;
  /* Never so wide that it outweighs the big sign. */
  max-width: calc(var(--sign) * 2.5);
  padding: clamp(1.125rem, var(--sign) * 0.085, 2.25rem);
  border-radius: calc(var(--sign) * 0.035);
  text-decoration: none;
}

@media (min-width: 62rem) {
  .marquee {
    display: flex;
  }
}

/* The light the sign throws on the wall behind it. */
.marquee::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -3;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--neon-a), var(--neon-b));
  background: linear-gradient(90deg in oklab, var(--neon-a), var(--neon-b));
  filter: blur(calc(var(--sign) * 0.07)) opacity(0.4);
  transition: filter 0.35s;
  animation: tube-on 1.5s 1.9s linear backwards;
}

/* The black backing, and the border tube's glass. */
.marquee::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  border: var(--tube) solid var(--glass);
  border-radius: inherit;
  background: radial-gradient(closest-side, #0b0b0b, #020202);
}

/* The border tube, lit, and the light it throws inwards. */
.marquee__tube {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  border: var(--tube) solid transparent;
  border-radius: inherit;
  background: radial-gradient(closest-side, #0b0b0b, #020202) padding-box,
    linear-gradient(90deg, var(--neon-a), var(--neon-b)) border-box;
  background: radial-gradient(closest-side, #0b0b0b, #020202) padding-box,
    linear-gradient(90deg in oklab, var(--neon-a), var(--neon-b)) border-box;
  animation: tube-on 1.5s 1.9s linear backwards;
}

.marquee__tube::before {
  content: "";
  position: absolute;
  inset: calc(var(--sign) * -0.02);
  border: calc(var(--sign) * 0.03) solid;
  border-image: linear-gradient(90deg, var(--neon-a), var(--neon-b)) 1;
  border-image: linear-gradient(90deg in oklab, var(--neon-a), var(--neon-b)) 1;
  filter: blur(calc(var(--sign) * 0.03));
  opacity: 0.5;
  transition: opacity 0.35s;
}

.marquee .title {
  flex: 0 0 100%;
  /* Sized so that a name of ten letters fills the sign from edge to edge. */
  font-size: calc(100cqi / 8.5);
}

/* Here the lettering itself is the glass; ::after is the same lettering lit,
   and ::before is its glow. */
.marquee .neon {
  background-image: none;
  color: var(--glass);
}

.marquee .neon::before,
.marquee .neon::after {
  background-image: linear-gradient(90deg, var(--neon-a) 38%, var(--neon-b) 62%);
  background-image: linear-gradient(90deg in oklab, var(--neon-a) 38%, var(--neon-b) 62%);
  color: transparent;
  animation: tube-on 1.5s 2.2s linear backwards;
}

.marquee .neon::before {
  opacity: 1;
  transition: filter 0.35s;
}

.marquee .neon::after {
  content: attr(data-text);
  content: attr(data-text) / "";
  position: absolute;
  inset: 0;
  -webkit-background-clip: text;
  background-clip: text;
}

.marquee__blurb {
  flex: 1 1 14rem;
  max-width: 24rem;
  color: #d0d0d0;
  font-size: 1rem;
  line-height: 1.45;
}

.marquee__blurb,
.marquee .btn {
  animation: fade-in 1s 2.5s both;
}

.marquee .btn {
  flex: none;
}

.marquee:hover::before,
.marquee:focus-visible::before {
  filter: blur(calc(var(--sign) * 0.07)) opacity(0.75);
}

.marquee:hover .marquee__tube::before,
.marquee:focus-visible .marquee__tube::before {
  opacity: 1;
}

.marquee:hover .neon::before,
.marquee:focus-visible .neon::before {
  filter: blur(0.26em);
}

/* ---------- Neon tube lettering (404) ---------- */

.tube {
  margin: 0;
  font: 800 clamp(2.25rem, 14cqi, 12.5rem) / 0.96 var(--display);
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.tube__line {
  display: block;
  width: fit-content;
  color: var(--void);
  -webkit-text-stroke: max(1.5px, 0.016em) var(--ink);
  paint-order: stroke fill;
  filter: drop-shadow(0 0 0.015em rgb(255 255 255 / 0.9))
    drop-shadow(0 0 0.09em rgb(255 255 255 / 0.4))
    drop-shadow(0 0 0.4em rgb(255 255 255 / 0.22));
  animation: tube-on 1.5s linear both, tube-hum 13s 4s linear infinite;
}

/* ---------- Neon colour lettering (game titles) ---------- */

.title {
  isolation: isolate;
  margin: 0;
  font: 800 clamp(2rem, 10.6cqi, 11rem) / 1 var(--display);
  letter-spacing: 0;
  text-transform: uppercase;
}

.neon {
  position: relative;
  display: inline-block;
  background-image: linear-gradient(90deg, var(--neon-a) 38%, var(--neon-b) 62%);
  background-image: linear-gradient(90deg in oklab, var(--neon-a) 38%, var(--neon-b) 62%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* A blurred copy of the same gradient text sits behind as the glow. */
.neon::before {
  content: attr(data-text);
  content: attr(data-text) / "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: inherit;
  -webkit-background-clip: text;
  background-clip: text;
  filter: blur(0.16em);
  opacity: 0.8;
}

/* ---------- Bands (the sections below a hero) ---------- */

/* A hairline this dark smears to nothing on a moving page, so each band also
   carries a faint wash of light under its top edge. The wash has area, and
   stays readable while the page scrolls. */
.band {
  position: relative;
  padding: clamp(3.5rem, 8vw, 6.5rem) var(--gutter);
  border-top: 2px solid var(--line);
  background: linear-gradient(#111, var(--void) 7rem) var(--void);
}

.band--slim {
  padding-block: clamp(2.25rem, 4vw, 3.25rem);
}

.band h2 {
  margin: 0 0 clamp(1.5rem, 3vw, 2.25rem);
  color: var(--ash);
  font: 500 0.9375rem/1.3 var(--display);
}

.band p {
  max-width: 36rem;
  margin: 0 0 1em;
}

.band p:last-child {
  margin-bottom: 0;
}

.band .statement {
  max-width: 44rem;
  font-size: clamp(1.25rem, 2.2vw, 1.625rem);
  line-height: 1.4;
}

.quiet {
  color: var(--ash);
}

/* ---------- Game cards on the home page ---------- */

.games {
  container-type: inline-size;
}

/* The whole card is the link. Its trailer loops behind the title. */
.game {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: 1fr auto;
  align-content: end;
  align-items: end;
  gap: 0.9rem 2rem;
  min-height: clamp(21rem, 48cqi, 31rem);
  margin-bottom: 1.5rem;
  padding: clamp(1.25rem, 3.6cqi, 2.75rem);
  overflow: hidden;
  border: 1px solid transparent;
  border-radius: 6px;
  background: linear-gradient(var(--void), var(--void)) padding-box,
    linear-gradient(90deg, var(--neon-a), var(--neon-b)) border-box;
  text-decoration: none;
  transition: box-shadow 0.35s;
}

.game:hover,
.game:focus-visible {
  box-shadow: -22px 0 48px -22px var(--neon-a), 22px 0 48px -22px var(--neon-b);
}

.game__reel {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.6;
  transition: opacity 0.35s;
}

.game:hover .game__reel,
.game:focus-visible .game__reel {
  opacity: 0.95;
}

/* A card with a still image instead of a loop: the picture drifts slowly, so the
   card is never quite still either. */
img.game__reel {
  animation: drift 26s ease-in-out infinite alternate;
}

@keyframes drift {
  from {
    transform: scale(1.04) translate(-1%, 0.6%);
  }
  to {
    transform: scale(1.12) translate(1.2%, -1.2%);
  }
}

/* Darkens the trailer where the words sit. */
.game::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.55) 45%, rgb(0 0 0 / 0.94));
}

/* A dark loop: shown at full strength, brightened, and only shaded low down
   where the words sit. */
.game--bright .game__reel {
  opacity: 1;
  filter: brightness(1.5) saturate(1.15);
  transition: filter 0.35s;
}

.game--bright:hover .game__reel,
.game--bright:focus-visible .game__reel {
  filter: brightness(1.75) saturate(1.2);
}

.game--bright::before {
  background: linear-gradient(transparent, rgb(0 0 0 / 0.15) 50%, rgb(0 0 0 / 0.85));
}

.game .title,
.game__blurb {
  grid-column: 1 / -1;
}

.game .title {
  font-size: clamp(1.75rem, 10.3cqi, 9rem);
}

.game .neon::before {
  transition: opacity 0.35s, filter 0.35s;
}

.game:hover .neon::before,
.game:focus-visible .neon::before {
  filter: blur(0.26em);
  opacity: 1;
}

.game__blurb {
  max-width: 34rem;
  color: #d0d0d0;
}

.game__meta {
  color: var(--ash);
  font-size: 0.9375rem;
}

/* ---------- Buttons and links ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  padding: 1em 1.8em;
  border: 1px solid var(--ink);
  border-radius: 999px;
  font: 500 0.875rem/1 var(--display);
  text-decoration: none;
  transition: background-color 0.25s, color 0.25s, box-shadow 0.25s;
}

.btn:hover {
  background-color: var(--ink);
  color: var(--void);
  box-shadow: 0 0 22px rgb(255 255 255 / 0.45), 0 0 70px rgb(255 255 255 / 0.2);
}

/* The button is always filled with its gradient. A black inset shadow covers the
   fill and fades away on hover, so the fill and the label change together. */
.btn--neon {
  border-color: transparent;
  background: linear-gradient(90deg, var(--neon-a), var(--neon-b)) border-box;
  box-shadow: inset 0 0 0 3em var(--void), -10px 0 26px -12px var(--neon-a),
    10px 0 26px -12px var(--neon-b);
}

/* A card, a marquee or a trailer lights its button when any part of it is hovered. */
.btn--neon:hover,
.game:hover .btn--neon,
.game:focus-visible .btn--neon,
.marquee:hover .btn--neon,
.marquee:focus-visible .btn--neon,
.trailer:hover .btn--neon {
  background: linear-gradient(90deg, var(--neon-a), var(--neon-b)) border-box;
  color: var(--void);
  box-shadow: inset 0 0 0 3em transparent, -14px 0 40px -8px var(--neon-a),
    14px 0 40px -8px var(--neon-b);
}

.biglink {
  font: 500 clamp(1.125rem, 2.6vw, 1.75rem) / 1.3 var(--display);
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  overflow-wrap: anywhere;
  transition: text-decoration-color 0.25s, text-shadow 0.25s;
}

.biglink:hover {
  text-decoration-color: var(--ink);
  text-shadow: 0 0 18px rgb(255 255 255 / 0.6);
}

.link {
  text-decoration: underline;
  text-decoration-color: #5c5c5c;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  transition: text-decoration-color 0.25s, text-shadow 0.25s;
}

.link:hover {
  text-decoration-color: var(--ink);
  text-shadow: 0 0 14px rgb(255 255 255 / 0.6);
}

/* ---------- The two brothers ---------- */

/* One sign, cut in two by a leaning tube, with a brother on each side.
   --lean is how far the tube's ends sit from the middle, as a percentage of the
   sign: of its width while the brothers are side by side, of its height once
   they are stacked. site.js reads it too, to light the fog along the same line. */
.crew {
  --lean: 6;
  --hi: calc(50% + var(--lean) * 1%);
  --lo: calc(50% - var(--lean) * 1%);
  /* One pixel of a portrait. site.js rounds this to whole device pixels. */
  --cell: clamp(4px, 0.8cqi, 9px);
  isolation: isolate;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  border-radius: 6px;
  background: var(--void);
  /* Everything is cut to the sign's outline, the fog canvas included. */
  clip-path: inset(0 round 6px);
}

.no-gl .crew {
  background: radial-gradient(90% 60% at 50% 108%, #2b2b2b, transparent 70%) var(--void);
}

/* The fog. Like the hero's, this canvas is pinned to the window, so its pixels
   hold still while the page scrolls; the sign is an opening onto it. For that to
   work, nothing from .crew up may be transformed, filtered or made a container.
   site.js sizes the canvas and draws into it. */
.crew__fog {
  position: fixed;
  top: 0;
  left: 0;
  z-index: -1;
  image-rendering: pixelated;
}

.crew__sign {
  position: relative;
  display: grid;
  container-type: inline-size;
  border: 1px solid var(--line);
  border-radius: inherit;
}

/* Both brothers fill the whole sign and are clipped to their own side of the
   tube, so pointing at a side means pointing at that brother. */
.dev {
  position: relative;
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-between;
  gap: clamp(1rem, 3cqi, 2rem);
  margin: 0;
  padding: clamp(1.25rem, 3.6cqi, 2.75rem) clamp(1.25rem, 3.6cqi, 2.75rem) 0;
  clip-path: polygon(0 0, var(--hi) 0, var(--lo) 100%, 0 100%);
}

.dev + .dev {
  align-items: flex-end;
  text-align: right;
  clip-path: polygon(var(--hi) 0, 100% 0, 100% 100%, var(--lo) 100%);
}

/* A shade over a brother's fog, drawn when he is switched off. */
.dev::before {
  content: "";
  position: absolute;
  inset: -10% 0;
  z-index: -1;
  background: var(--void);
  opacity: 0;
  transition: opacity 0.35s;
}

.dev figcaption {
  color: var(--ash);
  font-size: 0.9375rem;
  line-height: 1.4;
  text-shadow: 0 0 4px var(--void), 0 0 14px var(--void);
  transition: color 0.35s;
}

/* A name is a tube of its own: the glass is always there, and ::after is the
   same lettering lit. */
.dev__name {
  position: relative;
  display: block;
  width: fit-content;
  margin-bottom: 0.2em;
  color: var(--void);
  font: 800 clamp(1.75rem, 5.6cqi, 3.75rem) / 1 var(--display);
  letter-spacing: 0.01em;
  text-shadow: none;
  text-transform: uppercase;
  -webkit-text-stroke: max(3px, 0.06em) var(--glass);
  paint-order: stroke fill;
}

.dev + .dev .dev__name {
  margin-left: auto;
}

.dev__name::after {
  content: attr(data-text);
  content: attr(data-text) / "";
  position: absolute;
  inset: 0;
  -webkit-text-stroke-color: var(--ink);
  filter: drop-shadow(0 0 0.02em rgb(255 255 255 / 0.9))
    drop-shadow(0 0 0.14em rgb(255 255 255 / 0.4))
    drop-shadow(0 0 0.6em rgb(255 255 255 / 0.22));
  transition: opacity 0.35s;
  animation: tube-on 1.5s 0.35s linear backwards;
}

.dev + .dev .dev__name::after {
  animation-delay: 0.7s;
}

/* The portraits are real pixel art, drawn one image pixel to a cell. */
.dev__face {
  flex: none;
  display: block;
  width: calc(42 * var(--cell));
  height: auto;
  image-rendering: pixelated;
  /* A face is part of the sign: it cannot be selected or picked up and dragged. */
  -webkit-user-drag: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  filter: brightness(1) saturate(1);
  transition: filter 0.35s;
  /* A face is lit by the name above it, and strikes on with it. */
  animation: face-on 1.5s 0.35s linear backwards;
}

.dev + .dev .dev__face {
  animation-delay: 0.7s;
}

/* The tube between them: glass underneath, the lit tube and its glow in <i>. */
.crew__tube,
.crew__tube i,
.crew__tube::before,
.crew__tube i::before {
  position: absolute;
  inset: 0;
}

.crew__tube {
  pointer-events: none;
}

.crew__tube::before,
.crew__tube i::before {
  content: "";
  background: var(--glass);
  clip-path: polygon(calc(var(--hi) - 1.5px) 0, calc(var(--hi) + 1.5px) 0,
    calc(var(--lo) + 1.5px) 100%, calc(var(--lo) - 1.5px) 100%);
}

.crew__tube i {
  filter: drop-shadow(0 0 2px rgb(255 255 255 / 0.9))
    drop-shadow(0 0 12px rgb(255 255 255 / 0.4))
    drop-shadow(0 0 44px rgb(255 255 255 / 0.22));
  animation: tube-on 1.5s linear backwards, tube-hum 13s 6s linear infinite;
}

.crew__tube i::before {
  background: var(--ink);
}

/* Switched off. site.js keeps the whole sign off until it scrolls into view,
   and dims one brother while the pointer is on the other. Coming back from a
   dim is a plain fade; only the first switch-on strikes. */
.crew--off .dev__name::after,
.crew--off .crew__tube i {
  opacity: 0;
  animation: none;
}

.dev--dim .dev__name::after {
  opacity: 0;
}

.dev--dim::before {
  opacity: 0.7;
}

.crew--off .dev__face,
.dev--dim .dev__face {
  filter: brightness(0.3) saturate(0.4);
}

.crew--off .dev__face {
  animation: none;
}

.crew--off figcaption,
.dev--dim figcaption {
  color: #5c5c5c;
}

/* ---------- Game page details ---------- */

.facts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5rem 2rem;
  margin: 0;
}

.facts dt {
  color: var(--ash);
  font-size: 0.875rem;
}

.facts dd {
  margin: 0.3rem 0 0;
  font: 500 1rem/1.35 var(--display);
}

/* The trailer is a link to YouTube; site.js swaps it for the player in place. */
.trailer {
  position: relative;
  display: block;
  width: 100%;
  max-width: 60rem;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border: 0;
  border-radius: 6px;
  background: #050505;
}

.trailer img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.8;
  transition: opacity 0.3s;
}

.trailer:hover img {
  opacity: 1;
}

.trailer__play {
  position: absolute;
  inset: auto auto clamp(1rem, 4%, 2rem) clamp(1rem, 4%, 2rem);
}

/* A piece of art shown in place of a trailer, framed by a hairline in the game's
   two colours that glows when pointed at, like a card. */
.art {
  max-width: 60rem;
  margin: 0;
}

.art img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid transparent;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--neon-a), var(--neon-b)) border-box;
  transition: box-shadow 0.35s;
}

.art img:hover {
  box-shadow: -22px 0 48px -22px var(--neon-a), 22px 0 48px -22px var(--neon-b);
}

.art figcaption {
  margin-top: 0.85rem;
  color: var(--ash);
  font-size: 0.875rem;
}

.shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
}

.shots img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 6px;
}

/* ---------- Legal pages ---------- */

/* A long document, set in the same narrow column as the rest of the site's
   text, with each numbered section under a hairline of its own. */
.legal {
  max-width: 36rem;
  overflow-wrap: break-word;
}

.legal h3 {
  margin: clamp(2.5rem, 5vw, 3.5rem) 0 1.25rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font: 500 1.125rem/1.3 var(--display);
}

.legal h4 {
  margin: 2em 0 1em;
  color: var(--ash);
  font: 500 0.9375rem/1.3 var(--display);
}

.legal ul {
  margin: 0 0 1em;
  padding-left: 1.25rem;
}

.legal li {
  margin-bottom: 0.5em;
}

.legal li::marker {
  color: var(--ash);
}

.legal strong {
  font-weight: 600;
}

/* A lettered clause hangs from its letter. */
.legal__clause {
  padding-left: 2em;
  text-indent: -2em;
}

/* ---------- Footer ---------- */

.foot {
  position: relative;
  padding: 2rem var(--gutter) calc(2rem + var(--dock));
  border-top: 2px solid var(--line);
  background: var(--void);
  color: var(--ash);
  font-size: 0.875rem;
}

.foot .wrap {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem 2rem;
}

.foot a {
  text-decoration: none;
  transition: color 0.2s;
}

.foot a:hover {
  color: var(--ink);
}

/* ---------- Motion ---------- */

@keyframes fade-in {
  from {
    opacity: 0;
  }
}

/* A tube striking: a few stutters, then steady. */
@keyframes tube-on {
  0% { opacity: 0; }
  7% { opacity: 0.85; }
  9% { opacity: 0.08; }
  19% { opacity: 0.08; }
  21% { opacity: 1; }
  25% { opacity: 0.3; }
  31% { opacity: 1; }
  44% { opacity: 1; }
  46% { opacity: 0.55; }
  49%, 100% { opacity: 1; }
}

/* The same strike, as seen on a face the tube is lighting. */
@keyframes face-on {
  0%, 9%, 19% { filter: brightness(0.3) saturate(0.4); }
  7% { filter: brightness(0.9) saturate(0.9); }
  21% { filter: brightness(1) saturate(1); }
  25% { filter: brightness(0.5) saturate(0.6); }
  31%, 44% { filter: brightness(1) saturate(1); }
  46% { filter: brightness(0.7) saturate(0.75); }
  49%, 100% { filter: brightness(1) saturate(1); }
}

/* The occasional dip of a tube that is already lit. */
@keyframes tube-hum {
  0%, 96.4%, 100% { opacity: 1; }
  96.8% { opacity: 0.72; }
  97.3% { opacity: 1; }
  97.8% { opacity: 0.86; }
  98.2% { opacity: 1; }
}

@keyframes hero-out {
  to {
    opacity: 0;
    filter: blur(14px);
    transform: translateY(-7vh);
  }
}

@keyframes light-up {
  from {
    filter: grayscale(1) brightness(0.4);
  }
}

@media (prefers-reduced-motion: no-preference) {
  /* Pages cross-fade into each other, a game title travels from its card
     on the home page to the top of its own page, and the rail stays put. */
  @view-transition {
    navigation: auto;
  }

  .rail {
    view-transition-name: rail;
  }

  .lang {
    view-transition-name: lang;
  }

  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0.45s;
  }

  ::view-transition-group(*) {
    animation-duration: 0.65s;
    animation-timing-function: cubic-bezier(0.2, 0.7, 0.1, 1);
  }

  @supports (animation-timeline: scroll()) {
    /* The hero dissolves as it scrolls away. */
    .hero__inner {
      animation: hero-out linear both;
      animation-timeline: scroll(root);
      animation-range: 0 85vh;
    }

    /* On the home page the small logo waits until the sign has gone. */
    .rail__home--late {
      animation: fade-in linear both;
      animation-timeline: scroll(root);
      animation-range: 45vh 90vh;
    }

    /* A game title powers on as its card scrolls into view. */
    .game .title {
      animation: light-up linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 32%;
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* ---------- Small screens ---------- */

@media (max-width: 46rem) {
  .facts {
    grid-template-columns: repeat(2, 1fr);
  }

  .game {
    grid-template-columns: 1fr;
    justify-items: start;
  }
}

/* On a phone the brothers stack, and the tube leans across the sign between them. */
@media (max-width: 36rem) {
  .crew {
    --lean: 3;
    --cell: clamp(4px, 1.8cqi, 7px);
  }

  .crew__sign {
    grid-template-rows: 1fr 1fr;
  }

  .dev {
    grid-area: auto;
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--lean) * 2%), 0 calc(100% + var(--lean) * 2%));
  }

  .dev + .dev {
    padding-top: clamp(1.75rem, 9cqi, 3rem);
    clip-path: polygon(0 calc(var(--lean) * 2%), 100% calc(var(--lean) * -2%), 100% 100%, 0 100%);
  }

  .dev__name {
    font-size: clamp(1.75rem, 11cqi, 3rem);
  }

  /* The top portrait hangs past its own half, down to the tube. */
  .dev__face {
    margin-bottom: calc(var(--cell) * -4);
  }

  .dev + .dev .dev__face {
    margin-bottom: 0;
  }

  .crew__tube::before,
  .crew__tube i::before {
    clip-path: polygon(0 calc(var(--hi) - 1.5px), 100% calc(var(--lo) - 1.5px),
      100% calc(var(--lo) + 1.5px), 0 calc(var(--hi) + 1.5px));
  }
}
