/* The site's base styles. The colors are the thing8 palette: --void is
   PALETTE[0], the near-black the console clears to, and --light is the
   wordmark's own fill, used for the text beside it. The font is Kode Mono,
   the same one the editor uses everywhere. */

@font-face {
  font-family: 'Kode Mono';
  src: url(/assets/KodeMono-Regular.1eb66851d26f9ce2c668.ttf) format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

:root {
  --void:  #0f1224;
  --light: #eef3f6;
  --logo-glow: rgba(238, 243, 246, 0.35);

  /* The wordmark PNG is 93x30; it is drawn at an integer scale so its
     pixels stay even. */
  --wordmark-w: 93;
  --wordmark-h: 30;
  --wordmark-scale: 4;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  height: 100%;
}

body {
  background: var(--void);
  color: var(--light);
  font-family: 'Kode Mono', monospace;
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

#app {
  min-height: 100%;
}

/* The hidden attribute wins over any display rule below, so a page can hide
   a thing by setting it without knowing how the thing is laid out. */
[hidden] {
  display: none !important;
}

/* A page that is only the wordmark and a line: everything centered on an
   otherwise empty screen. */
.holding {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 28px;
  padding: 24px;
  text-align: center;
}

.wordmark {
  display: block;
  width: calc(var(--wordmark-w) * var(--wordmark-scale) * 1px);
  height: calc(var(--wordmark-h) * var(--wordmark-scale) * 1px);
  max-width: 100%;
  image-rendering: pixelated;
  filter: drop-shadow(0 0 12px var(--logo-glow));
  user-select: none;
}

.tagline {
  font-size: 20px;
  letter-spacing: 0.08em;
  opacity: 0.85;
}

/* On narrow screens the wordmark steps down one integer scale rather than
   shrinking fractionally, which would blur its pixels. */
@media (max-width: 440px) {
  :root {
    --wordmark-scale: 3;
  }
}

/* ---- Signing in ---- */

/* More of the palette: Red for errors, Leaf for a job done, Stone for
   borders and secondary text. */
:root {
  --red:   #e72734;
  --leaf:  #29bc36;
  --stone: #8191a7;
}

.dim {
  opacity: 0.7;
}

.error {
  color: var(--red);
  max-width: 480px;
}

.ok {
  color: var(--leaf);
}

/* The top-right corner of the Create Account screen: one quiet link. */
.corner {
  position: fixed;
  top: 16px;
  right: 20px;
  z-index: 1;
}

.corner-link {
  color: var(--light);
  font-size: 13px;
  letter-spacing: 0.04em;
  text-decoration: none;
  opacity: 0.45;
  transition: opacity 0.15s;
}

.corner-link:hover,
.corner-link:focus-visible {
  opacity: 0.9;
  text-decoration: underline;
}

.corner-link.busy {
  pointer-events: none;
  opacity: 0.25;
}

/* The signed-in screens: a narrow column, centered, the wordmark small at
   the top so the page still says whose it is. */
.panel {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 64px 24px;
  text-align: center;
}

.panel > * {
  max-width: 480px;
}

.wordmark.small {
  --wordmark-scale: 2;
  filter: none;
  opacity: 0.85;
  margin-bottom: 12px;
}

.panel h1 {
  font-size: 24px;
  font-weight: normal;
  letter-spacing: 0.06em;
}

.panel form {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  width: 100%;
  max-width: 360px;
}

.panel input {
  width: 100%;
  padding: 10px 12px;
  background: transparent;
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 4px;
  font: inherit;
  outline: none;
}

.panel input:focus {
  border-color: var(--light);
}

.panel input:disabled,
.panel button:disabled {
  opacity: 0.5;
  cursor: default;
}

.buttons {
  display: flex;
  gap: 12px;
  justify-content: center;
}

.panel button,
.panel a.primary {
  padding: 8px 18px;
  background: transparent;
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 4px;
  font: inherit;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}

.panel button:hover:not(:disabled) {
  border-color: var(--light);
}

.panel button.primary,
.panel a.primary {
  background: var(--light);
  color: var(--void);
  border-color: var(--light);
}

/* The acceptance of the terms, on the Create Account screen: the whole line
   is the target, label included — a checkbox on its own is a small thing to
   ask someone to hit. The two links open the documents in a new tab and,
   being links, do not tick the box: reading is not agreeing. */
.accept-terms {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  text-align: left;
  line-height: 1.4;
  cursor: pointer;
}

.accept-terms input {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  padding: 0;
  accent-color: var(--light);
  cursor: pointer;
}

.accept-terms a {
  color: var(--light);
  text-decoration: underline;
}

/* The confirmation step of the Create Account screen: the face the account
   will wear and the name under it, as they will appear to everyone. */
.confirm-who {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
}

.confirm-pic {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--stone);
  border: 2px solid var(--light);
}

.confirm-uname {
  font-size: 22px;
  letter-spacing: 0.04em;
}

#create-step-form,
#create-step-confirm {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  width: 100%;
}

#create-step-form[hidden],
#create-step-confirm[hidden] {
  display: none;
}

/* Who invited you, on the Create Account screen. */
.invite-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.invite-pic {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
}

/* The desktop app's sign-in page (app-signin.js): the panel, with a line of
   plain text or two where the other screens have a form. */
.app-signin p {
  text-align: center;
  line-height: 1.5;
}

.app-signin .dim a {
  color: inherit;
}

/* The shell and the pages in it: the top bar, the front page's shelves, a
   game's page, the Download page, the dialogs. styles.css has the base —
   the palette, the font, the wordmark, the Create Account panel. More of
   the palette here: Gold for Get It and Play, Deep for the cards' ground. */

:root {
  --gold:  #f8da62;
  --deep:  #152979;
  --water: #1c7fe3;
  --card:  rgba(21, 41, 121, 0.28);
  --line:  rgba(129, 145, 167, 0.35);
  --topbar-h: 56px;
  --page-max: 1120px;
}

#shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

#page {
  flex: 1;
  width: 100%;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 20px 40px;
}

/* A game's page (index.js): the screen scales to the window, so the page
   takes the whole of it. */
#page.wide {
  max-width: none;
}

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

/* ---- The top bar ---- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px 0 20px;
  background: rgba(15, 18, 36, 0.92);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(6px);
}

.brand {
  display: flex;
  align-items: center;
  line-height: 0;
}

.wordmark.bar {
  --wordmark-scale: 1;
  filter: none;
}

@media (min-width: 640px) {
  .wordmark.bar {
    --wordmark-scale: 1;
    width: calc(var(--wordmark-w) * 1.5px);
    height: calc(var(--wordmark-h) * 1.5px);
  }
}

.topbar-right {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
}

.get-it {
  padding: 6px 14px;
  background: var(--gold);
  color: var(--void);
  border: 1px solid var(--gold);
  border-radius: 4px;
  font: inherit;
  font-size: 14px;
  letter-spacing: 0.04em;
  cursor: pointer;
}

.get-it:hover:not(:disabled) {
  filter: brightness(1.08);
}

.get-it:disabled {
  opacity: 0.5;
  cursor: default;
}

.face {
  width: 36px;
  height: 36px;
  padding: 0;
  border: 2px solid var(--stone);
  border-radius: 50%;
  background: var(--stone);
  cursor: pointer;
  overflow: hidden;
  line-height: 0;
}

.face img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.face:hover:not(:disabled),
.face[aria-expanded="true"] {
  border-color: var(--light);
}

.face.waiting {
  opacity: 0.5;
  cursor: default;
}

.menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 200px;
  background: var(--void);
  border: 1px solid var(--stone);
  border-radius: 6px;
  padding: 6px 0;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  z-index: 6;
}

.menu-who {
  display: block;
  padding: 8px 14px;
  font-size: 13px;
  opacity: 0.7;
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
  color: inherit;
  text-decoration: none;
}

.menu-who:hover {
  opacity: 1;
  text-decoration: underline;
}

.menu button {
  display: block;
  width: 100%;
  padding: 8px 14px;
  background: none;
  border: 0;
  color: var(--light);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}

.menu button:hover {
  background: rgba(238, 243, 246, 0.08);
}

/* The line under the bar for what the sign-in had to say. */
.notice {
  max-width: var(--page-max);
  margin: 12px auto 0;
  padding: 8px 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 14px;
}

