/*
  Arcade - phosphor green on black, monospaced and uppercase, with a hard offset edge and a static
  scanline overlay. The entry is stepped rather than eased, so the popup snaps into place in four
  frames the way a cabinet would draw it.

  Everything here is cheap on purpose: the scanlines are one repeating gradient painted once, the
  offset edge is a box-shadow, and the motion is transform and opacity only. Nothing blurs.

  Rendered by the shared preset engine (index.html); this file owns every pixel.
*/

:root {
  --ach-in: 320ms;
  --ach-out: 240ms;
  --ease-in: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out: cubic-bezier(0.7, 0, 0.84, 0);

  --surface: #050c07;
  --text: #d8ffe6;
  --muted: #6fbf8c;
  --accent: #4dff88;
  --accent-soft: #b6ffcf;
}

html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  background: transparent;
}

.ach {
  position: fixed;
  left: 50%;
  top: 50%;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 16px;
  width: 452px;
  padding: 15px 18px;
  border: 2px solid var(--accent);
  border-radius: 2px;
  overflow: hidden;
  background: var(--surface);
  /* The hard offset instead of a soft drop shadow - a printed edge, not a lit one. */
  box-shadow:
    3px 3px 0 0 color-mix(in srgb, var(--accent) 22%, transparent),
    0 0 8px color-mix(in srgb, var(--accent) 26%, transparent);
  color: var(--text);
  font-family: Consolas, 'Cascadia Mono', 'Courier New', monospace;
  opacity: 0;
  will-change: transform, opacity;
  transform: translate(-50%, -50%) scale(var(--scale, 1));
}

/*
  Scanlines. One gradient, painted once, never animated.

  Kept light on purpose: they cross the achievement icon as well as the text, and at full strength
  they read as damage to the artwork rather than as a screen the popup is being drawn on.
*/
.ach::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.24) 0 1px, transparent 1px 3px);
}

.ach > * {
  position: relative;
  z-index: 1;
}

/* --- icon ------------------------------------------------------------------------------------ */

.ach .icon {
  flex: 0 0 auto;
}

/*
  The icon is rendered normally, deliberately.

  `image-rendering: pixelated` looks like the obvious choice here and is the wrong one: achievement
  icons arrive at 64px and this frame is 56px, so nearest-neighbour is a DOWNscale - it drops rows
  and columns outright rather than adding visible pixels, and it took the points off the artwork.
  The retro reading comes from the type, the scanlines, the phosphor palette and the stepped motion;
  none of it needs the one piece of the user's own content to be damaged.
*/
.ach .icon img {
  display: block;
  box-sizing: border-box;
  width: 62px;
  height: 62px;
  border: 2px solid var(--accent);
  border-radius: 0;
  object-fit: cover;
  background: #000000;
}

/* --- text ------------------------------------------------------------------------------------ */

.ach .text_wrap {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
  overflow: hidden;
}

.ach .text_wrap:has(.marquee) {
  -webkit-mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0.35) 0, #000 10px, #000 calc(100% - 22px), transparent 100%);
  mask-image: linear-gradient(90deg, rgba(0, 0, 0, 0.35) 0, #000 10px, #000 calc(100% - 22px), transparent 100%);
}

.ach .meta {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
  margin-bottom: 3px;
  line-height: 1.1;
}

.ach .meta[hidden] {
  display: none;
}

