/* ===============================================================
   Luke No Further
   Black and white, nothing else.
   =============================================================== */

:root {
  --bg:   #000;
  --fg:   #fff;
  --dim:  #9a9a9a;
  --dimmer: #6a6a6a;
  --line: rgba(255, 255, 255, .16);
  --line-strong: rgba(255, 255, 255, .32);

  --wrap: 1040px;
  --gap: 28px;
  --tile-inset: 12px;      /* emoji offset, and the text indent that matches it */

  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Helvetica,
          "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; display: block; }

a { color: var(--fg); }

a:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 3px;
}

/* ---------------------------------------------------------------
   Game of Life field, sitting behind everything
   --------------------------------------------------------------- */

#life {
  position: fixed;
  inset: 0;
  z-index: 0;
  display: block;
  pointer-events: none;
}

.page {
  position: relative;
  z-index: 1;
}

/* ---------------------------------------------------------------
   Splash — first visit of a session only.

   There is deliberately no text in here: the name is stamped into
   the Game of Life field behind it, in live cells, and .splash__word
   is an empty box whose only job is to tell the canvas where to put
   it. Clicking Enter starts the simulation and the letters erode.
   --------------------------------------------------------------- */

.splash { display: none; }

html.is-splash,
html.is-splash body { overflow: hidden; height: 100%; }

/* The delay is the point: the letters get a beat of erosion on their own
   before the site arrives over the top of them. */
html.is-splash .page {
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.3s ease 1s;
}

html.is-splash .splash {
  position: fixed;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 24px;
  transition: opacity .55s ease;
}

/* Sized in the same proportions the name wants, so the letters come out
   as large as they can without crowding the button. */
.splash__word {
  width: min(1080px, 86vw);
  height: min(300px, 34vh);
}

.splash__enter {
  margin-top: clamp(34px, 7vh, 84px);
  padding: 12px 42px;
  border: 1px solid var(--fg);
  background: #000;
  color: var(--fg);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .16em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background .18s linear, color .18s linear;
}

.splash__enter:hover { background: var(--fg); color: #000; }

html.is-splash.is-leaving .splash { opacity: 0; pointer-events: none; }
html.is-splash.is-leaving .page  { opacity: 1; pointer-events: auto; }

/* Scrolling comes back the moment Enter is pressed, rather than waiting
   for the fade to finish. */
html.is-splash.is-leaving,
html.is-splash.is-leaving body { overflow: visible; height: auto; }

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 24px;
}

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

/* ---------------------------------------------------------------
   Masthead
   --------------------------------------------------------------- */

.mast {
  display: grid;
  grid-template-columns: 1fr auto 1fr;   /* keeps the eye dead centre */
  align-items: center;
  gap: 18px;
  padding: 26px 0 0;
}

.mast__name {
  justify-self: start;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -.01em;
  text-decoration: none;
}

.mast__name:hover { text-decoration: underline; text-underline-offset: 3px; }