.notice.error {
  max-width: var(--page-max);
  border: 1px solid var(--red);
  border-radius: 4px;
  margin-left: 20px;
  margin-right: 20px;
}

@media (min-width: 1160px) {
  .notice.error {
    margin-left: auto;
    margin-right: auto;
  }
}

/* ---- Buttons shared by the pages ---- */

button.ghost,
button.more,
a.primary,
button.primary {
  padding: 6px 14px;
  background: transparent;
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 4px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}

button.ghost {
  border-color: transparent;
  opacity: 0.75;
}

button.ghost:hover:not(:disabled),
button.more:hover:not(:disabled) {
  border-color: var(--light);
  opacity: 1;
}

a.primary,
button.primary {
  background: var(--light);
  color: var(--void);
  border-color: var(--light);
}

button:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ---- The front page ---- */

/* One line and a picture, side by side: the sentence and its Learn More on
   the left, the app on the right, the picture a link to the same place. On
   a narrow screen the picture goes under the words. */
.hero {
  padding: 40px 0 24px;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 32px 40px;
  align-items: center;
}

.hero-title {
  font-size: 30px;
  font-weight: normal;
  letter-spacing: 0.04em;
  line-height: 1.25;
  margin-bottom: 14px;
}

.hero-blurb {
  opacity: 0.85;
  line-height: 1.6;
  margin-bottom: 14px;
}

/* The way into the Asset Library, in the blurb: gold like the hero's other
   links, and underlined so it reads as one inside the sentence. */
.hero-blurb a {
  color: var(--gold);
  text-decoration: underline;
}

.hero-blurb a:hover {
  text-decoration: none;
}

.hero-more {
  font-size: 18px;
}

.hero-more a {
  color: var(--gold);
  text-decoration: none;
}

.hero-more a:hover {
  text-decoration: underline;
}

.hero-shot {
  display: block;
  line-height: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--void);
  transition: border-color 0.15s, transform 0.15s;
}

.hero-shot:hover {
  border-color: var(--light);
  transform: translateY(-2px);
}

.hero-shot img {
  width: 100%;
  height: auto;
}

@media (max-width: 720px) {
  .hero {
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
    padding-top: 28px;
  }

  .hero-title {
    font-size: 24px;
  }
}

.shelf {
  padding: 24px 0 8px;
}

.shelf-title {
  font-size: 18px;
  font-weight: normal;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 14px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

@media (max-width: 720px) {
  .grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
  }
}

.card {
  display: block;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  color: var(--light);
  transition: border-color 0.15s, transform 0.15s;
}

.card:hover {
  border-color: var(--light);
  transform: translateY(-2px);
}

/* The game itself: everything on the card but the byline, which is a link of
   its own to whoever made it (ui.js gameCard). */
.card-main {
  display: block;
  text-decoration: none;
  color: inherit;
}

/* A card with no byline under it still needs the room the byline's padding
   was giving the counts. */
.card-main:last-child .card-stats {
  padding-bottom: 10px;
}

.card-thumb {
  aspect-ratio: 256 / 240;
  background: var(--void);
  line-height: 0;
}

.card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
}

.card-nothumb {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 48px;
  line-height: 1;
  color: var(--stone);
}

