/* The gelato die: a die of translucent cherry resin in a walnut tray lined with pistachio felt, on a white page. */
:root {
  --page: #ffffff;          /* the page */
  --ink: #2b1712;           /* the words, dark chocolate */
  --muted: #8a756b;
  --resin: #b8001f;         /* the die: cherry resin, seen through */
  --pip: #fff8f0;           /* the paint in the pips */
  --felt: #d5e0b2;          /* the felt the die lands on */
  --wood: #6e4631;          /* the walnut of the tray */
  --button: #2b1712;        /* Roll */
  --w: min(340px, calc(100vw - 48px));   /* the game's width */
}

* {
  box-sizing: border-box;
}

html {
  touch-action: manipulation;
}

html,
body {
  margin: 0;
}

body {
  min-height: 100svh;
  background: var(--page);
  color: var(--ink);
  font-family: 'Bricolage Grotesque Variable', system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

.stage {
  min-height: 100svh;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  padding: 24px 16px;
}

.game {
  display: grid;
  justify-items: center;
  width: var(--w);
}

.game__head {
  margin-top: 10px;
  text-align: center;
}

.game__title {
  margin: 0;
  font-size: 30px;
  font-weight: 750;
  font-stretch: 86%;
  line-height: 1;
  letter-spacing: -0.02em;
}

.game__rule {
  text-wrap: balance;
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 15px;
  font-weight: 450;
}

/* ---------------------------------------------------------------- the tray, in 3D */
/* the tray is drawn in its own space: the floor is tipped back by the script, and the sides, the rim and the die
   stand on it. The point the eye looks through sits where the middle of the floor is */
.tray {
  --rim: 13px;
  --wall: 15px;
  --fw: calc(var(--w) * 0.9 - 2 * var(--rim));
  --fd: calc(var(--fw) * 0.6);
  --size: calc(var(--fw) * 0.205);
  --oy: 59%;
  position: relative;
  width: var(--w);
  height: calc(var(--w) * 0.65);
  perspective-origin: 50% var(--oy);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  cursor: grab;
}

.tray.is-held {
  cursor: grabbing;
}

/* without motion a tap on the tray rolls, there is nothing to pick up */
@media (prefers-reduced-motion: reduce) {
  .tray {
    cursor: pointer;
  }
}

.tray__world {
  position: absolute;
  left: 50%;
  top: var(--oy);
  width: var(--fw);
  height: var(--fd);
  margin: calc(var(--fd) / -2) 0 0 calc(var(--fw) / -2);
  transform-style: preserve-3d;
}

/* the felt: fibres from a little noise, and the shade of the back wall falling on it */
.tray__felt {
  position: absolute;
  inset: 0;
  border-radius: 3px;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.1' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.2 0 0 0 0 0.25 0 0 0 0 0.05 0 0 0 0.55 -0.2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23f)'/%3E%3C/svg%3E"),
    radial-gradient(ellipse 80% 70% at 42% 18%, rgba(255, 255, 236, 0.32), rgba(255, 255, 236, 0) 70%),
    var(--felt);
  box-shadow:
    inset 0 14px 16px -8px rgba(40, 52, 12, 0.42),
    inset 10px 0 14px -9px rgba(40, 52, 12, 0.3),
    inset -10px 0 14px -9px rgba(40, 52, 12, 0.22);
}

.tray__shadow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* the inner sides of the walnut, in the shade: the light is behind the tray */
.tray__side {
  position: absolute;
  background:
    linear-gradient(to bottom, rgba(0, 0, 0, 0.32), rgba(0, 0, 0, 0.12)),
    var(--wood);
}

.tray__side--back {
  left: 0;
  top: 0;
  width: var(--fw);
  height: var(--wall);
  transform-origin: 50% 0;
  transform: rotateX(90deg);
}

.tray__side--left,
.tray__side--right {
  top: 0;
  width: var(--wall);
  height: var(--fd);
  background:
    linear-gradient(to right, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.12)),
    var(--wood);
}

.tray__side--left {
  left: 0;
  transform-origin: 0 50%;
  transform: rotateY(-90deg);
}

.tray__side--right {
  right: 0;
  transform-origin: 100% 50%;
  transform: rotateY(90deg);
  background:
    linear-gradient(to left, rgba(0, 0, 0, 0.12), rgba(255, 255, 255, 0.06)),
    var(--wood);
}