.ach .game {
  min-width: 0;
  overflow: hidden;
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.ach .game[hidden] {
  display: none;
}

.ach .rarity {
  flex: 0 0 auto;
  padding: 0 5px;
  background: var(--accent);
  color: #04170c;
  font-size: 10.5px;
  font-weight: 700;
}

.ach .rarity[hidden] {
  display: none;
}

.ach .title {
  max-width: 100%;
  margin: 0;
  color: var(--accent);
  font-size: 16px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-shadow: 0 0 8px color-mix(in srgb, var(--accent) 55%, transparent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The cursor. Blinks on opacity alone, which is a compositor-only property. */
.ach .title::after {
  content: '_';
  margin-left: 2px;
  animation: aw_blink 1s steps(1) infinite;
}

.ach .detail {
  max-width: 100%;
  margin: 1px 0 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ach .title.marquee,
.ach .detail.marquee {
  display: inline-block;
  overflow: visible;
  text-overflow: clip;
  will-change: transform;
}

/* --- progress -------------------------------------------------------------------------------- */

.progress_line {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin-top: 8px;
  min-width: 0;
}

.progress_line[hidden] {
  display: none;
}

.progress_track {
  display: block;
  flex: 1 1 auto;
  min-width: 70px;
  height: 8px;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: 0;
  background: #000000;
}

/* Blocks rather than a bar - a meter drawn out of cells, like a cabinet would. */
.progress_meter {
  display: block;
  width: 0%;
  height: 100%;
  background:
    repeating-linear-gradient(90deg, var(--accent) 0 4px, transparent 4px 6px);
  transition: width 0.35s ease;
}

.progress_label {
  flex: 0 0 auto;
  color: var(--accent);
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* --- states ---------------------------------------------------------------------------------- */

/* A different phosphor for a rare unlock - amber, the other colour these screens came in. */
.ach.state-rare {
  --accent: #ffb000;
  --accent-soft: #ffd980;
  --text: #ffe9c2;
  --muted: #bf8f45;
  --surface: #0d0803;
}

.ach.state-rare.tier-silver {
  --accent: #cfe2f2;
  --accent-soft: #eef6ff;
  --text: #e8f2fb;
  --muted: #7f97ab;
  --surface: #05090d;
}

.ach.state-rare.tier-bronze {
  --accent: #e08a3c;
  --accent-soft: #f5c08a;
  --text: #f7ddc2;
  --muted: #a87042;
  --surface: #0c0703;
}

/* 100%: white phosphor, a doubled frame and a brighter bloom. */
.ach.state-platinum {
  --accent: #b9f4ff;
  --accent-soft: #ffffff;
  --text: #ffffff;
  --muted: #7fb9c8;
  --surface: #030c10;
  box-shadow:
    3px 3px 0 0 color-mix(in srgb, var(--accent) 26%, transparent),
    0 0 0 5px color-mix(in srgb, var(--accent) 14%, transparent),
    0 0 8px color-mix(in srgb, var(--accent) 38%, transparent);
}

/* --- motion ---------------------------------------------------------------------------------- */

@keyframes aw_blink {
  0%,
  49% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}

@keyframes aw_in {
  from {
    transform: translate(calc(-50% - 30px), -50%) scale(calc(var(--scale, 1) * 0.94));
    opacity: 0;
  }
  to {
    transform: translate(-50%, -50%) scale(var(--scale, 1));
    opacity: 1;
  }
}

@keyframes aw_hold {
  from,
  to {
    transform: translate(-50%, -50%) scale(var(--scale, 1));
    opacity: 1;
  }
}

@keyframes aw_out {
  from {
    transform: translate(-50%, -50%) scale(var(--scale, 1));
    opacity: 1;
  }
  to {
    transform: translate(calc(-50% - 22px), -50%) scale(calc(var(--scale, 1) * 0.94));
    opacity: 0;
  }
}

@keyframes aw_rise {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.ach.active {
  animation:
    aw_in var(--ach-in) cubic-bezier(0.2, 1.3, 0.35, 1) forwards,
    aw_hold var(--ach-hold, 5440ms) forwards,
    aw_out var(--ach-out) var(--ease-out) forwards;
  animation-delay: 0s, var(--ach-in), calc(var(--ach-in) + var(--ach-hold, 5440ms));
}

/* Never .title / .detail: the engine cancels their animations when it measures the marquee. */
.ach.active .text_wrap {
  animation: aw_rise 240ms var(--ease-out) 260ms both;
}