.card-title {
  padding: 10px 12px 2px;
  font-size: 15px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.card-by {
  padding: 0 12px 10px;
  font-size: 12px;
  opacity: 0.7;
  white-space: nowrap;
  overflow: hidden;
}

/* The like and play counts under a card's title (ui.js cardStats): numbers
   and icons only, in the byline's quiet voice — the number first, then its
   icon, a size up from the text so it reads from across the shelf. The
   heart is the Like button's glyph (play.js likeRow) at the card's size; the
   play triangle is the game page's .play-icon. */
.card-stats {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 2px 12px 6px;
  font-size: 12px;
  opacity: 0.7;
  font-variant-numeric: tabular-nums;
}

.card-stat {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.card-heart {
  color: var(--red);
  font-size: 17px;
  line-height: 1;
}

.card-stat .play-icon {
  width: 14px;
  height: 14px;
}

/* A person, wherever they are named: their picture and their name, linking
   to their profile (ui.js userCredit). It borrows its size and spacing from
   whichever credit class it is given — .card-by, .play-by — and adds only
   what makes it read as a link. */
.user-credit {
  display: flex;
  align-items: center;
  gap: 6px;
  color: inherit;
  text-decoration: none;
  min-width: 0;
}

.user-credit span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-credit:hover {
  opacity: 1;
  text-decoration: underline;
}

.card-by-pic {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
}

.shelf-note {
  margin-top: 12px;
  font-size: 14px;
}

/* Who sees what, said once under the Starred Games heading: the list is
   private, the count of stars on a game is not. */
.shelf-privacy {
  margin: -6px 0 14px;
  font-size: 14px;
}

.shelf-more {
  display: flex;
  justify-content: center;
  margin-top: 16px;
}

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

.footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 8px 12px;
  padding: 24px 20px 32px;
  border-top: 1px solid var(--line);
  font-size: 13px;
  text-align: center;
}

.footer a,
.footer .footer-link {
  color: var(--light);
  opacity: 0.6;
  text-decoration: none;
}

/* The two that open a dialog rather than a page (cookies.js), drawn as the
   links beside them. */
.footer .footer-link {
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
}

.footer a:hover,
.footer .footer-link:hover {
  opacity: 1;
  text-decoration: underline;
}

.footer .dot {
  opacity: 0.4;
}

/* ---- Narrow pages: Download, legal, not found ---- */

.page-narrow {
  max-width: 640px;
  padding: 40px 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.page-narrow h1 {
  font-size: 24px;
  font-weight: normal;
  letter-spacing: 0.06em;
}

.page-narrow h2 {
  font-size: 18px;
  font-weight: normal;
  letter-spacing: 0.06em;
  margin-top: 12px;
}

.page-narrow .back {
  text-decoration: none;
  opacity: 0.6;
  margin-right: 4px;
}

.page-narrow .back:hover {
  opacity: 1;
}

/* ---- The About page (about.js) ---- */

.about {
  padding: 40px 0 24px;
  display: flex;
  flex-direction: column;
  gap: 56px;
}

.about-head {
  max-width: 720px;
}

.about-head h1 {
  font-size: 30px;
  font-weight: normal;
  letter-spacing: 0.04em;
  line-height: 1.25;
  margin-bottom: 14px;
}

.about-head p {
  line-height: 1.6;
}

/* A row is the words on one side and the picture on the other, and the
   sides swap every other row so the page zigzags down. */
.about-row {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 24px 40px;
  align-items: center;
}

.about-row:nth-child(odd) .about-shot {
  order: -1;
}

.about-text h2 {
  font-size: 20px;
  font-weight: normal;
  letter-spacing: 0.06em;
  color: var(--gold);
  margin-bottom: 12px;
}

.about-text p {
  line-height: 1.6;
  opacity: 0.9;
}

.about-text p + p {
  margin-top: 12px;
}

.about-text code {
  font-family: inherit;
  padding: 0 4px;
  border-radius: 3px;
  background: rgba(238, 243, 246, 0.1);
}

.about-shot {
  margin: 0;
  line-height: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--void);
}

.about-shot img {
  width: 100%;
  height: auto;
}

.about-foot {
  padding-top: 8px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.about-foot .get-it {
  font-size: 16px;
  padding: 10px 22px;
}

@media (max-width: 720px) {
  .about {
    gap: 40px;
  }

  .about-head h1 {
    font-size: 24px;
  }

  .about-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
  }

  /* Words first, then the picture, on every row. */
  .about-row:nth-child(odd) .about-shot {
    order: 0;
  }
}

.builds {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.build {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 200px;
  padding: 14px 18px;
  border: 1px solid var(--light);
  border-radius: 6px;
  color: var(--light);
  text-decoration: none;
}

a.build:hover {
  background: rgba(238, 243, 246, 0.08);
}

.build-off {
  border-color: var(--line);
  opacity: 0.55;
}

.build-os {
  font-size: 18px;
}

.build-version {
  font-size: 13px;
  opacity: 0.8;
}

.steps {
  padding-left: 24px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* ---- A game's page ---- */

/* The screen and, beside it, the info column at a fixed width — the app's
   Game Sidebar's — so the screen gets every other pixel of the window; with
   the info folded away (play.js, .info-hidden) it gets them all. */
.play {
  --info-w: 360px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--info-w);
  gap: 32px;
  padding: 12px 0 24px;
  align-items: start;
}

.play.info-hidden {
  grid-template-columns: minmax(0, 1fr);
}

.play.info-hidden .play-info {
  display: none;
}

/* Narrow: the info goes under the screen, where it is never in the way, so
   it is always there and there is no toggle. */
@media (max-width: 860px) {
  .play,
  .play.info-hidden {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }

  .play.info-hidden .play-info {
    display: flex;
  }
}

.play-screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  min-width: 0;
  /* Nothing here is text to select: a finger held on the screen or the pad
     must not bring up the browser's selection bar or a long-press menu. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

/* On a phone the screen is the page: it runs edge to edge, wider than the
   page's margins would let it, and the pad below sits at the same width. */
@media (max-width: 640px) {
  .play-screen {
    margin: 0 -20px;
  }

  .play-hints {
    padding: 0 20px;
  }
}

.stage {
  position: relative;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  background: var(--void);
}

.stage canvas {
  display: block;
  image-rendering: pixelated;
  background: #000;
  outline: none;
  touch-action: none;
}

.poster {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.poster img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
  opacity: 0.55;
}

.play-btn {
  position: relative;
  padding: 12px 28px;
  background: var(--gold);
  color: var(--void);
  border: 0;
  border-radius: 6px;
  font: inherit;
  font-size: 20px;
  letter-spacing: 0.06em;
  cursor: pointer;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.6);
}

.play-btn:hover:not(:disabled) {
  filter: brightness(1.08);
}

.stage-note {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 10px 14px;
  background: rgba(15, 18, 36, 0.9);
  font-size: 14px;
  text-align: center;
}

/* Under the screen: the keys, then Stop and Restart while a game runs, and
   at the far end — on the seam with the info column — the toggle that folds
   the column away and back. The T hint is only worth reading while a game
   is running, and the hints line is one line, so it shows then. */
.play-hints {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  min-height: 30px;
}

.play-hints-room {
  flex: 1;
}

button.info-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* The chevron points the way the column goes: right, off the page, to hide
   it; left, back on, to show it. */
button.info-toggle .chevron {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin: 0 2px;
  border-top: 1.5px solid currentColor;
  border-right: 1.5px solid currentColor;
  transform: translateX(-2px) rotate(45deg);
}

button.info-toggle.closed .chevron {
  transform: translateX(2px) rotate(-135deg);
}

/* Narrow: no column to fold (see .play above), so no toggle. */
@media (max-width: 860px) {
  button.info-toggle {
    display: none;
  }
}

/* The on-screen pad, for a finger. The pad itself takes every pointer
   (play.js follows each finger from where it lands to where it lifts), so
   the buttons in it are only the look — they take no events of their own,
   and what a finger presses is read off its position, not off the button
   under it. Sizes are in viewport widths, clamped, so the targets are
   thumb-sized on a phone and no bigger than they need to be on a tablet. */
.pad {
  --cell: clamp(46px, 14vw, 68px);
  --action: clamp(56px, 17vw, 80px);
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 10px;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  touch-action: none;
  cursor: default;
}

.pad * {
  pointer-events: none;
}

/* The d-pad is one disc: the four cells are drawn on it, and the corners
   between them are where diagonals are held. */
.dpad {
  display: grid;
  grid-template-columns: repeat(3, var(--cell));
  grid-template-rows: repeat(3, var(--cell));
  padding: 6px;
  border-radius: 50%;
  background: rgba(21, 41, 121, 0.18);
  border: 1px solid var(--line);
}

.pad-up { grid-area: 1 / 2; border-radius: 10px 10px 4px 4px; }
.pad-left { grid-area: 2 / 1; border-radius: 10px 4px 4px 10px; }
.pad-right { grid-area: 2 / 3; border-radius: 4px 10px 10px 4px; }
.pad-down { grid-area: 3 / 2; border-radius: 4px 4px 10px 10px; }

.action-pad {
  display: flex;
  gap: clamp(12px, 4vw, 24px);
  align-items: center;
  padding: 6px;
}

.pad-btn {
  width: var(--cell);
  height: var(--cell);
  background: var(--card);
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 8px;
  font: inherit;
  font-size: 20px;
  -webkit-tap-highlight-color: transparent;
}

.action-pad .pad-btn {
  width: var(--action);
  height: var(--action);
  border-radius: 50%;
  font-size: 24px;
}

.pad-btn.held {
  background: var(--light);
  color: var(--void);
}

/* The camera, between the two halves of the pad and out of both thumbs'
   way: a tap captures the screen as it is and opens the screenshot view
   (play.js takeScreenshot; the T key does the same on a keyboard). The one
   thing on the pad that takes its own pointer. */
.pad .pad-shot {
  pointer-events: auto;
  align-self: flex-start;
  margin-top: 8px;
  width: 44px;
  height: 44px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--card);
  color: var(--light);
  border: 1px solid var(--line);
  -webkit-tap-highlight-color: transparent;
}

.pad-shot .shot-icon {
  width: 22px;
  height: 22px;
  background: currentColor;
  -webkit-mask: url(/assets/camera-viewfinder-solid-full.caaa99e75ba8f4abc1ba.svg) center / contain no-repeat;
  mask: url(/assets/camera-viewfinder-solid-full.caaa99e75ba8f4abc1ba.svg) center / contain no-repeat;
}

/* A phone on its side has no room under the screen for a pad: the two
   halves float over the page's bottom corners instead, either side of the
   screen, and the screen takes the height they would have taken (play.js
   sees the pad is fixed and leaves it no room). The camera goes to the top
   right corner, in the margin beside the screen, under the bar. */
@media (orientation: landscape) and (max-height: 520px) and (pointer: coarse) {
  .pad {
    --cell: clamp(42px, 13vh, 60px);
    --action: clamp(52px, 16vh, 72px);
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    padding: 0 16px 16px;
    z-index: 4;
    pointer-events: none;
  }

  .pad .dpad,
  .pad .action-pad {
    pointer-events: auto;
    opacity: 0.85;
  }

  .pad .pad-shot {
    position: fixed;
    right: 16px;
    top: 52px;
    margin: 0;
    opacity: 0.85;
  }
}

/* The full-screen layer a finger's device plays in (play.js openModal):
   over everything, the top bar included, and every touch on it is the
   game's — nothing scrolls, zooms, selects or pulls to refresh. The pad
   lives in here, under the screen, and its rules above still apply to it,
   the landscape ones included. */