/* The one interactive flourish: clicking the eye brightens the field. */
.mast__eye {
  justify-self: center;
  display: block;
  line-height: 0;
  padding: 6px 10px;
  margin: -6px -10px;          /* keeps the hit area generous without moving it */
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.mast__eye img {
  width: auto;
  height: 34px;
  opacity: .82;
  transition: opacity .18s linear, transform .18s ease-out;
}

.mast__eye:hover img,
.mast__eye:focus-visible img { opacity: 1; }

.mast__eye[aria-pressed="true"] img { opacity: 1; }

.mast__eye.is-hit img { animation: eye-hit .42s ease-out; }

@keyframes eye-hit {
  0%   { transform: scale(1); }
  22%  { transform: scale(.9); }
  55%  { transform: scale(1.1); }
  100% { transform: scale(1); }
}

.mast__who {
  justify-self: end;
  font-size: 15px;
  color: var(--dim);
  text-align: right;
}

.back {
  margin: 30px 0 0;
  font-size: 14px;
}

.back a { color: var(--dim); text-decoration: none; }
.back a:hover { color: var(--fg); }

/* ---------------------------------------------------------------
   Intro
   --------------------------------------------------------------- */

.intro { padding: 120px 0 104px; }

.intro h1 {
  margin: 0;
  font-size: clamp(34px, 5.4vw, 62px);
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1.08;
  max-width: 18ch;
}

.intro p {
  margin: 22px 0 0;
  max-width: 56ch;
  font-size: clamp(16px, 1.5vw, 18px);
  color: var(--dim);
}

.intro p + p { margin-top: 14px; }

/* The front page runs one long sentence as its headline where the games
   section runs a short one, so it takes the same type at a smaller step
   rather than a different treatment. */
.intro--home h1 {
  font-size: clamp(28px, 4vw, 46px);
  line-height: 1.14;
  max-width: 26ch;
}

.intro__bio { max-width: 62ch; }

.intro__bio a {
  color: var(--fg);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  transition: border-color .18s ease;
}

.intro__bio a:hover,
.intro__bio a:focus-visible { border-bottom-color: var(--fg); }

/* ---------------------------------------------------------------
   The row of links on the front page
   --------------------------------------------------------------- */

.linkrow {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: clamp(32px, 6vh, 54px) 0 0;
  max-width: 62ch;
}

.linkbtn {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 13px 18px;
  border: 1px solid var(--line);
  color: var(--fg);
  text-decoration: none;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -.01em;
  transition: border-color .18s ease, background-color .18s ease;
}

.linkbtn:hover,
.linkbtn:focus-visible {
  border-color: var(--line-strong);
  background: rgba(255, 255, 255, .04);
}

/* The first one is the games section — the reason the page exists to be
   clicked through, so it doesn't sit level with the outbound links. */
.linkrow .linkbtn:first-child {
  border-color: var(--line-strong);
}

.linkrow .linkbtn:first-child:hover {
  background: var(--fg);
  color: #000;
  border-color: var(--fg);
}

/* ---------------------------------------------------------------
   The grid of games

   Art-directed rather than systematic: a 12-column field with tiles of
   varying width, nudged vertically so no two rows line up. The slot
   classes are positional, so reordering games.js moves games through
   the composition rather than rebuilding it.
   --------------------------------------------------------------- */

.games {
  list-style: none;
  margin: 0;
  padding: 0 0 40px;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--gap);
  row-gap: 96px;
}

.game {
  transform: translate3d(0, var(--drift, 0px), 0);
  will-change: transform;
}

.game--slot-1  { grid-column: 1 / 8;   }
.game--slot-2  { grid-column: 9 / 13;  margin-top: 130px; }
.game--slot-3  { grid-column: 2 / 6;   margin-top: 40px;  }
.game--slot-4  { grid-column: 7 / 13;  }
.game--slot-5  { grid-column: 1 / 6;   }
.game--slot-6  { grid-column: 7 / 12;  margin-top: 150px; }
.game--slot-7  { grid-column: 2 / 8;   }
.game--slot-8  { grid-column: 9 / 13;  margin-top: 70px;  }
.game--slot-9  { grid-column: 1 / 5;   margin-top: 60px;  }
.game--slot-10 { grid-column: 6 / 12;  }

.game a {
  display: block;
  text-decoration: none;
  color: inherit;
}

/* The card is what leans; the list item is what drifts. Keeping them on
   separate elements stops the two transforms fighting. */
.game__card {
  position: relative;
  transition: transform .5s cubic-bezier(.2, .7, .3, 1);
}

/* The emoji pair, straddling the bottom edge of the card. No container —
   they sit directly on the artwork and the black below it. Inside the card,
   so they lean with it. Unlike the art they keep their colour at rest: they're
   the one bit of the tile that stays lit while the archive sits grey. The
   shadow is what keeps them legible over a bright cover.
   `--tile-inset` also sets the text indent below, so the two line up. */
.game__chip {
  position: absolute;
  left: var(--tile-inset);
  bottom: -20px;
  display: inline-block;
  font-size: 34px;
  line-height: 1;
  letter-spacing: 6px;
  filter: drop-shadow(0 2px 5px rgba(0, 0, 0, .85));
}

