/*
 * The stage is a fixed 640x480 box scaled with a transform, so every position
 * in the JS stays in the original movie's coordinates and nothing has to be
 * recomputed per breakpoint. Images are rendered with nearest-neighbour
 * throughout: these are 8-bit sprites and smoothing them turns them to mud.
 */

:root {
  --ink: #d8dee6;
  --dim: #7d8896;
  --line: #2a3340;
  --accent: #ff6a3d;
  --angel: #ff4d4d;
  --nerv: #4da3ff;
  --panel-bg: rgba(12, 16, 22, 0.55);
  --page: #07090c;
  --page-line: rgba(126, 158, 200, 0.11);
}

* { box-sizing: border-box; }

/*
 * The page surround: a repeating pattern rather than flat black, drawn with
 * gradients so it costs no asset and stays crisp at any zoom. It is page chrome
 * and is deliberately independent of the game -- nothing here reacts to whose
 * turn it is, so it never competes with the stage for attention.
 *
 * It goes on the root element, not on a `body::before`. A negative z-index
 * layer sits behind the body's own background, so with an opaque body the
 * pattern paints and is then covered by it: visible in the inspector, invisible
 * on screen.
 */
html {
  height: 100%;
  background-color: var(--page);
  background-image:
    repeating-linear-gradient(45deg,
      var(--page-line) 0 1px, transparent 1px 12px),
    repeating-linear-gradient(-45deg,
      var(--page-line) 0 1px, transparent 1px 12px);
}

body {
  margin: 0;
  height: 100%;
  background: transparent;
  color: var(--ink);
  font: 12px/1.4 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

/*
 * Banner and stage as one vertical stack with the free height split evenly
 * between the three gaps, which is what puts the banner midway between the top
 * of the page and the top of the board. view.fit() sizes both so the split is
 * always positive; the CSS values here are the fallback before it runs.
 */
:root { --stack-gap: 24px; --banner-h: clamp(64px, 26vh, 240px); }

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-evenly;
  padding: 0;
  opacity: 0;
  transition: opacity 220ms;
}
body.ready { opacity: 1; }

/*
 * The banner is 2.5:1, so it is sized by height rather than width -- letting it
 * span the page would give it a third of the viewport. Its exact height is
 * decided in view.fit(), which grows it into whatever the board does not need
 * once the board has taken the largest crisp scale it can.
 */
.banner {
  display: block;
  height: var(--banner-h);
  line-height: 0;
  border: 1px solid var(--line);
  transition: border-color 160ms;
}
.banner:hover { border-color: var(--accent); }

.banner img {
  height: 100%;
  width: auto;
  max-width: calc(100vw - 24px);
  object-fit: contain;
  display: block;
  /* Photographic, unlike everything else on the page. */
  image-rendering: auto;
}

img { image-rendering: pixelated; -webkit-user-drag: none; user-select: none; }

/*
 * Available to search engines and screen readers, out of the way of the game.
 * Not display:none -- that is skipped by assistive technology and discounted by
 * crawlers; this keeps the text in the accessibility tree.
 */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

#frame { position: relative; }

.bootfail {
  margin: 0;
  padding: 24px;
  max-width: 60ch;
  color: var(--accent);
  font: 12px/1.6 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  white-space: pre-wrap;
}

.stage {
  position: relative;
  transform-origin: top left;
  background: #000;
  overflow: hidden;
  user-select: none;
}

/*
 * Only the pieces that live in stage coordinates are absolutely placed. A
 * blanket `.stage img` rule outranks the panel's own `position: static`
 * declarations and collapses the whole status column into one corner, so the
 * positioning is opt-in per element instead.
 */
.plate, .grid, .unit, .effect { position: absolute; }

/* -- board ---------------------------------------------------------------- */

.plate { image-rendering: pixelated; }

.board {
  position: absolute;
  border: 2px solid #d8c400;
  background: #f4f4ee;
}

.grid { left: 0; top: 0; }

.units { position: absolute; inset: 0; }

.unit {
  position: absolute;
  width: 32px;
  height: 32px;
  object-fit: contain;
  transition: filter 120ms;
}

/*
 * The icons are full-bleed photo tiles, so the side has to be read off the frame
 * around them rather than off the artwork. The frame is an inset outline rather
 * than a box-shadow: a shadow spreads outside the 32px square and collides with
 * whatever is standing in the next cell, which on a crowded board draws one
 * unit's colour around its neighbour.
 */