.play-modal {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  background: var(--void);
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  touch-action: none;
  overscroll-behavior: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  cursor: default;
}

/* The page under the layer must not move under a stray finger either. */
html.play-modal-open,
html.play-modal-open body {
  overflow: hidden;
  overscroll-behavior: none;
}

.play-modal-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 40px;
  padding: 2px 8px;
}

.play-modal-title {
  flex: 1;
  min-width: 0;
  text-align: center;
  font-size: 14px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The screen's room: whatever the bar and the pad leave. */
.play-modal-stage {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.play-modal-stage canvas {
  display: block;
  image-rendering: pixelated;
  background: #000;
  touch-action: none;
}

.play-info {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}

/* The title and, at the far end of its line, the star: a star on the game as
   a whole, which is what it is, rather than one more button in the row of
   things you can do to it. The star keeps its size while a long title wraps
   under it. */
.play-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.play-star {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
}

.play-title {
  min-width: 0;
  font-size: 24px;
  font-weight: normal;
  letter-spacing: 0.04em;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.play-by {
  gap: 8px;
  font-size: 14px;
  opacity: 0.8;
  align-self: flex-start;
}

.by-pic {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
}

.play-desc {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  line-height: 1.6;
  opacity: 0.9;
}

.play-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 8px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.like-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* The Like button and, under it, the line saying who gets to see a like. */
.like-col {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* Said under a control whose effect everyone can see: the like button, the
   comment box. Small and quiet — it is a caption, not a warning. */
.public-note {
  margin: 0;
  font-size: 12px;
}

/* The two things you can do with the address of a game: hand it to the app
   on this machine, or hand it to someone else. */
.play-links {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.like {
  padding: 6px 14px;
  background: transparent;
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 4px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}

.like:hover:not(:disabled) {
  border-color: var(--light);
}

.like.liked {
  border-color: var(--red);
}

.like .heart {
  color: var(--red);
}

.like-count {
  font-size: 14px;
  opacity: 0.75;
}

/* The star: Font Awesome's star, the outline until it is given and the
   solid one after — the same two files the desktop app draws its star with
   (editor/assets/icons) — tinted through a mask so it takes the gold of
   whatever it sits in. */
.star-icon {
  display: inline-block;
  width: 15px;
  height: 15px;
  vertical-align: -2px;
  background: currentColor;
  -webkit-mask: url(/assets/star-regular-full.d81bb5437b919c60777a.svg) center / contain no-repeat;
  mask: url(/assets/star-regular-full.d81bb5437b919c60777a.svg) center / contain no-repeat;
}

.star-icon.solid {
  -webkit-mask-image: url(/assets/star-solid-full.ac0e2f1d36e3e055072d.svg);
  mask-image: url(/assets/star-solid-full.ac0e2f1d36e3e055072d.svg);
}

/* The two totals under the byline (play.js statsLine): plays behind Font
   Awesome's play triangle — the same file the desktop app draws its Run
   button with — and stars behind the solid star, both in the byline's quiet
   voice: facts about the game, not things to do to it. */
.play-stats {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin: 0;
  font-size: 14px;
}

.play-stat {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.play-stat .star-icon,
.play-stat .play-icon {
  width: 13px;
  height: 13px;
  vertical-align: 0;
}

.play-icon {
  display: inline-block;
  background: currentColor;
  -webkit-mask: url(/assets/play-solid-full.3dbed1b1661eea27be04.svg) center / contain no-repeat;
  mask: url(/assets/play-solid-full.3dbed1b1661eea27be04.svg) center / contain no-repeat;
}

/* The Star button, beside the title on a game's page: the Like button's
   shape, gold where that one is red. */
.star {
  padding: 6px 14px;
  background: transparent;
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 4px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}

.star:hover:not(:disabled) {
  border-color: var(--light);
}

.star.starred {
  border-color: var(--gold);
}

.star .star-icon {
  color: var(--gold);
}

/* ---- Starred Games (starred.js) ----
   The signed-in account's own shelf, drawn like every other. The star on a
   card sits over the thumbnail's top-right corner and takes the game off the
   shelf; the card is the page's usual card, positioned so the star has a
   corner to sit in. */

.shelf.starred {
  padding-top: 32px;
}

.shelf.starred .shelf-title .star-icon {
  width: 17px;
  height: 17px;
  vertical-align: -2px;
}

.shelf.starred .card {
  position: relative;
}

.card-star {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  background: rgba(15, 18, 36, 0.7);
  color: var(--gold);
  border: 1px solid transparent;
  border-radius: 50%;
  cursor: pointer;
}

.card-star:hover:not(:disabled) {
  border-color: var(--light);
  color: var(--light);
}

.card-star:disabled {
  opacity: 0.5;
  cursor: default;
}

/* The high-score table (play.js scoresPanel): a title line that folds the
   table under it away, and, folded, says who is on top. */
.scores {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.scores-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.scores-title {
  font-size: 16px;
  font-weight: normal;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.8;
  margin: 0;
}

.scores-head:hover .scores-title {
  opacity: 1;
}

/* The chevron points down at the table, or right at where it was. */
.scores-head .chevron {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin: 0 4px 2px 2px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  opacity: 0.8;
  transition: transform 120ms ease;
}

.scores.closed .scores-head .chevron {
  transform: translateY(2px) rotate(-45deg);
}

.scores-summary {
  margin-left: auto;
  font-size: 14px;
  opacity: 0.7;
}

.scores.closed .scores-body {
  display: none;
}

.scores-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.scores-list {
  list-style: none;
  margin: 0;
  padding: 2px 12px;
  max-height: 232px;
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 14px;
}

.scores-list:empty {
  display: none;
}

.score {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
  border-top: 1px solid var(--line);
}

.score:first-child {
  border-top: 0;
}

.score-rank {
  flex: none;
  width: 2.2em;
  text-align: right;
  opacity: 0.6;
  font-variant-numeric: tabular-nums;
}

.score-pic {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--stone);
  display: block;
}

.score-who {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: inherit;
  text-decoration: none;
}

a.score-who:hover {
  text-decoration: underline;
}

.score-value {
  flex: none;
  font-variant-numeric: tabular-nums;
}

.score.mine .score-who,
.score.mine .score-value {
  color: var(--gold);
}

/* The caller's own row when it did not make the board: at the foot, set
   off from the list above it, with the rank's column empty. */
.score.unranked {
  border-top: 1px dashed var(--stone);
}

/* Taking your own score off the table: a small × at the end of your row,
   and in its place, once pressed, the question and its two answers — on
   the row itself, never a browser dialog. */
.score-delete {
  flex: none;
  width: 22px;
  height: 22px;
  padding: 0;
  margin-left: 2px;
  background: transparent;
  color: var(--light);
  border: 1px solid transparent;
  border-radius: 4px;
  font: inherit;
  font-size: 16px;
  line-height: 1;
  opacity: 0.5;
  cursor: pointer;
}

.score-delete:hover {
  opacity: 1;
  border-color: var(--stone);
}

/* The question takes a line of its own under the row rather than squeezing
   the name out beside the score. */
.score-confirm {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  padding-bottom: 2px;
  font-size: 13px;
  white-space: nowrap;
}

.score-confirm-btn {
  padding: 2px 8px;
  background: transparent;
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 4px;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

.score-confirm-btn:hover {
  border-color: var(--light);
}

.score-delete-wait {
  flex: none;
  font-size: 13px;
}

.scores-note,
.scores-mine {
  margin: 0;
  font-size: 14px;
}

.comments {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.comments-title {
  font-size: 16px;
  font-weight: normal;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.8;
}

.comments-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.comment {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.comment-pic {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--stone);
  flex: none;
}

/* The picture links to its author's profile, so the anchor around it is what
   the comment row lays out. */
.comment > a {
  flex: none;
  line-height: 0;
}

.comment-body {
  min-width: 0;
  flex: 1;
}

.comment-head {
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 13px;
}

.comment-name {
  font-weight: bold;
}

/* A name that is a link: it reads as the name until the pointer is on it. */
.user-link {
  color: inherit;
  text-decoration: none;
}

.user-link:hover {
  text-decoration: underline;
}

.comment-time {
  font-size: 12px;
}

.comment-text {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-size: 14px;
  line-height: 1.5;
  margin: 2px 0;
}

.comment-reply {
  padding: 2px 8px;
  font-size: 12px;
}

.comments-foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.comments-note {
  font-size: 14px;
}

.composer {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.comment-input {
  width: 100%;
  padding: 10px 12px;
  background: transparent;
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 4px;
  font: inherit;
  font-size: 14px;
  resize: vertical;
  outline: none;
}

.comment-input:focus {
  border-color: var(--light);
}

.composer-row {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
}

.composer-row .error {
  font-size: 13px;
}

/* A comment's screenshot with its stickers is shared/screenshot.css's
   (.ss-shot-box); here only its place in the comment. */
.comment-body .ss-shot-box {
  margin-top: 6px;
}

/* ---- Dialogs ---- */

.backdrop {
  position: fixed;
  inset: 0;
  z-index: 10;
  background: rgba(15, 18, 36, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.dialog {
  width: 100%;
  max-width: 460px;
  background: var(--void);
  border: 1px solid var(--stone);
  border-radius: 8px;
  padding: 20px 22px 22px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
}

.dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.dialog-head h2 {
  font-size: 18px;
  font-weight: normal;
  letter-spacing: 0.06em;
}

.dialog-head .ghost {
  font-size: 20px;
  padding: 0 8px;
  line-height: 1;
}

.dialog form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.field-row {
  display: flex;
  gap: 8px;
}

.field-row input {
  flex: 1;
  min-width: 0;
  padding: 10px 12px;
  background: transparent;
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 4px;
  font: inherit;
  outline: none;
}

.field-row input:focus {
  border-color: var(--light);
}

/* Each of the two ways in: the invitation you have, or the one to ask for. */
.dialog .branch {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.dialog .branch h3 {
  font-size: 15px;
  font-weight: normal;
  letter-spacing: 0.06em;
}

/* Everything under a heading is the answer to it, and sits in from it. A
   branch with no heading (a phone's, which has only the one way in) does not
   indent, so it stays flush with the line above it. */
.dialog .branch h3 ~ p,
.dialog .branch h3 ~ form {
  padding-left: 14px;
}

.dialog .branch > p {
  font-size: 14px;
  line-height: 1.5;
  opacity: 0.8;
}

.dialog .branch a {
  color: var(--light);
  text-decoration: underline;
}

.dialog .aside {
  opacity: 0.6;
}

.dialog .ok {
  font-size: 14px;
}

.dialog .error {
  font-size: 14px;
}

/* ---- The legal pages ---- */

.legal {
  max-width: 720px;
  padding: 32px 0 40px;
  line-height: 1.6;
  font-size: 15px;
}

.legal h1 {
  font-size: 26px;
  font-weight: normal;
  letter-spacing: 0.06em;
  margin: 16px 0 8px;
}

.legal h2 {
  font-size: 19px;
  font-weight: normal;
  letter-spacing: 0.04em;
  color: var(--gold);
  margin: 32px 0 10px;
}

.legal h3 {
  font-size: 16px;
  font-weight: bold;
  margin: 22px 0 8px;
}

.legal h4 {
  font-size: 15px;
  font-weight: bold;
  margin: 16px 0 6px;
}

.legal p {
  margin: 0 0 14px;
}

.legal ul,
.legal ol {
  margin: 0 0 14px;
  padding-left: 28px;
}

.legal li {
  margin-bottom: 6px;
}

.legal li p {
  margin-bottom: 6px;
}

.legal a {
  color: var(--light);
}

.legal .table-wrap,
.legal table {
  max-width: 100%;
}

.legal table {
  border-collapse: collapse;
  margin: 0 0 18px;
  font-size: 13px;
  display: block;
  overflow-x: auto;
}

.legal th,
.legal td {
  border: 1px solid var(--line);
  padding: 8px 10px;
  vertical-align: top;
  text-align: left;
}

.legal th {
  background: var(--card);
  font-weight: bold;
}

.legal-thanks {
  margin-top: 32px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  opacity: 0.7;
}

/* ---- A user's page (profile.js) ----
   The person at the top — their face, their name, and the two facts worth
   saying about them — and their games under it on the same shelf the front
   page uses, so a profile reads as one more shelf of Thing8 rather than a
   different kind of page. */

.profile {
  padding: 32px 0 8px;
}

.profile-head {
  display: flex;
  align-items: center;
  gap: 20px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}

.profile-pic {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--card);
  flex: none;
}

.profile-who {
  min-width: 0;
}

.profile-uname {
  font-size: 26px;
  font-weight: normal;
  letter-spacing: 0.04em;
  overflow-wrap: anywhere;
}

.profile-meta {
  margin-top: 6px;
  font-size: 14px;
}

@media (max-width: 720px) {
  .profile-head {
    gap: 14px;
  }

  .profile-pic {
    width: 64px;
    height: 64px;
  }

  .profile-uname {
    font-size: 20px;
  }
}

/* ---- Data Transparency (data-transparency.js) ---- */

.transparency .dt-item {
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.transparency .dt-item h2 {
  margin-top: 0;
}

.dt-facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 14px;
  font-size: 14px;
}

.dt-facts dt {
  opacity: 0.6;
  white-space: nowrap;
}

.dt-facts dd {
  margin: 0;
}

.dt-fields summary {
  cursor: pointer;
  font-size: 14px;
  opacity: 0.8;
}

.dt-fields summary:hover {
  opacity: 1;
}

.dt-fields table {
  border-collapse: collapse;
  margin-top: 8px;
  font-size: 13px;
  width: 100%;
}

.dt-fields th,
.dt-fields td {
  border: 1px solid var(--line);
  padding: 6px 8px;
  vertical-align: top;
  text-align: left;
  font-weight: normal;
}

.dt-fields th {
  white-space: nowrap;
  background: var(--card);
}

.dt-export {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  padding-top: 6px;
  border-top: 1px solid var(--line);
  font-size: 14px;
}

.dt-export label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.dt-export input,
.dt-export select,
.st-row select {
  padding: 5px 8px;
  background: transparent;
  color: var(--light);
  border: 1px solid var(--stone);
  border-radius: 4px;
  font: inherit;
  font-size: 14px;
  color-scheme: dark;
}

.dt-export input:focus,
.dt-export select:focus,
.st-row select:focus {
  border-color: var(--light);
  outline: none;
}

.dt-export select option {
  color: var(--void);
}

.dt-export .dt-single {
  margin: 0;
}

.dt-export .dt-status {
  flex-basis: 100%;
  margin: 0;
  font-size: 13px;
}

.dt-export .dt-status.ok {
  opacity: 0.8;
}

.dt-request-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* The account's Cookies and Privacy settings: three choices, each with its
   state called out at the start of the line so the whole set reads down the
   left edge without having to be read through. Boxed like a .dt-item, since
   it sits in that list's rhythm, but it lists choices rather than data. */
.dt-settings {
  display: flex;
  flex-direction: column;
  gap: 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 16px 18px;
}

.dt-setting {
  display: flex;
  align-items: baseline;
  gap: 12px;
}

/* One width for both words, so the names line up whatever the states are. */
.dt-setting-state {
  flex: none;
  width: 3.5em;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.dt-setting-state.on {
  color: var(--gold);
}

.dt-setting-state.off {
  opacity: 0.5;
}

.dt-setting-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.dt-setting-desc {
  font-size: 14px;
}

/* A ghost button's border is transparent until hover, so its padding would
   indent the label away from the margin every other line on the page starts
   on. The padding bleeds to the left instead: the label lines up, and the
   button keeps its target and its hover box. */
.dt-settings-manage, .st-manage {
  display: flex;
  margin-left: -14px;
}

/* ---- Settings (settings.js) ---- */

/* The account's settings, one row each: the name, the control, what it
   does, and — when a save is refused — why. */
.st-rows {
  display: flex;
  flex-direction: column;
  gap: 16px;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 16px 18px;
}

.st-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

.st-desc, .st-status {
  font-size: 14px;
}

/* A setting that is a box: the whole line is the target, like the Create
   Account screen's boxes. */
.st-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  line-height: 1.4;
  cursor: pointer;
}

.st-check input {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  padding: 0;
  accent-color: var(--light);
  cursor: pointer;
}

.st-who {
  font-size: 14px;
  font-weight: normal;
}

/* The profile picture row: the face as it is worn, and the button that
   changes it (settings.js, crop.js). */
.st-pic {
  display: flex;
  align-items: center;
  gap: 14px;
}

.st-pic-face {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--card);
  border: 2px solid var(--stone);
  flex: none;
}

/* ---- The crop dialog (crop.js) ---- */

/* Over everything, the shell's own dialogs included. */
.crop-backdrop {
  z-index: 20;
}

.crop-dialog {
  max-width: 360px;
  align-items: center;
}

.crop-dialog .dialog-head {
  align-self: stretch;
}

.crop-hint {
  font-size: 14px;
  margin: 0;
  text-align: center;
}

/* The frame: a square the picture is dragged around in. touch-action off,
   so a finger on it moves the picture and not the page. */
.crop-stage {
  width: 280px;
  max-width: 100%;
  aspect-ratio: 1;
  border-radius: 6px;
  overflow: hidden;
  background: var(--card);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  line-height: 0;
}

.crop-stage canvas {
  cursor: grab;
  display: block;
  max-width: 100%;
}

.crop-stage canvas:active {
  cursor: grabbing;
}

.crop-zoom {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 280px;
  max-width: 100%;
  font-size: 14px;
}

.crop-zoom input {
  flex: 1;
  min-width: 0;
  accent-color: var(--light);
}

.crop-buttons {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
  align-self: stretch;
}

@media (max-width: 480px) {
  .dt-facts {
    grid-template-columns: 1fr;
    gap: 2px;
  }

  .dt-facts dd {
    margin-bottom: 6px;
  }
}

/* ---- Cookies and Privacy (cookies.js) ----
   The Cookies popup and the settings dialog sit in the page's dialog frame;
   the GPC banner runs along the bottom of the window. */

.cookie-buttons {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
}

.cookie-scope {
  font-size: 14px;
}

/* The line a GPC browser gets instead of controls that work. */
.cookie-locked {
  padding: 10px 12px;
  border: 1px solid var(--gold);
  border-radius: 4px;
  font-size: 14px;
}

.cookie-rows {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* A row is one choice: its control, then its name and a line about it. The
   whole row is the target, as on the Create Account screen. */
.cookie-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  line-height: 1.4;
  cursor: pointer;
}

.cookie-row input {
  flex: none;
  width: 16px;
  height: 16px;
  margin: 3px 0 0;
  padding: 0;
  accent-color: var(--light);
  cursor: pointer;
}

.cookie-row input:disabled {
  opacity: 0.5;
  cursor: default;
}

.cookie-row-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 14px;
}

.cookie-row-desc {
  font-size: 13px;
}

/* The opt-out is a switch rather than a box: a request rather than a cookie
   category. Drawn by hand so it takes the palette. */
.cookie-row input.switch {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  width: 36px;
  height: 20px;
  margin-top: 1px;
  border: 1px solid var(--stone);
  border-radius: 10px;
  background: transparent;
}

.cookie-row input.switch::before {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--stone);
  transition: left 0.15s, background 0.15s;
}

.cookie-row input.switch:checked {
  border-color: var(--leaf);
}

.cookie-row input.switch:checked::before {
  left: 18px;
  background: var(--leaf);
}

.cookie-row input.switch:focus-visible {
  outline: 2px solid var(--light);
  outline-offset: 2px;
}

.gpc-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  padding: 10px 20px;
  background: var(--void);
  border-top: 1px solid var(--gold);
  font-size: 14px;
}

/* The words take the room, and the buttons sit at the right end while there
   is room for them there. */
.gpc-banner > span:first-child {
  flex: 1 1 480px;
}

/* The account one only says which settings apply: quieter. */
.gpc-banner.subtle {
  border-top-color: var(--line);
  opacity: 0.85;
  font-size: 13px;
}

.gpc-banner-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
}

.gpc-banner-actions #gpc-dismiss {
  font-size: 20px;
  padding: 0 8px;
  line-height: 1;
}

/* ---- The Asset Library (ASSET-LIBRARY.md; library.js, pack.js) ---- */

/* The library: one left column of tabs, and beside it the search box and
   whatever shelf is up. On a phone the column becomes a row of pills over
   the shelves. */
.library {
  display: flex;
  gap: 28px;
  align-items: flex-start;
  padding-top: 8px;
}

.library-side {
  flex: none;
  width: 180px;
  position: sticky;
  top: 16px;
}

.library-tabs {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.library-tab {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: transparent;
  color: var(--light);
  border: 1px solid transparent;
  border-radius: 6px;
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
  opacity: 0.8;
}

.library-tab:hover {
  opacity: 1;
  background: rgba(238, 243, 246, 0.06);
}

.library-tab.on {
  opacity: 1;
  border-color: var(--line);
  background: var(--card);
  color: var(--gold);
}

.library-tab-emoji {
  width: 22px;
  text-align: center;
  font-size: 16px;
}

.library-config-error {
  margin-top: 10px;
  font-size: 12px;
}

.library-main {
  flex: 1;
  min-width: 0;
}

.library-search {
  display: flex;
  gap: 8px;
}

.library-search input {
  flex: 1;
  min-width: 0;
  padding: 8px 12px;
  background: var(--void);
  color: var(--light);
  border: 1px solid var(--line);
  border-radius: 6px;
  font: inherit;
  font-size: 14px;
}

.library-heading {
  margin: 24px 0 -8px;
  font-size: 22px;
  font-weight: normal;
  letter-spacing: 0.04em;
}

.library-body .shelf:first-child {
  padding-top: 20px;
}

@media (max-width: 720px) {
  .library {
    flex-direction: column;
    gap: 16px;
  }

  .library-side {
    width: auto;
    position: static;
  }

  .library-tabs {
    flex-direction: row;
    flex-wrap: wrap;
  }
}

/* A pack's card: the game card with the count badges where a game's counts
   go, and a TEMPLATE tag on a game template's picture. */
.pack-card {
  position: relative;
}

.pack-card .card-thumb {
  position: relative;
}

.pack-tag {
  position: absolute;
  top: 8px;
  left: 8px;
  padding: 3px 6px;
  background: var(--gold);
  color: var(--void);
  border-radius: 3px;
  font-size: 10px;
  letter-spacing: 0.08em;
  line-height: 1;
}

.pack-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 4px 12px 8px;
}

.pack-badge {
  padding: 2px 7px;
  border: 1px solid var(--line);
  border-radius: 10px;
  font-size: 11px;
  opacity: 0.8;
  white-space: nowrap;
}

/* The pack's page: the thumbnail large beside the listing, the play page's
   info column reused for the right-hand side. */
.pack-back {
  margin: 8px 0 16px;
  font-size: 14px;
}

.pack-top {
  display: flex;
  gap: 32px;
  align-items: flex-start;
}

.pack-shot {
  position: relative;
  flex: none;
  width: min(512px, 45vw);
  aspect-ratio: 256 / 240;
  background: var(--void);
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  line-height: 0;
}

.pack-shot img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
}

.pack-shot .pack-tag {
  top: 12px;
  left: 12px;
  font-size: 12px;
}

.pack-info {
  flex: 1;
}

.pack-info .pack-badges {
  padding: 0;
}

.pack-what {
  font-size: 14px;
}

.pack-app-note {
  font-size: 13px;
  line-height: 1.5;
}

@media (max-width: 720px) {
  .pack-top {
    flex-direction: column;
    gap: 16px;
  }

  .pack-shot {
    width: 100%;
  }
}

/* The credits under a game's or a pack's description (pack.js
   creditsMarkup): the author's acknowledgements, and apart from them, under
   their own line, the packs the server found the assets in. */
.credits {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 14px;
  line-height: 1.5;
}

.credit-link {
  color: var(--light);
}

.credits-matches {
  padding-top: 6px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.credits-matches p {
  margin: 0;
  font-size: 13px;
}

.comment-shot img {
  max-width: 256px;
  width: 100%;
  height: auto;
  image-rendering: pixelated;
  border: 1px solid var(--line);
  border-radius: 4px;
}

/* Octoplex (octoplex.js), the internal admin console: an 80s terminal, on
   the console's own Void, in the console's own typeface. Everything here is
   prefixed `ox-` and nothing else on the site uses it.

   The rules of the look, so additions keep to them: square corners, one
   pixel of Stone for every border, labels in caps, and no color that is not
   one of the sixteen (styles.css already names Void, Light, Red, Leaf and
   Stone; the three below are the rest of what this page needs). */

:root {
  --ox-sky:   #79d9f6; /* PALETTE[10] — links, the current tab, what is live */
  --ox-gold:  #f8da62; /* PALETTE[4]  — a notice, a featured game */
  --ox-line:  rgba(129, 145, 167, 0.35); /* Stone, quieted, for rules */
  --ox-panel: rgba(129, 145, 167, 0.08);
}

.ox {
  min-height: 100vh;
  padding: 20px 24px 64px;
  font-size: 13px;
  line-height: 1.45;
}

/* ---- the top ---- */

.ox-top {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--ox-line);
}

.ox-mark {
  font-size: 26px;
  font-weight: normal;
  letter-spacing: 0.22em;
  color: #fff;
  text-shadow: 0 0 14px rgba(255, 255, 255, 0.35);
}

/* The sixteen colors, beside the name — the console's whole palette, and the
   only ornament on the page. */
.ox-palette {
  display: flex;
  gap: 2px;
}

.ox-palette span {
  width: 12px;
  height: 12px;
  /* An outline in Light rather than in Void: the first of the sixteen *is*
     Void, and a square the same color as the page is not a square. */
  border: 1px solid rgba(238, 243, 246, 0.28);
}

.ox-who {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 14px;
  color: var(--stone);
  letter-spacing: 0.06em;
}

.ox-who a {
  color: var(--ox-sky);
  text-decoration: none;
  letter-spacing: 0.12em;
}

.ox-who a:hover {
  text-decoration: underline;
}

/* ---- tabs ---- */

.ox-tabs {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 0;
}

.ox-tabs button {
  padding: 5px 16px;
  letter-spacing: 0.14em;
}

.ox-tabs button.on {
  background: var(--ox-sky);
  color: var(--void);
  border-color: var(--ox-sky);
}

.ox-roles {
  margin-left: auto;
  color: var(--stone);
  font-size: 11px;
  letter-spacing: 0.08em;
}

/* ---- controls ---- */

.ox button,
.ox input,
.ox select {
  font: inherit;
  color: var(--light);
  background: transparent;
  border: 1px solid var(--stone);
  border-radius: 0;
  padding: 4px 10px;
  outline: none;
}

.ox button {
  cursor: pointer;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.ox button:hover:not(:disabled),
.ox input:focus,
.ox select:focus {
  border-color: var(--light);
}

.ox button:disabled {
  opacity: 0.35;
  cursor: default;
}

.ox button.ox-danger,
.ox .ox-danger {
  color: var(--red);
  border-color: rgba(231, 39, 52, 0.6);
}

.ox button.ox-danger:hover:not(:disabled) {
  border-color: var(--red);
}

.ox-controls {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.ox-search {
  display: flex;
  gap: 6px;
}

.ox-sorts {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--stone);
  letter-spacing: 0.1em;
}

.ox-sorts button.on {
  color: var(--ox-sky);
  border-color: var(--ox-sky);
}

.ox-action {
  margin-left: auto;
}

.ox-actions {
  display: flex;
  gap: 10px;
  margin: 14px 0;
}

.ox-actions .ox-action {
  margin-left: 0;
}

/* An inline form for an action that needs a word first — a number of cups, a
   reason. Deliberately not a browser dialog: those stop the page dead. */
.ox-panel {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 16px;
  padding: 12px 14px;
  background: var(--ox-panel);
  border: 1px solid var(--ox-line);
}

.ox-panel label {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--stone);
  letter-spacing: 0.1em;
}

.ox-panel-roles {
  gap: 6px;
}

.ox-panel-roles button.on {
  color: var(--ox-gold);
  border-color: rgba(248, 218, 98, 0.6);
}

.ox-hint {
  flex-basis: 100%;
  color: var(--stone);
  font-size: 11px;
}

/* ---- messages ---- */

.ox-busy {
  color: var(--ox-sky);
  letter-spacing: 0.2em;
  margin-bottom: 10px;
}

.ox-error {
  color: var(--red);
  margin-bottom: 12px;
}

.ox-notice {
  color: var(--leaf);
  margin-bottom: 12px;
}

.ox-empty {
  color: var(--stone);
  text-align: center;
  padding: 18px 0;
  letter-spacing: 0.12em;
}

/* ---- tables ---- */

.ox-table,
.ox-fields {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 14px;
}

.ox-table th,
.ox-fields th {
  text-align: left;
  font-weight: normal;
  color: var(--stone);
  letter-spacing: 0.12em;
}

.ox-table th {
  border-bottom: 1px solid var(--stone);
  padding: 6px 10px;
  white-space: nowrap;
}

.ox-table td,
.ox-fields td,
.ox-fields th {
  padding: 5px 10px;
  border-bottom: 1px solid var(--ox-line);
  vertical-align: top;
}

/* Every row of a listing opens the thing it names. */
.ox-table tbody tr[data-account],
.ox-table tbody tr[data-game],
.ox-table tbody tr[data-pack] {
  cursor: pointer;
}

.ox-table tbody tr[data-account]:hover,
.ox-table tbody tr[data-game]:hover,
.ox-table tbody tr[data-pack]:hover {
  background: var(--ox-panel);
}

.ox-num,
.ox-table th.ox-num {
  text-align: right;
}

.ox-id {
  color: var(--stone);
  font-size: 11px;
  word-break: break-all;
}

.ox-roles-cell {
  color: var(--ox-gold);
  font-size: 11px;
  letter-spacing: 0.06em;
}

/* A document dump: the field name in a narrow first column, the value as it
   is stored, however long that turns out to be. */
.ox-fields th {
  width: 210px;
  white-space: nowrap;
}

.ox-fields td {
  word-break: break-word;
}

.ox-pager {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--stone);
  letter-spacing: 0.1em;
  margin-bottom: 20px;
}

/* ---- detail views ---- */

.ox-back {
  margin-bottom: 14px;
}

.ox-detail-head {
  display: flex;
  align-items: center;
  gap: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--ox-line);
}

.ox-detail-head img {
  width: 64px;
  height: 64px;
  object-fit: cover;
  border: 1px solid var(--stone);
  flex: none;
}

.ox-detail-head .ox-thumb {
  width: 128px;
  height: 96px;
  image-rendering: pixelated;
}

.ox-detail-head h2 {
  font-size: 18px;
  font-weight: normal;
  letter-spacing: 0.08em;
}

.ox-subtabs {
  display: flex;
  gap: 8px;
  margin: 14px 0;
}

.ox-subtabs button.on {
  color: var(--ox-sky);
  border-color: var(--ox-sky);
}

.ox-h3 {
  font-size: 13px;
  font-weight: normal;
  letter-spacing: 0.2em;
  color: var(--stone);
  margin: 24px 0 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--ox-line);
}

.ox-comments {
  list-style: none;
}

.ox-comments li {
  padding: 10px 0;
  border-bottom: 1px solid var(--ox-line);
}

.ox-comment-head {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--stone);
  margin-bottom: 4px;
}

