/* The disc library component (disc-library.js), in the player's dialog (index.html). Everything is scoped to .lib and named lib-*, so it never meets the player's
   own rules; it uses the player's tokens and its .btn-primary / .btn-quiet / .icon / .vh. States are
   on the root: data-mode, data-lights, data-tray, data-disc, data-drag.
   Departures from the player's rules, on purpose: physical objects move (the tray, the discs), the
   console is a photo, a disc's hub is translucent, and the console's lights glow. */

@property --away {
  syntax: "<number>";
  inherits: false;
  initial-value: 1;
}

/* As dark as the player while a game runs (the room with its lights down), so that the library fading away
   into the game, or back in after it, changes no colour. */
.lib {
  position: relative;
  min-height: 0;
  background: var(--house-down);
  transition: background-color 300ms var(--ease-out);
}

.lib-room {
  position: absolute;
  inset: 0;
  overflow: hidden;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}

.lib[data-mode="shelf"] .lib-room {
  cursor: grab;
}

.lib.dragging .lib-room {
  cursor: grabbing;
}

/* Without a BIOS the library asks for one first: no shelf yet. */
.lib[data-bios="none"] :is(.lib-shelf, .lib-info, .lib-bar) {
  visibility: hidden;
}

.lib[data-drag="ok"] .lib-room {
  outline: 2px solid var(--amber);
  outline-offset: -8px;
}

/* A fixed-size stage in the photo's units, scaled as a whole to fit the room (--k). */
.lib-stage {
  position: absolute;
  left: 50%;
  top: 50%;
  width: var(--stage-w, 1240px);
  height: var(--stage-h, 1090px);
  transform: translate(-50%, -50%) scale(var(--k, 1));
  pointer-events: none;
  transition: opacity 300ms var(--ease-out);
}

/* ---------------------------------------------------------------- the console */

.lib-console,
.lib-panel {
  position: absolute;
  width: 1100px;
  height: 662px;
}

