* { box-sizing: border-box; }

/* the pages hide <html> inline until this sheet arrives, so they never flash unstyled */
html { visibility: visible; }

body {
  margin: 0;
  background: #000;
  color: #c2c3c7;
  font: 16px/1.5 ui-monospace, "Cascadia Mono", Menlo, monospace;
}

a { color: #ff77a8; }

nav {
  display: flex;
  gap: 1.5rem;
  padding: .75rem 1rem;
}
nav a { text-decoration: none; white-space: nowrap; }
nav a:first-child { color: #fff1e8; font-weight: bold; }
/* game title: centred over the game on the nav's row, so it takes no height from the game.
   kept clear of the nav links on either side, and cut off rather than wrapping */
#meta {
  position: absolute;
  top: 0;
  left: calc(50% + 1.25rem);  /* the player starts 2.5rem in, after the info tab */
  transform: translateX(-50%);
  max-width: calc(100% - 20rem);
  padding: .75rem 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
nav a:last-child { margin-left: auto; }
#meta b { color: #fff1e8; }

/* home */

/* content in the middle row, footer in the bottom one. the top row matches the bottom so the content sits in the middle
   of the window, not of the space above the footer. when space runs short the top row shrinks first, down to the
   footer's height once the page scrolls */
.page {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto minmax(auto, 1fr);
  min-height: 100vh;
  min-height: 100dvh;
}

.home {
  grid-row: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 34rem;
  margin: 0 auto;
  padding: 1rem;
  text-align: center;
}
.home.about { max-width: 44rem; }
.home h1 { color: #fff1e8; font-size: 2rem; margin: 0 0 1rem; }
.home .play {
  margin-top: 1rem;
  padding: .5rem 1.25rem;
  background: #ff004d;
  color: #fff1e8;
  text-decoration: none;
  border-radius: 4px;
}
/* github mark in the top right corner */
.github {
  position: absolute;
  top: .75rem;
  right: 1rem;
  opacity: .75;  /* dimmed until hovered */
}
.github:hover, .github:focus-visible { opacity: 1; }
.github img { display: block; width: 1.75rem; height: 1.75rem; }
/* in the page's bottom row, so it sits at the bottom but scrolls below the content when space runs out */
.site-footer {
  grid-row: 3;
  align-self: end;
  padding: 1rem;
  font-size: .875rem;
  text-align: center;
}

/* browse */

.browse {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

.stage { position: relative; display: flex; flex: 1; min-height: 0; margin-bottom: .75rem; }
#player { flex: 1; min-width: 0; margin-left: 2.5rem; }  /* room for the closed info tab, which overlays it */
#player iframe { display: block; width: 100%; height: 100%; border: 0; }

/* loading spinner, covering the player while a game boots */
#player { position: relative; }
#loading { position: absolute; inset: 0; background: #000 url(loading.svg) center no-repeat; pointer-events: none; }
#loading[hidden] { display: none; }

/* tucked below the screen with a thin strip showing; slides up when the cursor nears the bottom.
   the transparent top padding is the "near the bottom" band that triggers it */
.shelf {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;  /* above the info panel */
  padding-top: 3rem;
  transform: translateY(calc(100% - 3.75rem));
  transition: transform .2s ease-out;
}
.shelf:hover, .shelf:focus-within { transform: none; }

/* a tab on the shelf's top right edge, only there while the shelf is up */
#search {
  position: absolute;
  top: 3rem;  /* the top of the carousel, below the hover band */
  right: 3rem;
  width: min(12rem, 50vw);
  padding: .4rem .75rem;
  border: 0;
  border-radius: 3px 3px 0 0;
  background: #333;  /* same grey as the shelf */
  color: #fff1e8;
  font: inherit;
  font-size: 1rem;  /* any smaller and iOS zooms in on focus */
  outline: none;
  translate: 0 -100%;
  visibility: hidden;
}
#search::placeholder { color: #888; }
.shelf:hover #search, .shelf:focus-within #search { visibility: visible; }

/* half-width side padding so even the first and last cartridge can sit in the middle */
.carousel {
  position: relative;
  display: flex;
  gap: 1rem;
  padding: 1rem calc(50% - 3.75rem);
  overflow-x: auto;
  scrollbar-width: thin;
  scrollbar-color: #5f574f #333;
  background: #333;
}

/* PC: a scrollbar 50% thicker than thin. firefox only has thin (8px) and auto (12px), so it gets auto; chromium
   and safari ignore the ::-webkit-scrollbar rules while scrollbar-width/color are set, so those are reset there */
@media (hover: hover) {
  .carousel { scrollbar-width: auto; }
  @supports selector(::-webkit-scrollbar) {
    .carousel { scrollbar-width: auto; scrollbar-color: auto; }
    .carousel::-webkit-scrollbar { height: 16px; background: #333; }
    .carousel::-webkit-scrollbar-thumb { background: #5f574f; }
  }
}

/* a cartridge: grey shell, clipped corner, thumbnail art, name, grip ridges. the shell is one svg laid out in
   percentages, with the corner and pins pinned to its edges, so it fits whatever height the thumbnail ends up */
.cart {
  flex: none;
  width: 7.5rem;
  padding: .5rem .5rem 1.4rem;
  border: 0;
  background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><mask id='m'><rect width='100%' height='100%' fill='white'/><svg x='100%' overflow='visible'><path d='M-16 0h16v16z'/></svg></mask><rect width='100%' height='100%' rx='3' fill='%235f574f' mask='url(%23m)'/><svg x='50%' y='100%' overflow='visible'><path stroke='%233a3a40' stroke-width='8' stroke-dasharray='4' d='M-34-10.4h68'/></svg></svg>");
  font: inherit;
  cursor: pointer;
  transition: transform .15s;
}
.cart .thumbnail {  /* its tile of the thumbnail sprite sheet, set in thumbnails.css */
  display: block;
  width: 100%;
  aspect-ratio: 1;
  image-rendering: pixelated;
  border: 3px solid #000;
  border-bottom: 0;
}
.cart span {
  display: block;
  padding: .2rem .25rem;
  background: #fff1e8;
  color: #000;
  font-size: .75rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border: 3px solid #000;
  border-top: 0;
}
.cart:hover, .cart:focus-visible { transform: translateY(-4px); outline: none; }
.cart[aria-current] {
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><mask id='m'><rect width='100%' height='100%' fill='white'/><svg x='100%' overflow='visible'><path d='M-16 0h16v16z'/></svg></mask><rect width='100%' height='100%' rx='3' fill='%23ff004d' mask='url(%23m)'/><svg x='50%' y='100%' overflow='visible'><path stroke='%233a3a40' stroke-width='8' stroke-dasharray='4' d='M-34-10.4h68'/></svg></svg>");  /* same shell in red */
  transform: translateY(-4px);
}

/* info panel: just a sideways "Game Info" tab on the left until opened, then it widens to show the game's
   description and controls, with the tab sticking out past its right edge. it slides out over the
   player rather than pushing it aside, so the game stays put */
#meta .info { display: none; }
#info {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 1;  /* over the player */
  width: 2.5rem;
  border-right: 2px solid transparent;
  /* the grey snaps on when opening and only snaps off once it has slid shut, so it never fades */
  transition: width .2s ease-out, background-color 0s .2s, border-color 0s .2s;
}
#info.open {
  width: min(20rem, 80vw);
  background: #333;  /* same grey as the shelf */
  border-color: #333;
  transition: width .2s ease-out;
}
#info-toggle {
  position: absolute;
  top: 50%;
  right: .25rem;
  padding: 1rem 0;
  width: 2.25rem;  /* reaches the left edge of the closed panel */
  height: 8rem;  /* fixed, since the text's length would set it in vertical writing */
  border: 0;
  border-radius: 3px 0 0 3px;  /* flat on the left once rotated */
  background: #5f574f;
  color: #fff1e8;
  font: inherit;
  font-size: 1rem;  /* same as the PicoPlayer logo */
  font-weight: bold;
  white-space: nowrap;
  writing-mode: vertical-rl;
  transform: translateY(-50%) rotate(180deg);  /* reads bottom to top */
  cursor: pointer;
  transition: right .2s ease-out;
}
#info.open #info-toggle { right: calc(-2.25rem - 2px); }  /* just outside the panel and its border */
#info-toggle:hover, #info-toggle:focus-visible, #info.open #info-toggle { background: #ff004d; outline: none; }
#info-body {
  height: 100%;
  padding: 1rem 1rem 4.5rem;  /* clear the shelf's strip below */
  overflow: hidden auto;  /* clips the content while the panel widens */
  color: #bbb;
  font-size: .875rem;
  visibility: hidden;
  transition: visibility .2s;
}
#info.open #info-body { visibility: visible; }
#info-body > * { width: calc(min(20rem, 80vw) - 2rem); }  /* full width from the start, so text doesn't reflow mid-slide */
.byline { display: none; margin: 0 0 1rem; font-size: 1rem; }
.byline b { color: #fff1e8; }
.info p { margin: 0 0 1rem; }
.info h2 { margin: 0 0 .5rem; color: #fff; font-size: .875rem; text-transform: uppercase; }
/* descriptions copied from Lexaloffle posts bring their own headings, images, tables and code */
.info :is(h1, h3, h4, h5, h6) { margin: 0 0 .5rem; color: #fff; font-size: .875rem; }
.info :is(ul, ol) { margin: 0 0 1rem; padding-left: 1.25rem; }
.info img { display: block; max-width: 100%; height: auto; margin: 0 0 1rem; image-rendering: pixelated; }
.info :is(pre, table) { display: block; max-width: 100%; overflow-x: auto; margin: 0 0 1rem; }
.info a { color: #29adff; overflow-wrap: anywhere; }
.info hr { border: 0; border-top: 1px solid #555; margin: 0 0 1rem; }
.info .source { color: #888; font-size: .75rem; }
.info dl { display: grid; grid-template-columns: auto 1fr; gap: .25rem .75rem; margin: 0; }
.info dt { color: #fff; white-space: nowrap; }
.info dd { margin: 0; }

#shelf-toggle, .hint-touch { display: none; }

/* touch screens can't hover, so the shelf becomes a sheet that pops up from a Games bar at the bottom,
   with the cartridges in a grid that scrolls vertically */
@media (hover: none) {
  .hint-hover, #meta { display: none; }
  .hint-touch { display: block; }
  .stage { margin-bottom: 2rem; }  /* keep the game and its touch controls clear of the bar */
  .shelf, .shelf:hover, .shelf:focus-within {
    display: flex;
    flex-direction: column;
    height: 80dvh;
    padding-top: 0;
    transform: translateY(calc(100% - 2rem));
  }
  .shelf.open { transform: none; }
  #search, .shelf:hover #search, .shelf:focus-within #search { top: 0; visibility: hidden; }
  .shelf.open #search { visibility: visible; }
  /* dims the page behind the open sheet, and taps on it close the sheet */
  .shelf.open::before { content: ""; position: fixed; inset: -100dvh 0 0; z-index: -1; background: rgb(0 0 0 / .6); }
  #shelf-toggle {
    display: block;
    flex: none;
    height: 2rem;
    border: 0;
    background: #5f574f;
    color: #fff1e8;
    font: inherit;
    font-weight: bold;
  }
  #shelf-toggle::before { content: "\25B2  "; }
  .shelf.open #shelf-toggle { background: #ff004d; }
  .shelf.open #shelf-toggle::before { content: "\25BC  "; }
  .carousel {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
    align-content: start;
    padding: 1rem;
    overflow: hidden auto;
  }
  .cart { width: auto; }
  .cart:hover { transform: none; }  /* a tap leaves :hover stuck on */
  .cart[aria-current] { transform: none; }
}

/* touch screens: Game Info moves to the top right of the bar in place of Random Game,
   and the game gets the full width now that the side tab is gone */
@media (hover: none) {
  #random { display: none; }
  #player { margin-left: 0; }
  #info { width: 0; }
  #info-toggle, #info-toggle:hover, #info-toggle:focus-visible, #info.open #info-toggle {
    position: fixed;
    top: 0;
    right: 0;
    width: auto;
    height: auto;
    padding: .75rem 1rem;
    border-radius: 0;
    background: none;
    color: #ff77a8;
    font-size: 1rem;
    font-weight: normal;
    writing-mode: horizontal-tb;
    transform: none;
  }
  #info.open #info-toggle { color: #fff1e8; }
  .byline { display: block; }  /* the title bar is hidden, so name the game and its creator in the panel */
}

/* touch screens held sideways: the game is a square in the middle with empty space above the touch controls,
   so the nav floats over the top corners and the game takes its row too. only the links catch taps */
@media (hover: none) and (orientation: landscape) {
  nav { position: absolute; top: 0; left: 0; right: 0; z-index: 2; pointer-events: none; }  /* above the info panel */
  nav a { pointer-events: auto; }
  #info-body { padding-top: 3rem; }  /* clear the nav's row */
}