.ox-comment-head button {
  margin-left: auto;
  padding: 2px 8px;
  font-size: 11px;
}

/* ---- the way in, and the way it is refused ---- */

.ox-gate {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  text-align: center;
  padding: 24px;
}

.ox-gate .ox-mark {
  margin-bottom: 4px;
}

.ox-gate a,
.ox-gate button {
  color: var(--ox-sky);
  background: transparent;
  border: 1px solid var(--stone);
  border-radius: 0;
  padding: 6px 16px;
  font: inherit;
  letter-spacing: 0.12em;
  text-decoration: none;
  cursor: pointer;
}

/* The link into Octoplex, on the signed-in page. */
.octoplex-link {
  color: var(--ox-sky);
  letter-spacing: 0.16em;
  text-decoration: none;
  border: 1px solid var(--ox-sky);
  padding: 8px 18px;
}

.octoplex-link:hover {
  background: var(--ox-sky);
  color: var(--void);
}

/* A comment's screenshot, small, the way the crawler-cache and the game's
   thumbnail are shown: pixels as pixels. */
.ox-shot {
  display: inline-block;
  vertical-align: middle;
  width: 128px;
  height: 120px;
  image-rendering: pixelated;
  border: 1px solid currentColor;
}

/* The screenshot view (screenshot.js open) and a comment's screenshot with
   its stickers (shotElement / stickerLayer). Shared by the website's game
   page and the editor's player, and loaded by both, so the view is one thing
   on the two. The colours are the console's palette rather than either
   host's theme: the picture is the game's, and so is the frame around it. */

