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

html,
body {
  height: 100%;
  margin: 0;
}

/* No blue flash over whatever you tap on a phone; the TV, cases and discs react themselves. */
html {
  -webkit-tap-highlight-color: transparent;
}

body {
  overflow: hidden;
  background: #000;
  color: #e6edf3;
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}

/* The room: the TV screen fills the window, with its stand and DVD shelf just below.
   Tapping the screen pans the room up to bring the shelf into view. */
.room {
  --pan: 72%;
  position: fixed;
  inset: 0;
  transition: transform 0.9s cubic-bezier(0.65, 0, 0.25, 1);
}

.panned .room {
  transform: translateY(calc(-1 * var(--pan)));
}

main {
  position: absolute;
  inset: 0;
  cursor: pointer;
  overflow: hidden;
  background: #06080b;
}

/* CRT glass, above the logo: scanlines plus edge darkening that fakes a curved tube. */
main::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 55%, rgb(0 0 0 / 0.6) 100%),
    repeating-linear-gradient(to bottom, rgb(255 255 255 / 0.1) 0 2px, rgb(0 0 0 / 0.35) 2px 6px);
  box-shadow: inset 0 0 6vmin rgb(0 0 0 / 0.85);
}

/* Centered by default (no JS, or reduced motion); bounce.js takes over positioning. */
.logo {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: 0;
  width: clamp(140px, 30vw, 320px);
  line-height: 0;
  color: #00e5ff;
  transform: translate(-50%, -50%);
  /* Phosphor glow; the scanlines above cut through it like on a real tube. */
  filter: drop-shadow(0 0 8px color-mix(in srgb, currentColor 60%, transparent));
  transition: color 0.15s linear;
}

.logo svg {
  display: block;
  width: 100%;
  height: auto;
}

/* Set by bounce.js once it takes over positioning. */
.bouncing .logo {
  top: 0;
  left: 0;
  will-change: transform;
}

/* Turn-on for the plain CSS picture (no WebGL): a bright line opens into the picture.
   crt.js plays its own version in the shader. */
@media (prefers-reduced-motion: no-preference) {
  main {
    animation: tv-on 1.1s 0.25s both;
  }

  main::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background: #e6f7ff;
    animation: tv-on-glare 1.1s 0.25s both;
  }

  .crt-boot main,
  .crt-gl main,
  .crt-boot main::before,
  .crt-gl main::before {
    animation: none;
  }

  .crt-boot main::before,
  .crt-gl main::before {
    display: none;
  }
}

@keyframes tv-on {
  0% {
    clip-path: inset(50% 50%);
  }
  8% {
    clip-path: inset(calc(50% - 1px) calc(50% - 2px));
  }
  30% {
    clip-path: inset(calc(50% - 1px) 0);
    animation-timing-function: cubic-bezier(0.2, 0.7, 0.3, 1);
  }
  80%,
  100% {
    clip-path: inset(0);
  }
}

@keyframes tv-on-glare {
  0%,
  35% {
    opacity: 0.85;
  }
  100% {
    opacity: 0;
  }
}

/* The rare, glorious corner hit. */
.corner main {
  animation: corner-flash 1.2s ease-out;
}

@keyframes corner-flash {
  0% {
    background-color: #24282e;
  }
}

/* WebGL CRT (crt.js): the canvas draws the bent picture, so the DOM logo and
   CSS scanlines step aside. The logo stays in place for screen readers. */
.crt {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.crt-boot .logo,
.crt-gl .logo {
  opacity: 0;
}

.crt-boot main::after,
.crt-gl main::after {
  display: none;
}

/* Tap on the glass: a soft glint that rings out from the fingertip. */
.tap {
  position: absolute;
  z-index: 3;
  width: 180px;
  height: 180px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, rgb(230 247 255 / 0.45) 0 6%, rgb(230 247 255 / 0.12) 22%, transparent 62%);
  box-shadow: 0 0 0 1.5px rgb(230 247 255 / 0.35), inset 0 0 18px rgb(230 247 255 / 0.25);
  transform: translate(-50%, -50%) scale(0.15);
  animation: tap-ring 0.55s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}

@keyframes tap-ring {
  to {
    transform: translate(-50%, -50%) scale(1);
    opacity: 0;
  }
}

main:focus-visible {
  outline: 2px solid rgb(230 247 255 / 0.5);
  outline-offset: -6px;
}

/* What's playing from a DVD, drawn over the CRT canvas with the CSS glass on top. */
.disc-screen {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-content: center;
  gap: 1.2em;
  padding: 16px;
  text-align: center;
  background: radial-gradient(ellipse at center, color-mix(in srgb, var(--disc) 14%, #06080b), #06080b 70%);
  color: var(--disc);
}

.disc-screen[hidden] {
  display: none;
}

.disc-screen::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 55%, rgb(0 0 0 / 0.6) 100%),
    repeating-linear-gradient(to bottom, rgb(255 255 255 / 0.1) 0 2px, rgb(0 0 0 / 0.35) 2px 6px);
  box-shadow: inset 0 0 6vmin rgb(0 0 0 / 0.85);
}