.game__art {
  position: relative;
  aspect-ratio: 63 / 50;
  background: #0b0b0b;
  border: 1px solid var(--line);
  overflow: hidden;
  transition: border-color .4s ease;
}

.game a:hover .game__art { border-color: var(--line-strong); }

/* The archive sits grey. Colour comes back only in the one you're
   looking at — the same move the play page makes. */
.game__art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) brightness(.82) contrast(.92);
  transition: filter .55s ease;
}

.game a:hover .game__art img,
.game a:focus-visible .game__art img { filter: grayscale(0) brightness(1) contrast(1); }

/* Dark cover art needs a lift to survive being drained, or it reads as an
   empty tile. Set `lift: true` on the entry to opt in. */
.game__art--lift img { filter: grayscale(1) brightness(1.25) contrast(.9); }

.game__art .anim,
.game__art .still { position: absolute; inset: 0; }

/* Only tiles that actually have an animation swap on hover. A static
   cover stays exactly as it is. */
.game__art--anim .still { transition: opacity .18s linear, filter .55s ease; }

.game a:hover .game__art--anim .still,
.game a:focus-visible .game__art--anim .still { opacity: 0; }

.game__name {
  margin: 44px 0 0 var(--tile-inset);
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -.015em;
}

.game__line {
  margin: 6px 0 0 var(--tile-inset);
  max-width: 44ch;
  font-size: 15px;
  line-height: 1.5;
  color: var(--dim);
}

.game a:hover .game__name { text-decoration: underline; text-underline-offset: 3px; }

/* ---------------------------------------------------------------
   Clicking a tile expands its cover into the game frame. Browsers
   without cross-document view transitions just navigate normally.
   --------------------------------------------------------------- */

@view-transition { navigation: auto; }

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

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* ---------------------------------------------------------------
   "A few more"
   --------------------------------------------------------------- */

.more {
  border-top: 1px solid var(--line);
  padding: 34px 0 0;
  margin-top: 20px;
}

.more > summary {
  cursor: pointer;
  list-style: none;
  font-size: 15px;
  color: var(--dim);
  display: inline-block;
}

.more > summary::-webkit-details-marker { display: none; }
.more > summary:hover { color: var(--fg); }
.more > summary::after { content: " →"; }
.more[open] > summary::after { content: " ↑"; }
.more[open] > summary { color: var(--fg); }

.more__note {
  margin: 16px 0 0;
  max-width: 56ch;
  font-size: 15px;
  color: var(--dimmer);
}

.more__list {
  list-style: none;
  margin: 22px 0 0;
  padding: 0;
}

.more__list li { border-top: 1px solid var(--line); }

.more__list a {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 14px;
  padding: 13px 0;
  text-decoration: none;
}

.more__list a:hover { background: rgba(255, 255, 255, .04); }
.more__list b { font-weight: 600; font-size: 16px; }
.more__list span { font-size: 15px; color: var(--dim); }

/* ---------------------------------------------------------------
   Play page
   --------------------------------------------------------------- */

.gamehead { padding: 40px 0 26px; }

.gamehead h1 {
  margin: 0;
  font-size: clamp(24px, 3.4vw, 34px);
  font-weight: 600;
  letter-spacing: -.02em;
}

.gamehead p {
  margin: 8px 0 0;
  color: var(--dim);
  font-size: 17px;
}

.screen {
  position: relative;
  margin: 0 auto;
  background: #000;
  border: 1px solid var(--line);
  overflow: hidden;
}

.screen__scaler {
  position: absolute;
  top: 50%;
  left: 50%;
  transform-origin: center center;
}

.screen__scaler iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  background: #000;
}

.screen__scaler iframe.crisp { image-rendering: pixelated; }

/* Cover art sits well back behind the Play button: blurred, dimmed and
   drained of colour, scaled up a touch so the blur doesn't show soft edges.
   Hovering brings the colour back and pushes in very slightly — the game
   surfacing before you commit to it. */
.poster {
  position: absolute;
  inset: 0;
  width: 100%;
  display: block;
  padding: 0;
  border: 0;
  background: #000;
  color: var(--fg);
  font: inherit;
  cursor: pointer;
  overflow: hidden;
}