/* ---- A screenshot in a comment ---- */

/* The box keeps the screen's shape whatever width the list gives it, and is
   the container the stickers' size is measured against. */
.ss-shot-box {
  position: relative;
  width: 100%;
  max-width: 256px;
  aspect-ratio: 256 / 240;
  margin: 6px 0 4px;
  container-type: inline-size;
  background: #0f1224;
  border: 1px solid rgba(129, 145, 167, 0.5);
  border-radius: 4px;
  overflow: hidden;
  user-select: none;
  -webkit-user-select: none;
}

.ss-shot-img {
  display: block;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
}

/* The stickers over a picture: each at its place in percent of the picture,
   sized as a fraction of its width (STICKER_SIZE in screenshot.js), so they
   follow the picture at any size with no script. */
.ss-stickers {
  position: absolute;
  inset: 0;
  container-type: inline-size;
  pointer-events: none;
}

.ss-sticker {
  position: absolute;
  transform: translate(-50%, -50%);
  font-size: 12.5cqw;
  line-height: 1;
  white-space: nowrap;
  text-shadow: 0 1px 2px rgba(15, 18, 36, 0.6);
}

/* ---- The view ---- */

.ss-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  box-sizing: border-box;
  background: rgba(15, 18, 36, 0.86);
  color: #eef3f6;
  overflow: auto;
  touch-action: pan-y;
  -webkit-tap-highlight-color: transparent;
}