/* the front of the tray, facing us: its top edge catches a line of light */
.tray__side--front {
  left: calc(var(--rim) * -1);
  top: calc(var(--fd) + var(--rim));
  width: calc(var(--fw) + 2 * var(--rim));
  height: var(--wall);
  border-radius: 0 0 5px 5px;
  transform-origin: 50% 0;
  transform: rotateX(90deg);
  background:
    linear-gradient(to top, rgba(255, 236, 214, 0.28), rgba(255, 236, 214, 0) 2px),
    linear-gradient(to top, rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.3)),
    var(--wood);
}

/* the top of the rim, lit from above, with the grain running along it */
.tray__rim {
  position: absolute;
  left: calc(var(--rim) * -1);
  top: calc(var(--rim) * -1);
  width: calc(var(--fw) + 2 * var(--rim));
  height: calc(var(--fd) + 2 * var(--rim));
  border: var(--rim) solid transparent;
  border-radius: 5px;
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.05) 0 1px, transparent 1px 7px, rgba(0, 0, 0, 0.05) 7px 8px, transparent 8px 13px) border-box,
    linear-gradient(to bottom, rgba(255, 240, 220, 0.22), rgba(255, 240, 220, 0.04)) border-box,
    var(--wood) border-box;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  box-shadow: inset 0 0 0 1px rgba(255, 236, 214, 0.18);
  transform: translateZ(var(--wall));
}

/* the air over the tray, where the sprinkles fall: it reaches up above the tray, 140 px at most, but never past the
   top of the page (the game is about 550 px tall and sits in the middle of the screen) */
.tray__air {
  --air: clamp(10px, 50vh - 290px, 140px);
  position: absolute;
  left: 0;
  top: calc(var(--air) * -1);
  width: 100%;
  height: calc(100% + var(--air));
  pointer-events: none;
}

/* ---------------------------------------------------------------- the die */
/* six faces of tinted resin around a middle; the script turns and moves the die and, on every face, sets how much
   of the resin we look through (--a), the glow of the light through it (--glow) and the shine (--shine) */
.die {
  position: absolute;
  left: calc(50% - var(--size) / 2);
  top: calc(50% - var(--size) / 2);
  width: var(--size);
  height: var(--size);
  transform-style: preserve-3d;
  pointer-events: none;
}