.poster img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: .13;
  filter: blur(3.5px) grayscale(1);
  transform: scale(1.04);
  transition: opacity .5s ease,
              filter .5s ease,
              transform .9s cubic-bezier(.2, .7, .3, 1);
}

/* Armed only while the pointer is on the Play button itself — the whole
   panel stays clickable, but the bloom is reserved for the button. */
.poster.is-armed img,
.poster:focus-visible img {
  opacity: .38;
  filter: blur(3.5px) grayscale(0);
  transform: scale(1.09);
}

.poster__label {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 8px;
}

.poster__btn {
  border: 1px solid var(--fg);
  padding: 11px 30px;
  font-size: 16px;
  font-weight: 600;
  background: #000;
}

.poster.is-armed .poster__btn,
.poster:focus-visible .poster__btn { background: var(--fg); color: #000; }

.poster__hint {
  font-size: 13px;
  color: var(--dim);
}

.bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 12px auto 0;
  flex-wrap: wrap;
}

.bar__spacer { flex: 1; }

.btn {
  background: transparent;
  color: var(--dim);
  border: 1px solid var(--line);
  padding: 7px 15px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}

.btn:hover { color: var(--fg); border-color: var(--line-strong); }

.notice {
  margin: 16px auto 0;
  max-width: 62ch;
  padding: 12px 15px;
  border: 1px solid var(--line);
  font-size: 14px;
  color: var(--dim);
}

/* ---- text below the game ---- */

.detail {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 56px;
  padding: 62px 0 0;
  border-top: 1px solid var(--line);
  margin-top: 62px;
}

.detail h2 {
  margin: 0 0 12px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--dimmer);
}

.detail section + section { margin-top: 38px; }

.detail p {
  margin: 0 0 14px;
  max-width: 58ch;
  color: #d8d8d8;
}

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

.keys {
  margin: 0;
  display: grid;
  gap: 0;
}

.keys > div {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  padding: 9px 0;
  border-top: 1px solid var(--line);
  font-size: 15px;
}

.keys dt { font-weight: 600; min-width: 9em; }
.keys dd { margin: 0; color: var(--dim); }

.meta {
  margin: 0;
  font-size: 15px;
}

.meta > div {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  padding: 9px 0;
  border-top: 1px solid var(--line);
}

.meta dt { color: var(--dimmer); min-width: 7em; }
.meta dd { margin: 0; color: var(--dim); }

.links {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 15px;
}

.links li { border-top: 1px solid var(--line); padding: 9px 0; }
.links a { color: var(--dim); text-decoration: none; }
.links a:hover { color: var(--fg); text-decoration: underline; text-underline-offset: 3px; }

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

.foot {
  margin-top: 90px;
  border-top: 1px solid var(--line);
  padding: 26px 0 60px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 26px;
  font-size: 14px;
  color: var(--dimmer);
}

.foot a { color: var(--dim); text-decoration: none; }
.foot a:hover { color: var(--fg); }

/* ---------------------------------------------------------------
   Small screens — none of these builds take touch input
   --------------------------------------------------------------- */

.note-desktop {
  display: none;
  margin: 0 0 34px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  font-size: 14px;
  color: var(--dim);
}

/* Below this the composition stops being art direction and starts being
   a mess, so it collapses to an even grid. */
@media (max-width: 1080px) {
  .games { grid-template-columns: repeat(2, 1fr); row-gap: 56px; }
  .games .game { grid-column: auto !important; margin-top: 0 !important; }
  .detail { grid-template-columns: 1fr; gap: 38px; }
}

@media (max-width: 720px) {
  .note-desktop { display: block; }
  .intro--home { padding: 46px 0 40px; }
  .intro { padding: 56px 0 46px; }
  .games { grid-template-columns: 1fr; row-gap: 40px; }
  .foot { margin-top: 60px; }
  .mast__eye img { height: 28px; }
}

@media (max-width: 520px) {
  .mast { grid-template-columns: 1fr auto; }
  .mast__who { display: none; }
  .linkrow { flex-direction: column; }
  .linkbtn { justify-content: flex-start; }
}

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