.ss-panel {
  width: min(100%, 560px);
  max-height: 100%;
  overflow-y: auto;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px 16px;
  background: #0f1224;
  border: 1px solid #8191a7;
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
  font-size: 14px;
  line-height: 1.4;
}

.ss-panel * {
  box-sizing: border-box;
}

.ss-title {
  font-size: 15px;
  color: #f8da62;
}

/* The picture with the stickers being placed on it. It is the container
   the stickers are sized against, and every pointer on it is the view's. */
.ss-stage {
  position: relative;
  width: 100%;
  max-width: 480px;
  aspect-ratio: 256 / 240;
  margin: 0 auto;
  container-type: inline-size;
  background: #0f1224;
  border: 1px solid #8191a7;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  overflow: hidden;
}

.ss-shot {
  display: block;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
}

.ss-stage .ss-stickers {
  pointer-events: auto;
}

.ss-stage .ss-sticker {
  cursor: grab;
  padding: 2px;
  border-radius: 6px;
  border: 2px solid transparent;
}

.ss-stage .ss-sticker.selected {
  border-color: #f8da62;
}

/* The tray of stickers: one row, scrolling sideways where it does not fit. */
.ss-tray {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  padding: 2px 0 6px;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}

.ss-emoji {
  flex: none;
  font-size: 24px;
  line-height: 1;
  padding: 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  color: inherit;
  cursor: pointer;
}