.lib-console img,
.lib-panel img {
  display: block;
  width: 1100px;
  height: 662px;
  max-width: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* Where the tray's front was: the dark inside of the drive. */
.lib-hole {
  position: absolute;
  inset: 0;
  background: #050505;
  clip-path: var(--hole);
  visibility: hidden;
}

.lib:not([data-tray="closed"]) .lib-hole {
  visibility: visible;
}

/* The tray's front panel is the photo's own, cut out and moved. */
.lib-panel {
  clip-path: var(--panel);
  will-change: transform;
}

.lib-tray-clip {
  position: absolute;
  inset: 0;
  clip-path: var(--outside);
}

.lib-tray-move {
  position: absolute;
  inset: 0;
  will-change: transform;
}

.lib[data-tray="closed"] .lib-tray-move {
  visibility: hidden;
}

/* The plate, in millimetres on the tray's plane (an affine transform from the script). */
.lib-plate,
.lib-plate-side {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
}

.lib-plate {
  background: #1d1d1f;
  box-shadow: inset 0 0 0 1px #2c2c2f;
}

.lib-well {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 124px;
  height: 124px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: #141416;
  box-shadow: inset 0 0 0 1px #2e2e31;
}

/* The opening the laser and the spindle reach the disc through. */
.lib-channel {
  position: absolute;
  left: 50%;
  top: 0;
  width: 30px;
  height: 46%;
  transform: translateX(-50%);
  border-radius: 0 0 15px 15px;
  background: #0c0c0d;
}

.lib-plate-side {
  background: #0d0d0e;
}

/* The power light (green, in the Reset button) comes on with a disc in. */
.lib-led {
  position: absolute;
  width: 22px;
  height: 22px;
  border-radius: 3px;
  opacity: 0;
  mix-blend-mode: screen;
  transition: opacity 160ms var(--ease-out);
}

.lib-led-power {
  left: 788px;
  top: 466px;
  background: radial-gradient(closest-side, rgb(90 255 140 / 0.85), rgb(40 200 90 / 0.35) 60%, transparent);
}

.lib[data-disc="in"] .lib-led {
  opacity: 1;
}

/* ---------------------------------------------------------------- discs */

.lib-shelf {
  position: absolute;
  inset: 0;
}

.lib-shelf:focus {
  outline: none;
}

.lib-disc {
  position: absolute;
  width: var(--disc, 250px);
  height: var(--disc, 250px);
  left: calc(var(--disc, 250px) / -2);
  top: calc(var(--disc, 250px) / -2);
  border-radius: 50%;
  opacity: var(--fade, 1);
  filter: brightness(var(--away));
  pointer-events: auto;
  cursor: pointer;
  transition: --away 300ms var(--ease-out);
}

.lib-disc.is-away {
  --away: 0.22;
}

/* The one in the air goes over the console. */
.lib-disc.is-flying {
  z-index: 100;
}

.lib-tray-move .lib-disc {
  pointer-events: none;
}

.lib-disc .disc-svg {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
}

/* Where the keyboard's input goes: the house's amber, around the disc in front. */
.lib-disc::after {
  content: "";
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  border: 2px solid var(--amber);
  opacity: 0;
  transition: opacity 160ms var(--ease-out);
}

.lib[data-mode="shelf"] .lib-shelf:focus-visible .lib-disc[aria-selected="true"]::after {
  opacity: 1;
}

/* ---------------------------------------------------------------- the Easter egg: cleaning a disc */

.lib-clean {
  position: absolute;
  inset: 0;
  z-index: 200;
  pointer-events: none;
}

.lib-bottle,
.lib-cloth,
.lib-mist {
  position: absolute;
  left: 0;
  top: 0;
}

.lib-bottle svg,
.lib-cloth svg {
  display: block;
  width: 100%;
  height: 100%;
}

.lib-mist {
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: rgb(228 238 242 / 0.85);
}

/* The data side: silver, with the rainbow a disc's tracks throw back, the clear hub and its hole. */
.lib-data {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  overflow: hidden;
  background:
    radial-gradient(circle closest-side, transparent 0 12.4%, rgb(214 216 222 / 0.35) 12.6% 27%, #9b9da4 27.4% 39%, transparent 39.4%),
    conic-gradient(from 10deg, hsl(220 14% 70%), hsl(280 24% 78%), hsl(185 26% 76%), hsl(48 30% 78%), hsl(325 22% 76%), hsl(205 22% 74%), hsl(220 14% 70%));
  mask: radial-gradient(circle closest-side, transparent 12.4%, #000 12.6%);
  box-shadow: inset 0 0 0 3px rgb(255 255 255 / 0.3);
}

.lib-dirt {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.lib-glint {
  position: absolute;
  inset: -20% 30%;
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.55), transparent);
  transform: translateX(-120%) rotate(20deg);
}

/* While it is turned over, its label shows edge on. */
.lib-disc .disc-svg {
  position: absolute;
  inset: 0;
}

/* ---------------------------------------------------------------- text over the room */

.lib-bar {
  position: absolute;
  top: 8px;
  right: max(calc(var(--gutter, 24px) - 12px), env(safe-area-inset-right));
  display: flex;
  align-items: center;
  gap: 16px;
}

.lib-count {
  margin: 0;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 16px;
  color: var(--ink-3);
  white-space: nowrap;
}

.lib-info {
  position: absolute;
  left: 50%;
  top: var(--info-top, 60%);
  width: min(40rem, calc(100% - 2 * var(--gutter, 24px)));
  transform: translateX(-50%);
  text-align: center;
  pointer-events: none;
  transition: opacity 180ms var(--ease-out);
}

.lib:not([data-mode="shelf"]) .lib-info {
  opacity: 0;
  visibility: hidden;
  transition: opacity 180ms var(--ease-out), visibility 0s 180ms;
}

.lib h3 {
  margin: 0;
  font-weight: 500;
  font-stretch: 125%;
  letter-spacing: -0.02em;
  text-wrap: balance;
  overflow-wrap: anywhere;
  color: var(--ink);
}

.lib h3:focus {
  outline: none;
}

.lib-info h3 {
  font-size: clamp(22px, 2.2vw, 32px);
  line-height: 1.1;
}

.lib-info p,
.lib-card p {
  margin: 0;
}

.lib-meta {
  margin-top: 8px !important;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 16px;
  font-weight: 450;
  color: var(--ink-2);
}

.lib-file {
  margin-top: 2px !important;
  font-size: 12.5px;
  line-height: 18px;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lib-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 12px !important;
  font-size: 12.5px;
  line-height: 18px;
  color: var(--ink-3);
}

.lib-sep {
  color: var(--ink-3);
}

.lib-hint kbd,
.lib-cap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 18px;
  padding: 0 4px;
  border-radius: 3px;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 16px;
  font-weight: 500;
}

.lib-hint kbd {
  border: 1px solid var(--line-2);
  background: var(--raise);
  color: var(--ink-2);
}

.lib-hint kbd .icon {
  width: 12px;
  height: 12px;
}

.lib-cap {
  margin-left: 4px;
  border: 1px solid rgb(26 19 6 / 0.45);
}

@media (hover: none) and (pointer: coarse) {
  .lib-hint {
    display: none;
  }
}

.lib-error {
  margin-top: 12px !important;
  color: var(--coral);
}

/* ---------------------------------------------------------------- cards: the intake, and the insert's end */

/* The setup: the BIOS, then the folder of games, as two tiles side by side over the room (one above the other
   on narrow windows). A tile has its icon, its name, a line and its button; the BIOS tile shows a check and the
   file's name once there is one, and the games' tile waits, dimmed, until then. */
.lib-setup {
  position: absolute;
  left: 50%;
  top: var(--card-top, 14%);
  width: min(40rem, calc(100% - 2 * var(--gutter, 24px)));
  transform: translateX(-50%);
}

.lib-steps {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

@media (max-width: 559px) {
  .lib-steps {
    grid-template-columns: minmax(0, 1fr);
  }
}

.lib-step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "icon title" "icon sub" "actions actions" "error error";
  column-gap: 14px;
  align-content: start;
  padding: 18px 18px 16px;
  border: 1px solid var(--line-2);
  border-radius: 12px;
  background: rgb(28 27 25 / 0.88);
  backdrop-filter: blur(6px);
  transition: opacity 240ms var(--ease-out), border-color 240ms var(--ease-out);
}

.lib-step-icon {
  grid-area: icon;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: rgb(242 181 68 / 0.12);
  color: var(--amber);
}

.lib-step-icon .icon {
  grid-area: 1 / 1;
  width: 24px;
  height: 24px;
}

.lib-step-title {
  grid-area: title;
  margin: 2px 0 0;
  font-size: 17px;
  line-height: 22px;
  font-weight: 600;
  color: var(--ink);
}

.lib-step-sub {
  grid-area: sub;
  margin: 2px 0 0;
  font-size: 13px;
  line-height: 18px;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}

.lib-step-actions {
  grid-area: actions;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  margin-top: 14px;
}

.lib-step-aside {
  font-size: 13px;
  color: var(--ink-3);
}

.lib-step-aside:empty {
  display: none;
}

.lib-step-error {
  grid-area: error;
  margin: 10px 0 0;
  font-size: 13px;
  line-height: 18px;
  color: var(--coral);
}

/* The BIOS is in: a check, its file's name, and Change. */
.lib-step-done,
.lib-step[data-done="true"] .lib-step-todo {
  display: none;
}

.lib-step[data-done="true"] .lib-step-done {
  display: block;
}

.lib-step[data-done="true"] .lib-step-icon {
  background: rgb(110 220 150 / 0.12);
  color: #7fd79c;
}

.lib-step[data-done="true"] .lib-step-sub {
  overflow: hidden;
  font-family: var(--mono);
  font-size: 12px;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.lib-step[data-done="true"] .btn-quiet {
  margin-left: -12px;
}

/* The games wait for the BIOS. */
.lib-step.is-waiting {
  opacity: 0.45;
}

.lib-step.is-waiting .lib-step-icon {
  background: rgb(236 232 225 / 0.06);
  color: var(--ink-3);
}

.lib-setup-fine {
  margin: 14px 2px 0;
  font-size: 12px;
  line-height: 17px;
  color: var(--ink-3);
  text-wrap: pretty;
}

.lib[data-drag="ok"] .lib-step:not(.is-waiting, [data-done="true"]) {
  border-color: var(--amber);
}

.lib-card {
  position: absolute;
  left: 50%;
  top: var(--card-top, 18%);
  width: min(30rem, calc(100% - 2 * var(--gutter, 24px)));
  transform: translateX(-50%);
  text-align: left;
}

.lib-card h3 {
  font-size: clamp(26px, 2.4vw, 36px);
  line-height: 1.08;
}

.lib-body {
  margin-top: 12px !important;
  color: var(--ink-2);
  text-wrap: pretty;
}

.lib-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin-top: 24px;
}

.lib-aside {
  font-size: 13px;
  line-height: 18px;
  font-weight: 480;
  color: var(--ink-2);
}

.lib-fine {
  margin-top: 16px !important;
  font-size: 12.5px;
  line-height: 18px;
  color: var(--ink-3);
  text-wrap: pretty;
}

.lib-card-dark {
  top: 50%;
  transform: translate(-50%, -50%);
  animation: lib-fade-in 240ms var(--ease-out);
}

@keyframes lib-fade-in {
  from {
    opacity: 0;
  }
}

.lib[data-mode="scanning"] .lib-actions {
  opacity: 0.5;
  pointer-events: none;
}

/* ---------------------------------------------------------------- lights down
   The disc is in: the room goes black over 900 ms, like the player's lights down. They come back up
   in 300 ms. */

.lib[data-lights="down"] {
  background: #000;
  transition: background-color 900ms var(--ease-out);
}

.lib[data-lights="down"] .lib-stage {
  opacity: 0;
  visibility: hidden;
  transition: opacity 900ms var(--ease-out), visibility 0s 900ms;
}

/* ---------------------------------------------------------------- the player's dialog */

.lib-dialog {
  width: 100vw;
  height: 100vh;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--house-down);
  color: var(--ink);
  overflow: hidden;
  opacity: 1;
  transition: opacity 700ms var(--ease-out), background-color 900ms var(--ease-out);
}