.unit {
  outline: 2px solid #2f6fbf;
  outline-offset: -2px;
}
.unit.enemy { outline-color: #b02020; }
.unit.spent { opacity: 0.55; }
.unit.masked { opacity: 0.3; filter: grayscale(1); }
.unit.selected { outline-color: #ffd400; outline-width: 3px; outline-offset: -3px; }

.effect {
  position: absolute;
  width: 32px;
  height: 32px;
  opacity: 0;
  pointer-events: none;
  z-index: 5;
}

/* -- hud and status column ------------------------------------------------ */
/*
 * Every piece below is positioned from web/src/layout.js at the coordinate its
 * sprite channel had in the original score, so only appearance is set here.
 */
.hud, .pilot, .portrait, .nameplate, .chip, .hp, .weapons, .wepcursor,
.buttons button.cmd, .tray button.slot { position: absolute; }

/* Every readout is clipped to its field: overflowing text lands on the board
   artwork, where it still looks intentional. */
.hud, .hp, .weapons, .pilot { overflow: hidden; }

.hud {
  display: flex;
  align-items: baseline;
  gap: 4px;
  color: #e8eef6;
  font-size: 11px;
  text-shadow: 0 1px 2px #000;
  pointer-events: none;
  white-space: nowrap;
}
.hud .side { font-weight: 700; letter-spacing: 0.06em; }
.hud .side.s0 { color: var(--angel); }
.hud .side.s1 { color: var(--nerv); }
.hud .turn { font-size: 13px; font-weight: 700; }
.hud .turn::before { content: ": "; color: var(--dim); font-weight: 400; }
.pilot {
  font-size: 8px;
  line-height: 10px;
  text-align: right;
  color: #3d4854;
  letter-spacing: 0.14em;
  white-space: nowrap;
  pointer-events: none;
}

.portrait, .nameplate, .chip { object-fit: fill; }
.stage.nosel .portrait,
.stage.nosel .nameplate,
.stage.nosel .chip,
.stage.nosel .wepcursor { visibility: hidden; }

.hp {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 2px;
  color: #10151b;
  pointer-events: none;
}
.hp .value { font-size: 14px; font-weight: 700; line-height: 1; }
.hp .max { font-size: 9px; color: #46515f; }

.weapons {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 9px;
  line-height: 12px;
  overflow: visible;
}

.weapons li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 3px;
  height: 12px;
  cursor: pointer;
  color: #161c24;
  white-space: nowrap;
}
.weapons li .wn { overflow: hidden; text-overflow: ellipsis; }
.weapons li.on { color: #7a1010; font-weight: 700; }
.weapons li.dry { opacity: 0.35; text-decoration: line-through; }
.weapons li .wr { color: #4d5866; }

.wepcursor { pointer-events: none; }

button.cmd {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  line-height: 0;
}
button.cmd img { width: 100%; height: 100%; display: block; }
button.cmd:disabled { opacity: 0.4; cursor: default; }
button.cmd.armed img { outline: 1px solid #ffd400; }
button.cmd:not(:disabled):hover img { filter: brightness(1.3); }

/* -- deployment chooser --------------------------------------------------- */
/*
 * A separate screen in the original, laid out as two rows of eight portraits
 * across the whole stage. It closes as soon as a unit is picked, because the
 * next click has to reach the board underneath it.
 */
.tray {
  position: absolute;
  inset: 0;
  display: none;
  background: rgba(4, 6, 9, 0.9);
  z-index: 6;
}
.tray.open { display: block; }

.tray::before {
  content: "CHOOSE A UNIT";
  position: absolute;
  top: 120px;
  left: 0;
  right: 0;
  text-align: center;
  font-size: 11px;
  letter-spacing: 0.3em;
  color: var(--accent);
}

button.slot {
  padding: 0;
  border: 1px solid var(--line);
  background: #0d1117;
  cursor: pointer;
  line-height: 0;
}
button.slot img { width: 100%; height: 100%; display: block; }
button.slot:disabled { opacity: 0.2; cursor: default; }
button.slot:not(:disabled):hover { border-color: #ffd400; }

/* -- overlay -------------------------------------------------------------- */

.overlay {
  position: absolute;
  inset: 0;
  display: none;
  z-index: 10;
  background: #05070a;
}
.overlay.open { display: block; }

.title, .reel { position: relative; width: 100%; height: 100%; background: #000; }

/*
 * Only the plates are positioned in stage coordinates. A blanket `.title img`
 * rule also catches the images *inside* the buttons, whose `width: 100%` then
 * resolves against the stage instead of the button and blows them up to full
 * screen -- the same trap as the status column.
 */
.plate-img, button.row, button.start { position: absolute; }

.reelframe {
  position: absolute;
  inset: 0;
  opacity: 0;
}

button.row {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  line-height: 0;
}
button.row img { width: 100%; height: 100%; display: block; }
button.row:hover img { filter: brightness(1.35); }

button.start {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  line-height: 0;
}
button.start img { width: 100%; height: 100%; display: block; }
button.start:hover img { filter: brightness(1.35); }

.title.over {
  display: grid;
  place-content: center;
  gap: 10px;
  text-align: center;
  background: #05070a;
}
.title.over h1 { margin: 0; font-size: 26px; letter-spacing: 0.22em; color: var(--accent); }
.title.over p { margin: 0; color: var(--dim); }
button.again {
  justify-self: center;
  margin-top: 8px;
  padding: 5px 14px;
  border: 1px solid var(--accent);
  background: rgba(5, 8, 12, 0.9);
  color: var(--ink);
  font: inherit;
  letter-spacing: 0.2em;
  cursor: pointer;
}
button.again:hover { background: var(--accent); color: #05070a; }

/* -- toast ---------------------------------------------------------------- */

.toast {
  position: absolute;
  left: 91px;
  top: 24px;
  padding: 3px 8px;
  background: rgba(5, 8, 12, 0.9);
  border: 1px solid var(--accent);
  color: var(--ink);
  font-size: 11px;
  letter-spacing: 0.1em;
  opacity: 0;
  transition: opacity 180ms;
  pointer-events: none;
  z-index: 8;
}
.toast.show { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .unit { transition: none; }
}