.ss-emoji:hover:not(:disabled) {
  border-color: #8191a7;
  background: rgba(129, 145, 167, 0.15);
}

.ss-emoji:disabled {
  opacity: 0.35;
  cursor: default;
}

.ss-tray-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  color: #8191a7;
}

.ss-hint {
  flex: 1;
  min-width: 0;
}

.ss-count {
  font-variant-numeric: tabular-nums;
}

.ss-text {
  width: 100%;
  min-height: 56px;
  padding: 8px 10px;
  background: transparent;
  color: inherit;
  border: 1px solid #8191a7;
  border-radius: 6px;
  font: inherit;
  font-size: 14px;
  line-height: 1.4;
  resize: vertical;
  outline: none;
}

.ss-text:focus {
  border-color: #eef3f6;
}

.ss-note {
  margin: 0;
  font-size: 12px;
  color: #8191a7;
}

.ss-error {
  display: none;
  font-size: 13px;
  color: #e72734;
}

.ss-error.shown {
  display: block;
}

.ss-buttons {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}

.ss-btn {
  padding: 8px 16px;
  min-height: 36px;
  background: transparent;
  color: #eef3f6;
  border: 1px solid #8191a7;
  border-radius: 8px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}

.ss-btn:hover:not(:disabled) {
  border-color: #eef3f6;
}

.ss-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.ss-btn.primary {
  background: #f8da62;
  color: #0f1224;
  border-color: #f8da62;
}

.ss-btn.primary:hover:not(:disabled) {
  background: #fbe58a;
}

.ss-btn.ss-small {
  min-height: 28px;
  padding: 3px 10px;
  font-size: 12px;
}

/* ---- Cover mode: the cover the project has beside the new picture ---- */

.ss-compare {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 4px 0;
}

.ss-side {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 224px;
  max-width: 100%;
}

.ss-label {
  font-size: 12px;
  color: #8191a7;
}

.ss-side-img {
  display: block;
  width: 100%;
  aspect-ratio: 256 / 240;
  image-rendering: pixelated;
  background: #0f1224;
  border: 1px solid #8191a7;
}

.ss-after .ss-side-img {
  border-color: #f8da62;
}

.ss-none {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #8191a7;
  border-style: dashed;
  font-size: 13px;
}

.ss-arrow {
  font-size: 24px;
  color: #8191a7;
}

@media (max-width: 520px) {
  .ss-arrow {
    transform: rotate(90deg);
  }
}


/*# sourceMappingURL=main.ee0ae1dae65e99455905.css.map*/