.disc-title {
  margin: 0;
  font-size: clamp(2rem, 8vw, 5rem);
  font-style: italic;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-shadow: 0 0 12px color-mix(in srgb, currentColor 60%, transparent);
}

.disc-sub {
  margin: 0;
  color: #e6edf3;
  opacity: 0.8;
  font-size: clamp(0.9rem, 2.4vw, 1.2rem);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

@media (prefers-reduced-motion: no-preference) {
  .disc-screen.loading,
  .disc-app.loading {
    animation: tv-on 0.9s both;
  }

  .disc-sub {
    animation: blink 1.6s steps(1) infinite;
  }
}

@keyframes blink {
  50% {
    opacity: 0.25;
  }
}

/* With the WebGL screen running, disc screens bend like it (the filter is built in crt.js). */
.crt-gl .bend {
  filter: url(#crt-bend);
}

/* Disc III: a DVD menu filling the screen, with everyone's messages as glowing chapter
   tiles where they were posted (board.js). The menu and its tiles are the bent picture; the
   message being written, the hint and the Discs button sit flat on the glass above it. */
.board {
  position: absolute;
  inset: 0;
  z-index: 2;
  cursor: crosshair;
  color: #e6edf3;
}

.board[hidden] {
  display: none;
}

/* On the WebGL screen board.js draws the board into the CRT picture itself; the page board
   stays where it is, invisible, to take clicks and typing. */
.board.on-crt .board-picture,
.board.on-crt .board-desk,
.board.on-crt .board-hint {
  opacity: 0;
  filter: none;
}

.board-picture {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background:
    radial-gradient(ellipse at center, color-mix(in srgb, #a77bff 14%, #06080b), #06080b 75%);
}

/* The menu's title, in the corner like a DVD player's on-screen readout. */
.board-osd {
  position: absolute;
  top: max(18px, 4vmin);
  left: max(22px, 5vmin);
  margin: 0;
  color: #7dff3a;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-shadow: 0 0 8px rgb(125 255 58 / 0.6);
}

/* The same glass over the picture as the other disc screens. */
.board-picture::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 55%, rgb(0 0 0 / 0.6) 100%),
    repeating-linear-gradient(to bottom, rgb(255 255 255 / 0.06) 0 2px, rgb(0 0 0 / 0.22) 2px 6px);
  box-shadow: inset 0 0 6vmin rgb(0 0 0 / 0.85);
}

.board-notes,
.board-desk {
  position: absolute;
  inset: 0;
}

.board-desk {
  z-index: 4;
  pointer-events: none;
}

.board-desk > * {
  pointer-events: auto;
}

.board-hint {
  position: absolute;
  left: 50%;
  bottom: max(16px, 4vmin);
  z-index: 4;
  margin: 0;
  padding: 6px 12px;
  border-radius: 2px;
  background: rgb(0 0 0 / 0.55);
  color: #ffe53a;
  font-size: clamp(0.7rem, 1.8vw, 0.9rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-shadow: 0 0 8px rgb(255 229 58 / 0.5);
  white-space: nowrap;
  pointer-events: none;
  transform: translateX(-50%);
}

.board-hint:empty {
  display: none;
}

/* Back down to the shelf, on discs that play an app. */
.disc-app-shelf {
  position: absolute;
  top: max(16px, 4vmin);
  right: max(16px, 4vmin);
  z-index: 4;
  padding: 6px 12px;
  border: 0;
  border-radius: 4px;
  background: rgb(0 0 0 / 0.55);
  color: #e6edf3;
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
}

.disc-app-shelf:hover,
.disc-app-shelf:focus-visible {
  background: rgb(0 0 0 / 0.75);
}

/* A message: a chapter tile from a DVD's scene selection, outlined in its color. */
.note {
  --glow: #ffe53a;
  position: absolute;
  width: clamp(120px, 18vmin, 190px);
  min-height: clamp(70px, 10vmin, 110px);
  padding: 8px 10px 10px;
  border: 2px solid var(--glow);
  border-radius: 3px;
  background: rgb(6 8 11 / 0.82);
  box-shadow: 0 0 14px color-mix(in srgb, var(--glow) 45%, transparent), inset 0 0 12px color-mix(in srgb, var(--glow) 18%, transparent);
  color: #f2f6fa;
  font-size: clamp(0.75rem, 1.7vmin, 0.95rem);
  line-height: 1.35;
  text-shadow: 0 0 6px rgb(230 237 243 / 0.35);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  cursor: default;
  transform: translate(-50%, -50%);
}

/* "CH 07" across the top of the tile. */
.note[data-chapter]::before {
  content: "CH " attr(data-chapter);
  display: block;
  margin-bottom: 4px;
  color: var(--glow);
  font-size: 0.75em;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-shadow: 0 0 8px var(--glow);
  white-space: nowrap;
}

/* Paper colors from before, now the site's neon colors. */
.note-yellow { --glow: #ffe53a; }
.note-pink { --glow: #ff2bd6; }
.note-green { --glow: #7dff3a; }
.note-blue { --glow: #00e5ff; }

/* The message you're writing: a little bigger, with its controls. */
.note-draft {
  z-index: 1;
  display: grid;
  gap: 8px;
  width: clamp(180px, 26vmin, 240px);
  background: rgb(6 8 11 / 0.96);
}

.note-draft::before {
  content: "NEW CHAPTER";
  color: var(--glow);
  font-size: 0.75em;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-shadow: 0 0 8px var(--glow);
}

.note-draft textarea {
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-shadow: inherit;
  resize: none;
  outline: none;
}

.note-draft textarea::placeholder {
  color: rgb(230 237 243 / 0.45);
}

.note-tools,
.note-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.note-colors {
  display: flex;
  gap: 6px;
}

.note-swatch {
  width: 18px;
  height: 18px;
  padding: 0;
  border: 2px solid var(--glow);
  border-radius: 50%;
  background: color-mix(in srgb, var(--glow) 35%, #06080b);
  cursor: pointer;
}

.note-swatch[aria-checked="true"] {
  background: var(--glow);
  box-shadow: 0 0 8px var(--glow);
}

.note-count {
  font-size: 0.75em;
  opacity: 0.6;
  font-variant-numeric: tabular-nums;
}

.note-actions button {
  padding: 4px 10px;
  border: 0;
  border-radius: 2px;
  font: inherit;
  font-size: 0.85em;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
}

.note-cancel {
  background: transparent;
  color: inherit;
  opacity: 0.7;
}

.note-cancel:hover,
.note-cancel:focus-visible {
  opacity: 1;
}

/* A highlighted menu item. */
.note-pin {
  background: var(--glow);
  color: #06080b;
  box-shadow: 0 0 10px color-mix(in srgb, var(--glow) 60%, transparent);
}

.note-pin::before {
  content: "\25B6\FE0E\00a0";
}

.note-pin:disabled {
  opacity: 0.5;
  cursor: progress;
}

/* Disc II: Name the Clip (trivia.js). The clip plays through the CRT shader when it's
   running (the layer is then see-through to the canvas below); otherwise the <video>
   shows here, flat, under CSS scanlines. The controls sit flat on the glass. */
.trivia {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  padding: 16px;
  color: #e6edf3;
}

.trivia[hidden] {
  display: none;
}

.trivia-picture {
  position: absolute;
  inset: 0;
  background: #06080b;
}

.trivia-picture::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 55%, rgb(0 0 0 / 0.6) 100%),
    repeating-linear-gradient(to bottom, rgb(255 255 255 / 0.06) 0 2px, rgb(0 0 0 / 0.3) 2px 6px);
  box-shadow: inset 0 0 6vmin rgb(0 0 0 / 0.85);
}

.trivia-video {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* On the CRT the shader draws the clip, so the page layer steps aside. The video stays
   in the page (tiny and invisible) so it keeps decoding frames. */
.trivia.on-crt .trivia-picture {
  background: none;
}

.trivia.on-crt .trivia-picture::after {
  display: none;
}

.trivia.on-crt .trivia-video {
  position: absolute;
  width: 2px;
  height: 2px;
  opacity: 0;
  pointer-events: none;
}

.trivia-hud {
  position: absolute;
  top: max(16px, 4vmin);
  left: max(16px, 4vmin);
  z-index: 1;
  margin: 0;
  padding: 6px 12px;
  border-radius: 4px;
  background: rgb(0 0 0 / 0.55);
  color: #7dff3a;
  font-size: 0.85rem;
  letter-spacing: 0.08em;
}

.trivia-hud:empty {
  display: none;
}

.trivia-card {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: center;
  gap: 14px;
  width: min(440px, 100%);
  padding: 28px 22px;
  border: 1px solid rgb(125 255 58 / 0.35);
  border-radius: 8px;
  background: rgb(5 12 4 / 0.82);
  box-shadow: 0 0 30px rgb(125 255 58 / 0.15);
  text-align: center;
}

.trivia-card[hidden],
.trivia-guess[hidden],
.trivia [hidden] {
  display: none;
}

.trivia-card p {
  margin: 0;
  opacity: 0.85;
}

.trivia-title {
  margin: 0;
  color: #7dff3a;
  font-size: clamp(1.5rem, 5vw, 2.2rem);
  font-style: italic;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-shadow: 0 0 12px rgb(125 255 58 / 0.5);
}

/* The guess box rides along the bottom of the screen, under the clip. */
.trivia-guess {
  position: absolute;
  left: 50%;
  bottom: max(16px, 4vmin);
  z-index: 1;
  display: grid;
  gap: 8px;
  width: min(560px, calc(100% - 32px));
  padding: 12px;
  border-radius: 8px;
  background: rgb(0 0 0 / 0.7);
  transform: translateX(-50%);
}

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

.trivia-row input {
  flex: 1;
  min-width: 0;
  padding: 10px;
  border: 1px solid #30363d;
  border-radius: 4px;
  background: #0d1117;
  color: inherit;
  font: inherit;
}

.trivia-row input:focus {
  border-color: #7dff3a;
  outline: none;
}

.trivia button {
  padding: 8px 14px;
  border: 1px solid #30363d;
  border-radius: 4px;
  background: #161b22;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.trivia button:hover,
.trivia button:focus-visible {
  background: #21262d;
}

.trivia .trivia-primary {
  border-color: transparent;
  background: #7dff3a;
  color: #0b1a04;
  font-weight: 700;
}

.trivia .trivia-primary:hover,
.trivia .trivia-primary:focus-visible {
  background: #a4ff73;
}

.trivia .trivia-primary:disabled {
  opacity: 0.4;
  cursor: default;
}

.trivia-small button {
  padding: 4px 10px;
  font-size: 0.85rem;
}

.trivia .disc-app-shelf {
  padding: 6px 12px;
  border: 0;
  background: rgb(0 0 0 / 0.55);
  font-size: 0.85rem;
}

.trivia-feedback {
  min-height: 1.3em;
  margin: 0;
  font-weight: 700;
}

.trivia-feedback:empty {
  display: none;
}

.trivia-feedback.right {
  color: #7dff3a;
}

.trivia-feedback.wrong {
  color: #ff7b8a;
}

.trivia-feedback.gave-up {
  color: #ffe53a;
}

/* Disc IV: a private message to the site's owner (mail.js). The form is part of the bent
   picture, under the same glass as the other disc screens, so it reads as on the TV. */
.mail {
  position: absolute;
  inset: 0;
  z-index: 2;
  color: #e6edf3;
}

.mail[hidden] {
  display: none;
}

/* On the WebGL screen mail.js draws this screen into the CRT picture itself; the form stays
   where it is, invisible and unbent, to take clicks and typing. */
.mail.on-crt .mail-picture {
  opacity: 0;
  filter: none;
}

.mail-picture {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 16px 16px 64px;
  background:
    radial-gradient(ellipse at center, color-mix(in srgb, #00e5ff 16%, #06080b), #06080b 75%);
}

.mail-picture::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, transparent 55%, rgb(0 0 0 / 0.6) 100%),
    repeating-linear-gradient(to bottom, rgb(255 255 255 / 0.06) 0 2px, rgb(0 0 0 / 0.22) 2px 6px);
  box-shadow: inset 0 0 6vmin rgb(0 0 0 / 0.85);
}

/* Laid out like a DVD menu: glowing text straight on the screen, underlined fields, and a
   blinking ▶ beside whichever item is selected. */
.mail-form {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 18px;
  width: min(640px, 100%); /* room for the title with a logo either side */
  max-height: 100%;
  overflow-y: auto;
  padding: 8px 4px 8px 1.6em; /* room for the ▶ to hang out to the left */
  text-shadow: 0 0 6px rgb(230 237 243 / 0.35);
}

.mail-title {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 0.35em;
  margin: 0;
  color: #00e5ff;
  font-size: clamp(1.25rem, 5.4vw, 2.6rem); /* with a logo either side, still one line on a phone */
  font-style: italic;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-shadow: 0 0 14px rgb(0 229 255 / 0.6);
}

/* The MGM logo from the home screen, small, turning on each side of the title like a DVD
   menu's. Its top lines up with the top of the title's capitals. */
.mail-logo {
  display: block;
  flex: none;
  width: 2em;
  margin-top: var(--cap-top, 0.2em);
  line-height: 0;
  color: #ff2bd6;
  filter: drop-shadow(0 0 6px color-mix(in srgb, currentColor 60%, transparent));
  /* A new color each time it's side-on (every 2s, from 1s in), in the bouncing logo's order
     without its cyan, which the rest of the screen uses (as LOGO_COLORS in mail.js). */
  animation:
    mail-logo-turn 4s linear infinite,
    mail-logo-colors 12s 1s step-end infinite;
}

.mail-logo svg {
  display: block;
  width: 100%;
  height: auto;
}

@keyframes mail-logo-colors {
  0% { color: #7dff3a; }
  16.667% { color: #ffe53a; }
  33.333% { color: #ff7a1a; }
  50% { color: #a77bff; }
  66.667% { color: #ff3b5c; }
  83.333% { color: #ff2bd6; }
}

/* At its widest the logo is 90% of its full width (as LOGO_WIDTH in mail.js). */
@keyframes mail-logo-turn {
  from {
    transform: perspective(6em) rotateY(0deg) scaleX(0.9);
  }
  to {
    transform: perspective(6em) rotateY(360deg) scaleX(0.9);
  }
}

/* On the CRT screen the logos are drawn turning (mail.js); the invisible page copies hold
   still so their place can be measured. */
.mail.on-crt .mail-logo {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  .mail-logo {
    animation: none;
  }
}

.mail-title-text {
  white-space: nowrap;
}

.mail-lede {
  margin: -10px 0 0;
  text-wrap: pretty;
  opacity: 0.75;
  font-size: 0.9rem;
}

.mail-field {
  display: grid;
  gap: 6px;
}

.mail-label {
  position: relative;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.mail-optional {
  opacity: 0.55;
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: none;
}

/* The menu cursor, only shown on the selected item. */
.mail-label::before,
.mail-send::before {
  content: "\25B6\FE0E";
  color: #00e5ff;
  opacity: 0;
}

.mail-label::before {
  position: absolute;
  left: -1.4em;
}

.mail-send::before {
  display: inline-block;
}

.mail-field:focus-within .mail-label::before,
.mail-send:focus-visible::before,
.mail-send:hover::before {
  opacity: 1;
  animation: blink 1s steps(1) infinite;
}

.mail-field input,
.mail-field textarea {
  width: 100%;
  padding: 6px 2px;
  border: 0;
  border-bottom: 2px solid rgb(0 229 255 / 0.3);
  border-radius: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 1rem;
  text-shadow: inherit;
  resize: none;
}

.mail-field textarea {
  /* Ruled lines under each row of text, like the single underline on the name field. */
  line-height: 1.6;
  background: repeating-linear-gradient(to bottom, transparent 0 calc(1.6em - 1px), rgb(0 229 255 / 0.12) calc(1.6em - 1px) 1.6em) 0 6px / 100% calc(100% - 12px) no-repeat;
}

.mail-field input:focus,
.mail-field textarea:focus {
  border-bottom-color: #00e5ff;
  outline: none;
  box-shadow: 0 6px 10px -8px rgb(0 229 255 / 0.8);
}

/* A highlighted menu item rather than a web button. */
.mail-send {
  justify-self: start;
  padding: 6px 18px 6px 0;
  border: 2px solid rgb(0 229 255 / 0.5);
  border-radius: 2px;
  background: rgb(0 229 255 / 0.08);
  color: #00e5ff;
  font: inherit;
  font-size: 1.1rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-shadow: 0 0 10px rgb(0 229 255 / 0.6);
  cursor: pointer;
}

.mail-send::before {
  width: 1.6em;
  text-align: center;
}

.mail-send:hover,
.mail-send:focus-visible {
  background: #00e5ff;
  color: #031418;
  text-shadow: none;
  outline: none;
}

.mail-send:hover::before,
.mail-send:focus-visible::before {
  color: #031418;
}

.mail-send:disabled {
  opacity: 0.5;
  cursor: progress;
}

.mail-status {
  min-height: 1.2em;
  margin: 0;
  color: #ffe53a;
  font-size: 0.9rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.mail-status:empty {
  display: none;
}

/* The characters left, in the corner like a DVD player's on-screen readout. */
.mail-count {
  position: absolute;
  top: max(18px, 4vmin);
  left: max(22px, 5vmin);
  z-index: 1;
  margin: 0;
  color: #7dff3a;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-shadow: 0 0 8px rgb(125 255 58 / 0.6);
}

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

/* The stand under the TV: the bottom of the set, a DVD player, and the shelf of discs. */
.stand {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: var(--pan);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(14px, 4vh, 36px);
  background:
    linear-gradient(to bottom, rgb(0 0 0 / 0.55), transparent 30%),
    repeating-linear-gradient(90deg, rgb(255 255 255 / 0.015) 0 3px, transparent 3px 11px),
    linear-gradient(#1a1410, #0d0a08);
}

.bezel {
  position: relative;
  align-self: stretch;
  height: clamp(18px, 4vh, 34px);
  background: linear-gradient(#25272b, #121315 60%, #050506);
  box-shadow: 0 8px 18px rgb(0 0 0 / 0.7);
}

.bezel-led {
  position: absolute;
  right: 24px;
  top: 50%;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #ff3b5c;
  box-shadow: 0 0 6px #ff3b5c;
  transform: translateY(-50%);
}

.player {
  display: flex;
  align-items: center;
  gap: 16px;
  width: min(560px, calc(100% - 32px));
  padding: 14px 18px;
  border-radius: 6px;
  background: linear-gradient(#2a2c31, #17181b);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.08), 0 10px 24px rgb(0 0 0 / 0.6);
}

.player-slot {
  flex: 1;
  height: 6px;
  border-radius: 3px;
  background: #000;
  box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.9), 0 1px 0 rgb(255 255 255 / 0.06);
}

/* A fixed size: it only ever shows short statuses (NO DISC, OPEN, LOADING, PLAYING, EJECT). */
.player-display {
  flex: none;
  box-sizing: border-box;
  width: 12ch;
  padding: 4px 8px;
  border-radius: 3px;
  background: #031008;
  color: #7dff3a;
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-align: center;
  text-shadow: 0 0 6px rgb(125 255 58 / 0.7);
  white-space: nowrap;
  overflow: hidden;
}

.player-eject {
  padding: 4px 10px;
  border: 0;
  border-radius: 3px;
  background: #3a3d44;
  color: #c9d1d9;
  font: inherit;
  cursor: pointer;
}

.player-eject:hover,
.player-eject:focus-visible {
  background: #4a4e57;
}

/* A walnut coffee table in front of the TV, seen a little from above, with the cases
   lying scattered on top. */
.shelf {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(10px, 2.5vw, 22px);
  max-width: min(920px, calc(100% - 32px));
  margin: clamp(4px, 2vh, 18px) 0 0;
  padding: clamp(16px, 4vh, 34px) clamp(12px, 4vw, 48px) clamp(20px, 5vh, 42px);
  list-style: none;
  border-radius: 14px;
  background:
    linear-gradient(170deg, rgb(255 255 255 / 0.1), transparent 35%),
    repeating-linear-gradient(94deg, rgb(0 0 0 / 0.07) 0 2px, transparent 2px 9px, rgb(255 255 255 / 0.03) 9px 10px, transparent 10px 23px),
    linear-gradient(#6b4528, #4a2d18 70%, #3d2413);
  /* The tabletop's front edge, then its shadow on the floor. */
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.12),
    0 9px 0 #2a180b,
    0 24px 34px rgb(0 0 0 / 0.65);
  transform: perspective(1200px) rotateX(18deg);
  transform-origin: 50% 100%;
}

/* The table and what's under it: a case can hide beneath the tabletop with just a corner
   showing past its front edge (dvd.js puts the hidden discs there). */
.table-area {
  position: relative;
  width: fit-content;
  max-width: min(920px, calc(100% - 32px));
  margin-top: clamp(4px, 2vh, 18px);
}

.table-area .shelf {
  position: relative;
  z-index: 1;
  max-width: 100%;
  margin: 0;
}

.hideout {
  position: absolute;
  right: 16%;
  bottom: 0;
  z-index: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Tucked under, turned, in the table's shadow, with only its bottom corner peeking out. */
.hideout .dvd {
  --scatter: translateY(26px) rotate(-16deg);
  transition: transform 0.35s cubic-bezier(0.3, 0.8, 0.3, 1), filter 0.35s;
  filter: brightness(0.7);
}

/* Pointed at, it edges out a little further. */
.hideout .dvd:hover,
.hideout .dvd:focus-visible {
  transform: translateY(46px) rotate(-12deg);
  filter: brightness(0.9);
}

/* Opened (or getting its disc back), it's pulled out from under and set on the tabletop. */
.hideout .dvd.open {
  transform: translateY(-36px) rotate(-4deg);
  filter: none;
}

.hideout:has(.dvd.open) {
  z-index: 2;
}

/* Lying where they were last put down: each case a little turned and out of line. */
.shelf > li:nth-child(4n + 1) .dvd { --scatter: translate(10px, 12px) rotate(-8deg); }
.shelf > li:nth-child(4n + 2) .dvd { --scatter: translate(-4px, -8px) rotate(5deg); }
.shelf > li:nth-child(4n + 3) .dvd { --scatter: translate(6px, 16px) rotate(-3deg); }
.shelf > li:nth-child(4n + 4) .dvd { --scatter: translate(-12px, 2px) rotate(11deg); }

/* A DVD keep case, standing face out. The front cover swings open on its spine to show
   the tray, and the disc lifts out of it. */
.dvd {
  --h: clamp(100px, min(30vh, 21vw), 240px);
  position: relative;
  display: block;
  flex: none;
  width: calc(var(--h) * 0.71);
  height: var(--h);
  padding: 0;
  border: 0;
  border-radius: 4px 6px 6px 4px;
  background: transparent;
  color: #fff;
  font: inherit;
  cursor: pointer;
  perspective: 900px;
  --scatter: translate(0, 0);
  transform: var(--scatter);
  transition: transform 0.2s ease;
}

.dvd:hover,
.dvd:focus-visible,
.dvd.open {
  transform: var(--scatter) translateY(-8px);
  outline: none;
}

.dvd.open {
  z-index: 2;
}

/* Inside the case: black plastic with the hub the disc clips onto. */
.dvd-tray {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: inherit;
  background:
    radial-gradient(circle, #2b2e33 0 7%, #0b0c0e 7.5% 11%, #1a1c20 11.5% 13%, transparent 13.5%),
    linear-gradient(160deg, #1d1f23, #0a0b0d);
  box-shadow: 0 10px 18px rgb(0 0 0 / 0.65), inset 0 0 0 2px rgb(0 0 0 / 0.6);
}

.dvd-tray .disc-art {
  width: 86%;
  height: auto;
  aspect-ratio: 1;
}

.dvd-cover {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  transform-origin: left center;
  transform-style: preserve-3d;
  transition: transform 0.6s cubic-bezier(0.3, 0.7, 0.3, 1);
}

.dvd.open .dvd-cover {
  transform: rotateY(-155deg);
}

.dvd-front,
.dvd-back {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  backface-visibility: hidden;
}

.dvd-front {
  background:
    linear-gradient(90deg, rgb(0 0 0 / 0.55) 0 7%, rgb(255 255 255 / 0.12) 7% 8%, transparent 8%),
    linear-gradient(160deg, rgb(255 255 255 / 0.16), transparent 40%),
    radial-gradient(circle at 60% 38%, color-mix(in srgb, var(--disc) 75%, #fff) 0, var(--disc) 30%, color-mix(in srgb, var(--disc) 35%, #000) 80%);
  box-shadow: 0 10px 18px rgb(0 0 0 / 0.65), inset 0 0 0 2px rgb(0 0 0 / 0.5);
  transition: box-shadow 0.2s ease;
}

.dvd:hover .dvd-front,
.dvd:focus-visible .dvd-front {
  box-shadow: 0 18px 24px rgb(0 0 0 / 0.7), inset 0 0 0 2px rgb(0 0 0 / 0.5), 0 0 0 2px var(--disc);
}

/* The inside of the front cover, seen once it swings open. */
.dvd-back {
  transform: rotateY(180deg);
  background: linear-gradient(200deg, #24272c, #0e0f11);
  box-shadow: inset 0 0 0 2px rgb(0 0 0 / 0.6), inset -6px 0 10px rgb(0 0 0 / 0.5);
}

/* Its disc is in the player. */
.dvd[aria-pressed="true"] .dvd-front {
  filter: brightness(0.45) saturate(0.6);
}

.dvd-title {
  position: absolute;
  left: 12%;
  right: 6%;
  top: 10%;
  font-size: clamp(0.6rem, calc(var(--h) * 0.08), 1.1rem);
  font-style: italic;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-align: left;
  text-shadow: 0 1px 3px rgb(0 0 0 / 0.8);
  overflow-wrap: anywhere;
}

.dvd-badge {
  position: absolute;
  left: 12%;
  bottom: 7%;
  width: 20%;
  line-height: 0;
  opacity: 0.9;
  filter: drop-shadow(0 1px 2px rgb(0 0 0 / 0.6));
}

.dvd-badge svg {
  display: block;
  width: 100%;
  height: auto;
}

/* The disc itself: two faces turning together, laid out like a real one (sizes are
   fractions of the radius): the center hole, a clear plastic hub out to 36% with its
   molded stacking ring, then the label or data area, and a thin clear rim at the edge.
   The clear parts are left see-through by the mask on each face. */
.disc-art {
  --thick: 1.5px; /* the disc's thickness; dvd.js sets it to scale with a disc out of its case */
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
}

/* One layer of the thickness: a plain ring of silver plastic, set at its depth between the
   faces (--k runs 0..1 from the data side to the label side). Hidden behind the label and
   data area when the disc faces you; side-on the layers stack into a solid edge. */
.disc-edge {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle closest-side, #c3ccd5 90%, #9aa5b0);
  -webkit-mask: radial-gradient(circle closest-side, transparent 36%, #000 36.5%);
  mask: radial-gradient(circle closest-side, transparent 36%, #000 36.5%);
  transform: translateZ(calc((var(--k) - 0.5) * var(--thick)));
  pointer-events: none;
}

.disc-face {
  --clear: #dfe7ee; /* the hub and rim plastic, before the mask thins it out */
  position: absolute;
  inset: 0;
  border-radius: 50%;
  backface-visibility: hidden;
  -webkit-mask: radial-gradient(circle closest-side, transparent 12.5%, rgb(0 0 0 / 0.4) 13% 35.5%, #000 36% 97.5%, rgb(0 0 0 / 0.4) 98%);
  mask: radial-gradient(circle closest-side, transparent 12.5%, rgb(0 0 0 / 0.4) 13% 35.5%, #000 36% 97.5%, rgb(0 0 0 / 0.4) 98%);
}

/* The clear hub on both faces: plastic with a molded ring and a fine edge where the
   label or data area starts. */
.disc-face::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle closest-side, var(--clear) 0 26%, #9aa6b2 26.5% 28.5%, #f4f7fa 29% 30%, var(--clear) 30.5% 35.5%, rgb(0 0 0 / 0.25) 35.8% 36%, transparent 36.2% 97.5%, var(--clear) 98%);
}

.disc-label {
  background: var(--disc);
  transform: translateZ(calc(var(--thick) / 2));
}

/* Title printed around the top of the label, following the curve of the disc. */
.disc-label svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.disc-label text {
  fill: #fff;
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: 7.2px;
  font-style: italic;
  font-weight: 800;
  letter-spacing: 0.6px;
  /* A solid black outline drawn behind the letters, so they read on any label color. */
  stroke: #000;
  stroke-width: 1.4px;
  stroke-linejoin: round;
  paint-order: stroke;
}

/* The data side: mirror-silver with a rainbow sheen. --sheen is the angle of the light
   across it; as the disc turns it swings, sweeping the rainbow and highlights around
   like a real disc. */
@property --sheen {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.disc-data {
  transform: rotateY(180deg) translateZ(calc(var(--thick) / 2));
  background:
    /* Starts and ends clear, so the wheel has no seam where it closes. */
    conic-gradient(from calc(200deg + var(--sheen)), transparent, rgb(255 80 180 / 0.35) 6%, rgb(80 220 255 / 0.4) 16%, rgb(255 250 140 / 0.35) 26%, transparent 36%, transparent 52%, rgb(140 255 170 / 0.35) 62%, rgb(170 120 255 / 0.4) 72%, rgb(255 80 180 / 0.35) 82%, transparent 94%),
    conic-gradient(from calc(30deg - var(--sheen) / 2), #e9eef3, #a9b4bf 15%, #f4f7fa 30%, #9aa6b2 48%, #eef2f6 65%, #b1bcc6 82%, #e9eef3);
}

/* How far a disc out of its case is tipped back, in degrees; dvd.js animates it and the
   3D disc (disc3d.js) reads it. */
@property --tilt {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

/* The 3D disc's canvas: wider than the disc, so it has room to tip back in. */
.disc-gl {
  position: absolute;
  left: -30%;
  top: -30%;
  width: 160%;
  height: 160%;
  pointer-events: none;
}

/* The disc out of its case: floats in front of it, slowly turning over like a coin,
   waiting to be clicked. */
.disc {
  position: absolute;
  z-index: 5;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  filter: drop-shadow(0 18px 16px rgb(0 0 0 / 0.7));
}

/* Going into or out of the player: the drop shadow would flatten the disc into a picture,
   so it fades out and the disc keeps its depth as it tips over flat. */
.disc.tipping,
.disc.tipping:hover {
  filter: none;
  transform-style: preserve-3d;
  transition: filter 0.2s;
}

.disc:focus-visible {
  outline: 2px solid var(--disc);
  outline-offset: 4px;
}

/* The 3D disc shows keyboard focus with its glow, which follows its outline as it turns. */
.disc.is-3d:focus-visible {
  outline: none;
}

.disc .disc-art {
  animation: disc-turn 6s linear infinite;
}

/* In step with the turn: the light sweeps across the data side while it faces you. */
.disc .disc-data {
  animation: disc-sheen 6s linear infinite;
}

/* The label also spins slowly around the center, carrying its title round. */
.disc .disc-label {
  animation: disc-spin 10s linear infinite;
}

.disc.settling .disc-art,
.disc.settling .disc-data,
.disc.settling .disc-label {
  animation: none;
}

/* Hover glow for the CSS disc; the 3D one (.is-3d) draws its own, behind the disc. */
.disc:not(.is-3d):hover {
  filter: drop-shadow(0 18px 16px rgb(0 0 0 / 0.7)) drop-shadow(0 0 14px color-mix(in srgb, var(--disc) 60%, transparent));
}

@keyframes disc-turn {
  from {
    transform: perspective(800px) rotateY(0deg);
  }
  to {
    transform: perspective(800px) rotateY(360deg);
  }
}

@keyframes disc-spin {
  to {
    rotate: 360deg;
  }
}

@keyframes disc-sheen {
  to {
    --sheen: 720deg;
  }
}

@media (prefers-reduced-motion: reduce) {
  .room,
  .dvd,
  .dvd-cover {
    transition: none;
  }

  .disc .disc-art,
  .disc .disc-data,
  .disc .disc-label {
    animation: none;
  }
}