.die__face {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 50% 50%, transparent 30%, color-mix(in srgb, color-mix(in srgb, var(--resin), #000000 68%) 30%, transparent)),
    color-mix(in srgb, var(--resin) calc(var(--a, 0.6) * 100%), transparent);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, color-mix(in srgb, var(--resin), #ffffff 55%) 80%, transparent),
    inset 0 0 0 2.5px color-mix(in srgb, color-mix(in srgb, var(--resin), #ffffff 30%) 25%, transparent);
}

.die__face[data-n='1'] {
  transform: translateZ(calc(var(--size) / 2));
}

.die__face[data-n='6'] {
  transform: rotateY(180deg) translateZ(calc(var(--size) / 2));
}

.die__face[data-n='2'] {
  transform: rotateY(90deg) translateZ(calc(var(--size) / 2));
}

.die__face[data-n='5'] {
  transform: rotateY(-90deg) translateZ(calc(var(--size) / 2));
}

.die__face[data-n='4'] {
  transform: rotateX(-90deg) translateZ(calc(var(--size) / 2));
}

.die__face[data-n='3'] {
  transform: rotateX(90deg) translateZ(calc(var(--size) / 2));
}

/* the glow of a face that the light behind the die comes through to the eye, and the shine of a face that
   sends the light straight to the eye */
.die__face::before,
.die__face::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}

.die__face::before {
  background: radial-gradient(circle at 50% 58%, color-mix(in srgb, var(--resin), #ffffff 22%), color-mix(in srgb, color-mix(in srgb, var(--resin), #ffffff 12%) 40%, transparent) 75%);
  opacity: calc(var(--glow, 0) * 0.3);
}

.die__face::after {
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(255, 255, 255, 0.18) 45%, rgba(255, 255, 255, 0) 70%);
  opacity: var(--shine, 0);
}

/* the pips: drilled and filled with paint, flush with the face */
.pip {
  position: absolute;
  width: 19%;
  height: 19%;
  border-radius: 50%;
  translate: -50% -50%;
  background: radial-gradient(circle at 42% 38%, var(--pip) 55%, #f0ddd2);
  box-shadow: 0 0 0 0.5px color-mix(in srgb, var(--resin) 40%, transparent);
  opacity: calc(1 - var(--far, 0) * 0.55);
}

/* ---------------------------------------------------------------- what each face gives */
.menu {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, max-content));
  justify-content: center;
  gap: 2px 18px;
  width: 100%;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}

.menu__item {
  position: relative;
  justify-self: start;
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  padding: 8px 10px;
  color: var(--ink);
  font-size: 15px;
  font-weight: 520;
  line-height: 1.1;
  isolation: isolate;
  transition: color 0.3s;
}

.menu__name {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* the little face beside each name, drawn */
.menu__face {
  flex: none;
  width: 20px;
  height: 20px;
  fill: currentColor;
}

.menu__face rect {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
}

/* the scoop of the flavour that came up, behind its name */
.menu__scoop {
  position: absolute;
  inset: -1px -2px;
  z-index: -1;
  width: calc(100% + 4px);
  height: calc(100% + 2px);
  fill: var(--scoop);
  opacity: 0;
  transform-origin: 30% 60%;
  overflow: visible;
}

/* the face that is free is written in the colour of the die */
.menu__item.is-jackpot {
  color: var(--resin);
  font-weight: 640;
}

.menu__item.is-won {
  color: var(--scoop-ink);
}

/* ---------------------------------------------------------------- Roll */
.roll {
  height: 52px;
  margin-top: 18px;
  padding: 0 34px;
  border: 0;
  border-radius: 999px;
  background: var(--button);
  color: #fff8f0;
  font: 650 17px/1 'Bricolage Grotesque Variable', system-ui, sans-serif;
  letter-spacing: 0.01em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: opacity 0.3s, background-color 0.2s, transform 0.16s ease-out;
}

.roll__label {
  display: inline-block;
}

@media (hover: hover) {
  .roll:hover {
    background: color-mix(in srgb, var(--button), #ffffff 14%);
  }

  .roll[aria-disabled='true']:hover {
    background: var(--button);
  }
}

.roll:active {
  transform: scale(0.96);
}

.roll[aria-disabled='true'] {
  opacity: 0.4;
  cursor: default;
}

.roll[aria-disabled='true']:active {
  transform: none;
}

.roll:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
}

html[data-using='pointer'] .roll:focus-visible {
  outline: none;
}

/* ---------------------------------------------------------------- what came up */
.result {
  min-height: 50px;
  margin-top: 14px;
  text-align: center;
}

.result__big {
  margin: 0;
  font-size: 19px;
  font-weight: 680;
  letter-spacing: -0.01em;
}

.result.is-hint .result__big {
  color: var(--muted);
  font-size: 15px;
  font-weight: 480;
}

.result__small {
  margin: 3px 0 0;
  min-height: 1.2em;
  color: var(--muted);
  font-size: 14px;
  font-weight: 450;
}

/* ---------------------------------------------------------------- short screens (the library's preview box, 341 × 410) */
/* everything in one screen: the tray takes its width from the height too, the lines are tighter, Roll and the result
   share a row, and the air over the tray reaches only as far as the top of the page */
@media (max-height: 520px) {
  :root {
    --w: min(340px, calc(100vw - 48px), calc((100vh - 230px) / 0.65));
  }

  .stage {
    padding: 10px 16px;
  }

  .game {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 14px;
    align-items: center;
  }

  .tray,
  .game__head,
  .menu {
    grid-column: 1 / -1;
  }

  .tray__air {
    top: -10px;
    height: calc(100% + 10px);
  }

  .game__head {
    margin-top: 4px;
  }

  .game__title {
    font-size: 24px;
  }

  .game__rule {
    margin-top: 4px;
    font-size: 13px;
  }

  .menu {
    margin-top: 4px;
  }

  .menu__item {
    padding: 4px 8px;
    font-size: 13px;
  }

  .menu__face {
    width: 16px;
    height: 16px;
  }

  .roll {
    justify-self: end;
    height: 40px;
    margin-top: 10px;
    padding: 0 22px;
    font-size: 15px;
  }

  .result {
    justify-self: start;
    min-height: 0;
    max-width: 15ch;
    margin-top: 10px;
    text-align: left;
  }

  .result__big {
    font-size: 16px;
  }

  .result.is-hint .result__big {
    font-size: 13px;
  }

  .result__small {
    min-height: 0;
    font-size: 12px;
  }
}