.lib-dialog[open] {
  display: grid;
  grid-template-rows: 48px minmax(0, 1fr) auto;
}

/* The backdrop fades with the dialog: else it stays over the player until the dialog closes, and the game
   appears all at once after a fade that shows nothing. */
.lib-dialog::backdrop {
  background: var(--house-down);
  opacity: 1;
  transition: opacity 700ms var(--ease-out);
}

.lib-dialog.is-leaving::backdrop {
  opacity: 0;
}

.lib-dialog.is-dark {
  background: #000;
}

.lib-dialog.is-leaving {
  opacity: 0;
}

.lib-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-inline: max(var(--gutter, 24px), env(safe-area-inset-left)) max(calc(var(--gutter, 24px) - 12px), env(safe-area-inset-right));
  transition: opacity 900ms var(--ease-out);
}

.lib-head h2 {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0;
  font-size: 16px;
  line-height: 20px;
  font-weight: 640;
  font-stretch: 125%;
  letter-spacing: 0.01em;
}

.lib-head .mark {
  width: 16px;
  height: 12px;
}

.lib-credit {
  margin: 0;
  padding: 7px max(var(--gutter, 24px), env(safe-area-inset-right)) calc(7px + env(safe-area-inset-bottom)) max(var(--gutter, 24px), env(safe-area-inset-left));
  font-size: 12.5px;
  line-height: 18px;
  color: var(--ink-3);
  transition: opacity 900ms var(--ease-out);
}

.lib-credit a {
  color: var(--ink-2);
}

.lib-dialog.is-dark .lib-head,
.lib-dialog.is-dark .lib-credit {
  opacity: 0;
}

/* Under 640 px the folder button keeps only its icon; its name stays for screen readers. */
@media (max-width: 639px) {
  .lib-folder-btn span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .lib-folder-btn {
    min-width: var(--hit, 40px);
    justify-content: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .lib *,
  .lib *::before,
  .lib *::after,
  .lib,
  .lib-dialog,
  .lib-dialog * {
    transition-duration: 0ms !important;
    transition-delay: 0ms !important;
    animation-duration: 0ms !important;
  }
}

@media (forced-colors: active) {
  .lib[data-mode="shelf"] .lib-shelf:focus-visible .lib-disc[aria-selected="true"]::after {
    border-color: Highlight;
  }
}
