/* BattleBot Arena v2 — title, bot select, results screens. */

/* ==================================================================== TITLE */

.screen-title {
  align-items: center;
  justify-content: center;
  text-align: center;
}

.screen-title::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 12px;
  background: var(--hazard);
  opacity: 0.9;
}

.title-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 24px;
}

.title-gear {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(78vmin, 700px);
  height: min(78vmin, 700px);
  transform: translate(-50%, -54%);
  z-index: -1;
  opacity: 0.1;
  color: var(--steel-500);
  animation: gearSpin 90s linear infinite;
}

@keyframes gearSpin {
  to {
    transform: translate(-50%, -54%) rotate(360deg);
  }
}

.title-logo {
  margin: 6px 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 0.92;
  user-select: none;
}

.title-logo-main {
  position: relative;
  font-family: var(--font-display);
  font-size: clamp(60px, 11vw, 148px);
  letter-spacing: 0.015em;
  text-transform: uppercase;
  transform: skewX(var(--skew));
  background: linear-gradient(
    180deg,
    #ffffff 0%,
    #dfe5ec 30%,
    #96a1b0 48%,
    #f2f5f9 52%,
    #b9c2cd 78%,
    #7e8896 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 4px 0 rgba(0, 0, 0, 0.55)) drop-shadow(0 12px 26px rgba(0, 0, 0, 0.6));
}

/* animated sheen sweep across the chrome lettering */
.title-logo-main::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  background: linear-gradient(
    115deg,
    transparent 42%,
    rgba(255, 255, 255, 0.95) 50%,
    transparent 58%
  );
  background-size: 300% 100%;
  background-position: 120% 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: sheen 5.2s ease-in-out infinite;
  pointer-events: none;
}

@keyframes sheen {
  0%,
  55% {
    background-position: 120% 0;
  }
  85%,
  100% {
    background-position: -60% 0;
  }
}

.title-logo-sub {
  display: inline-flex;
  align-items: center;
  gap: 18px;
  margin-top: 10px;
  transform: skewX(var(--skew));
}

.title-logo-sub .stripe {
  width: clamp(40px, 8vw, 110px);
  height: 16px;
  background: var(--hazard);
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.5);
}

.title-logo-sub b {
  padding: 6px 26px 4px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(30px, 4.6vw, 58px);
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  text-transform: uppercase;
  color: var(--white);
  background: linear-gradient(180deg, var(--red-hot), var(--red) 45%, var(--red-deep));
  box-shadow:
    0 3px 0 rgba(0, 0, 0, 0.55),
    0 12px 34px rgba(232, 54, 42, 0.4);
  clip-path: polygon(12px 0, 100% 0, calc(100% - 12px) 100%, 0 100%);
}

.title-tagline {
  margin: 20px 0 0;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(0.72rem, 1.4vw, 0.95rem);
  letter-spacing: 0.5em;
  text-indent: 0.5em;
  text-transform: uppercase;
  color: var(--muted);
}

.title-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  margin-top: 42px;
}

.title-secondary {
  display: flex;
  gap: 14px;
}

.title-footnote {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 30px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(147, 160, 177, 0.55);
}

/* =============================================================== BOT SELECT */

.screen-select {
  padding: clamp(12px, 2vh, 26px) clamp(16px, 3vw, 40px);
  gap: clamp(10px, 1.6vh, 18px);
  /* This screen NEVER scrolls. Everything you need in order to choose has to be
     on it at once: scrolling meant picking a bot from the bottom row updated a
     pod you could not see, which reads as nothing happening, and it took a pile
     of scroll-into-view rules to paper over. The grid is a fixed cost — it is
     the whole roster and every card has to stay reachable — so the STAGE is
     what flexes, taking whatever is left over. That also gets the viewers as
     big as this screen can make them for free, which is what the fixed 56vh
     heights were reaching for and what made it overflow.

     `auto` rather than `hidden` is a safety valve, not a plan: below about
     560px of viewport a pod cannot be drawn at a usable size AND leave room for
     three rows of roster, and a scrollbar there is far better than clipping the
     FIGHT button out of reach. At every size anyone plays at, there is nothing
     to scroll. */
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* The live showcase canvas is FIXED to the viewport, not to the scrolling
   content: the previewer positions its viewports by measuring each pod against
   the canvas rect every frame, so a pod that scrolls simply scissors smaller.
   The header stays put over it while the grid scrolls beneath. */
#preview-canvas {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  z-index: 0;
  pointer-events: none;
}

.screen-select > .select-head,
.screen-select > .select-stage,
.screen-select > .bot-grid {
  position: relative;
  z-index: 1;
}

.select-head {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  flex: 0 0 auto; /* the screen scrolls; nothing in it may be squeezed */
}

.select-head > :last-child {
  justify-self: end;
}

.select-step {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 2.4vw, 1.8rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: center;
  transform: skewX(var(--skew));
  color: var(--white);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.5);
}

.select-step::after {
  content: "";
  display: block;
  width: 120px;
  height: 3px;
  margin: 6px auto 0;
  background: linear-gradient(90deg, transparent, var(--red), transparent);
}

.difficulty {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.difficulty-label {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.24em;
  color: var(--muted);
}

.difficulty-buttons {
  display: inline-flex;
  transform: skewX(var(--skew));
  border: 1px solid var(--line-strong);
  clip-path: polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%);
}

.difficulty-buttons button {
  padding: 7px 16px;
  border: 0;
  border-right: 1px solid var(--line);
  background: linear-gradient(180deg, var(--steel-700), var(--steel-800));
  color: var(--muted);
  font-family: var(--font-display);
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  cursor: pointer;
  transition: filter 0.12s ease;
}

.difficulty-buttons button:last-child {
  border-right: 0;
}

.difficulty-buttons button:hover {
  filter: brightness(1.3);
}

.difficulty-buttons button.is-active {
  background: linear-gradient(180deg, var(--amber), #d98f13);
  color: #191203;
  text-shadow: none;
}

/* ------------------------------------------------------- showcase stage
   Two pods flank the VS column. A pod is: claim plate (button) on top, the
   3D view window in the middle (transparent — the canvas draws behind it),
   and a foot row with weapon badge, stat pips and the TEST WEAPON trigger. */

/* The stage takes everything the header and the roster do not. There is no
   fixed height and no size classes any more: a vh figure is a guess about how
   tall the grid will be, and every guess that was too generous overflowed a
   screen that must not scroll. `flex: 1 1 auto` with `min-height: 0` is the
   same intent stated as a constraint instead — as big as it can be, never
   bigger than fits. The floor is there so a very short window still shows a
   usable window rather than a sliver. */
.select-stage {
  flex: 1 1 auto;
  /* A flat number, not a vh: this is "the least a pod can be and still be a
     pod" — plate, a window you can see a bot in, and the foot row. Expressed as
     a fraction of the viewport it collapses on a short window and the roster
     draws straight over the pods instead of pushing them. */
  min-height: 240px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: clamp(14px, 2.2vw, 34px);
  align-items: stretch;
}

/* THREE AND FOUR PODS. The stage's default is the head-to-head pair with the
   VS column between them; with more players the pods take one row of their own
   and the VS column drops underneath as a strip, which is the same shape the
   narrow-window layout already used. data-pods is set by ui/ui.js. */
.select-stage[data-pods="3"],
.select-stage[data-pods="4"] {
  grid-template-rows: minmax(0, 1fr) auto;
  gap: clamp(8px, 1.4vw, 18px);
}

.select-stage[data-pods="3"] {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-areas:
    "p1 p2 p3"
    "mid mid mid";
}

.select-stage[data-pods="4"] {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-areas:
    "p1 p2 p3 p4"
    "mid mid mid mid";
}

.select-stage[data-pods="3"] .pod-player,
.select-stage[data-pods="4"] .pod-player {
  grid-area: p1;
}

.select-stage[data-pods="3"] .pod-rival,
.select-stage[data-pods="4"] .pod-rival {
  grid-area: p2;
}

.select-stage[data-pods="3"] .pod-p3,
.select-stage[data-pods="4"] .pod-p3 {
  grid-area: p3;
}

.select-stage[data-pods="4"] .pod-p4 {
  grid-area: p4;
}

.select-stage[data-pods="3"] .select-mid,
.select-stage[data-pods="4"] .select-mid {
  grid-area: mid;
  flex-direction: row;
  gap: 18px;
  padding: 2px 0 0;
}

/* THE FOOT ROW at three or four pods. A quarter-width pod cannot hold the badge,
   the stat pips and the control legend on one line — they overlapped — so the
   row wraps and centres, and every pod reads left-to-right (the rival pod's
   mirrored layout is a two-pod idea: it exists so the pair face each other
   across the VS column, and there is no pair here). */
.select-stage[data-pods="3"] .pod-foot,
.select-stage[data-pods="4"] .pod-foot {
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  gap: 3px 10px;
  min-height: 0;
  padding-top: 6px;
}

.select-stage[data-pods="3"] .pod-controls,
.select-stage[data-pods="4"] .pod-controls {
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 2px 12px;
  width: 100%;
  margin: 0;
}

.select-stage[data-pods="4"] .pod-stats {
  gap: 6px;
}

/* "VS" is a two-machine idea, and the orbit hint is the first thing worth
   giving up for the height four pods need. */
.select-stage[data-pods="3"] .vs-label,
.select-stage[data-pods="4"] .vs-label,
.select-stage[data-pods="4"] .pod-controls-hint {
  display: none;
}

.preview-pod {
  --accent: var(--muted);
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}

.pod-plate {
  position: relative;
  display: flex;
  flex: 0 0 auto;
  min-height: 58px;
  padding: 0;
  border: 1px solid var(--line);
  background:
    var(--carbon),
    linear-gradient(180deg, rgba(32, 38, 47, 0.9), rgba(12, 14, 18, 0.94));
  color: inherit;
  text-align: left;
  cursor: pointer;
  clip-path: polygon(
    var(--cut) 0,
    100% 0,
    100% calc(100% - 10px),
    calc(100% - 10px) 100%,
    0 100%,
    0 var(--cut)
  );
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.preview-pod.is-filled .pod-plate {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent);
}

.pod-plate::before {
  content: attr(data-role);
  position: absolute;
  top: 0;
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 0.28em;
  padding: 5px 14px 4px;
  color: #10131a;
  background: var(--role-color, var(--muted));
  clip-path: polygon(0 0, 100% 0, calc(100% - 8px) 100%, 0 100%);
  z-index: 1;
}

.pod-player .pod-plate::before {
  left: var(--cut);
  --role-color: linear-gradient(180deg, var(--red-hot), var(--red));
  color: #fff;
}

.pod-p3 .pod-plate::before {
  background: linear-gradient(180deg, #a45cf0, rgba(90, 40, 150, 0.5));
}

.pod-p4 .pod-plate::before {
  background: linear-gradient(180deg, #4bd6a0, rgba(20, 110, 80, 0.5));
}

.pod-rival .pod-plate::before {
  right: var(--cut);
  --role-color: linear-gradient(180deg, var(--yellow), var(--amber));
  clip-path: polygon(8px 0, 100% 0, 100% 100%, 0 100%);
}

.pod-plate-body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  width: 100%;
  min-width: 0;
  padding: 19px 18px 8px;
}

.pod-rival .pod-plate-body {
  align-items: flex-end;
  text-align: right;
}

.pod-name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.1rem, 1.8vw, 1.45rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent, var(--white));
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.55);
}

.pod-tag {
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.pod-plate-empty {
  width: 100%;
  font-family: var(--font-display);
  font-size: 0.85rem;
  letter-spacing: 0.3em;
  color: rgba(147, 160, 177, 0.5);
  text-transform: uppercase;
  text-align: center;
}

/* The 3D window. Transparent by design — the showcase canvas renders exactly
   this rect from behind. Chrome is edges only: hairline + corner brackets. */
.pod-view {
  position: relative;
  flex: 1;
  min-height: 84px; /* compact stage still has to leave a usable window */
  margin-top: 8px;
  border: 1px solid var(--line);
  background: transparent;
  touch-action: none;
  cursor: grab;
}

.pod-view.is-orbiting {
  cursor: grabbing;
}

.pod-view::before,
.pod-view::after {
  content: "";
  position: absolute;
  width: 26px;
  height: 26px;
  border: 2px solid color-mix(in srgb, var(--accent) 70%, transparent);
  pointer-events: none;
}

.pod-view::before {
  top: -1px;
  left: -1px;
  border-right: 0;
  border-bottom: 0;
}

.pod-view::after {
  bottom: -1px;
  right: -1px;
  border-left: 0;
  border-top: 0;
}

.preview-pod.is-armed .pod-view {
  border-color: rgba(255, 210, 61, 0.35);
  outline: 1px dashed rgba(255, 210, 61, 0.4);
  outline-offset: -7px;
  animation: armedPulse 1.6s ease-in-out infinite;
}

/* A FILLED pod gets the same dashed treatment on both sides, in its own bot's
   accent. Previously only the armed pod was dashed, so once you had picked,
   your bay went solid while the rival's stayed dashed and the two sides read
   as different kinds of thing rather than as the same thing twice. */
.preview-pod.is-filled:not(.is-armed) .pod-view {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  outline: 1px dashed color-mix(in srgb, var(--accent) 75%, transparent);
  outline-offset: -7px;
}

@keyframes armedPulse {
  50% {
    outline-color: rgba(255, 210, 61, 0.08);
  }
}

/* Browsing: this bay is showing the bot under the cursor, which is NOT the same
   claim as one you have pressed A on. It keeps the armed dashes so it still
   reads as an open bay, and its plate and pips are held back so the difference
   between "what you are looking at" and "what you have taken" is visible
   without having to read either. Claiming it is what brings them to full. */
.preview-pod.is-preview .pod-plate,
.preview-pod.is-preview .pod-stats,
.preview-pod.is-preview .pod-badge {
  opacity: 0.62;
}

.preview-pod.is-preview .pod-plate {
  filter: saturate(0.65);
}

.preview-pod .pod-plate,
.preview-pod .pod-stats,
.preview-pod .pod-badge {
  transition:
    opacity 0.18s ease,
    filter 0.18s ease;
}

/* The baked stand-in (engine/posters.js). A centred SQUARE, because the bay's
   camera fits the model's bounding sphere against the tighter of its two fov
   angles — so the picture is correctly framed at any pod size as long as it is
   laid into the largest square that fits. Sizing it in CSS rather than in JS
   keeps it right through the stage's own resize without a frame of lag. */
.pod-poster {
  position: absolute;
  top: 50%;
  left: 50%;
  height: 100%;
  width: auto;
  aspect-ratio: 1;
  max-width: 100%;
  max-height: 100%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.pod-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.9vw, 1.55rem);
  letter-spacing: 0.24em;
  line-height: 1.6;
  text-align: center;
  text-transform: uppercase;
  color: rgba(147, 160, 177, 0.4);
  pointer-events: none;
}

.preview-pod.is-filled .pod-empty {
  display: none;
}

/* Mystery opponent: the box stays sealed, so the window shows the "?" flag
   instead of a model. */
.pod-random-glyph {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: clamp(4rem, 9vw, 8rem);
  color: var(--yellow);
  text-shadow: 0 0 34px rgba(255, 210, 61, 0.45), 0 4px 0 rgba(0, 0, 0, 0.6);
  pointer-events: none;
}

.preview-pod.is-random .pod-random-glyph {
  display: flex;
}

.pod-loading {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -23px 0 0 -23px;
  pointer-events: none;
}

.pod-foot {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 8px 2px 0;
}

.pod-rival .pod-foot {
  flex-direction: row-reverse;
}

.pod-badge {
  /* Shrinkable, unlike the stats: a long badge ("DRUM + PUNCH ARMS") is the
     one thing in the foot that can give way, and unshrinkable it overlapped
     the ARM pips. */
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  padding: 3px 10px 2px;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.18em;
  color: #0d0f13;
  background: var(--accent);
  clip-path: polygon(5px 0, 100% 0, calc(100% - 5px) 100%, 0 100%);
}

.pod-badge:empty {
  display: none;
}

/* One row, never wrapped: a wrapped row put PWR beside SPD with ARM alone
   underneath, which reads as a different set of stats. Slimmer pips than the
   roster cards buy the room. */
.pod-stats {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: nowrap;
  gap: 12px;
}

.pod-stats .pip {
  width: 11px;
}

.pod-stats .stat {
  gap: 5px;
}

.pod-stats .stat-label {
  width: 26px;
}

/* Up to three weapon channels, matching the pad: primary is RT, secondary is
   RB, aux is LB (Tantrum's punch arms, which are a third machine).
   Each gets a readiness meter — with a LATCHING weapon (every spinner) the
   button alone cannot show that the rotor is still winding up, and the
   spin-up is the thing the practice viewer exists to teach. */
.pod-controls {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  margin-left: auto;
  font-family: var(--font-display);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  line-height: 1.5;
  color: var(--white);
}

.pod-rival .pod-controls {
  margin-left: 0;
  margin-right: auto;
  align-items: flex-start;
}

/* The channel (RT / RB / LB / LT) is the part the player needs to find on the
   pad, so it carries the accent; the mechanism name is what it does. */
.pod-control {
  white-space: nowrap;
  opacity: 0.82;
}

.pod-control > b {
  color: var(--accent, var(--amber));
  font-weight: 600;
}

.pod-control > i {
  font-style: normal;
  opacity: 0.6;
}

.select-mid {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 0 clamp(4px, 1vw, 14px);
}

.pod-controls-hint {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  line-height: 2;
  text-align: center;
  text-transform: uppercase;
  color: rgba(147, 160, 177, 0.55);
}

.vs-label {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 3.4vw, 2.6rem);
  letter-spacing: 0.04em;
  transform: skewX(var(--skew));
  background: linear-gradient(180deg, #fff, #8b96a5);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 3px 0 rgba(0, 0, 0, 0.5));
}

/* ---------------------------------------------------------------- bot grid
   The full roster, laid out as a grid that reflows to the viewport. The screen
   scrolls when it has to; the pods above shrink to keep that rare. */

.bot-grid {
  --card-min: clamp(104px, 11vw, 150px);
  display: grid;
  flex: 0 0 auto;
  grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr));
  gap: clamp(8px, 1vw, 13px);
  padding: 4px 2px 10px;
}

/* Once a bot is CLAIMED the roster stops being the main event and pays for the
   bay. Narrower cards mean more per row and one row fewer, and since the stage
   simply takes whatever is left (see .select-stage) that row goes straight into
   the viewers — about 120px of it. The badge goes too: at this width it is a
   truncated word, and the pod beside it now says the same thing in full.
   Browsing deliberately does NOT do this; the cursor is still in the grid, and
   resizing it under the cursor is the screen moving while you read it. */
.screen-select.is-showcase .bot-grid {
  --card-min: clamp(58px, 5vw, 74px);
  gap: clamp(6px, 0.7vw, 9px);
}

.screen-select.is-showcase .bot-card-badge {
  display: none;
}

.screen-select.is-showcase .bot-card-name {
  margin-top: 4px;
  margin-bottom: 2px;
  font-size: 0.66rem;
}

/* The roster's cost is ROWS, not columns, so on a short viewport the cards get
   narrower — more per row, fewer rows, and the whole roster stays in one view
   instead of pushing the pods off the top. 1366x768 goes 4 rows -> 2. */
@media (max-height: 860px) {
  .bot-grid {
    --card-min: clamp(92px, 7.5vw, 116px);
  }
}

@media (max-height: 720px) {
  .bot-grid {
    --card-min: clamp(84px, 6.5vw, 104px);
  }
}

.bot-card {
  --accent: var(--muted);
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 0 0 8px;
  border: 1px solid var(--line);
  background:
    var(--carbon),
    linear-gradient(180deg, rgba(34, 40, 50, 0.94), rgba(11, 13, 17, 0.96));
  color: inherit;
  text-align: left;
  cursor: pointer;
  clip-path: polygon(
    12px 0,
    100% 0,
    100% calc(100% - 12px),
    calc(100% - 12px) 100%,
    0 100%,
    0 12px
  );
  transition:
    transform 0.16s ease,
    border-color 0.16s ease,
    box-shadow 0.16s ease;
}

.bot-card::before {
  /* accent blade along the top edge */
  content: "";
  position: absolute;
  top: 0;
  left: 12px;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--accent), transparent 85%);
  opacity: 0.85;
  z-index: 1;
}

.bot-card:hover {
  transform: translateY(-3px);
  border-color: var(--line-strong);
  box-shadow:
    0 14px 30px rgba(0, 0, 0, 0.5),
    0 0 24px color-mix(in srgb, var(--accent) 26%, transparent);
}

.bot-card:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
}

.bot-card.is-disabled {
  opacity: 0.32;
  cursor: not-allowed;
  filter: grayscale(0.8);
}

.bot-card.is-player,
.bot-card.is-rival,
.bot-card.is-p3,
.bot-card.is-p4 {
  border-color: transparent;
}

.bot-card.is-player {
  box-shadow:
    inset 0 0 0 2px var(--red),
    0 0 26px rgba(232, 54, 42, 0.35);
}

.bot-card.is-rival {
  box-shadow:
    inset 0 0 0 2px var(--amber),
    0 0 26px rgba(255, 185, 46, 0.3);
}

.bot-card.is-p3 {
  box-shadow:
    inset 0 0 0 2px #a45cf0,
    0 0 26px rgba(164, 92, 240, 0.3);
}

.bot-card.is-p4 {
  box-shadow:
    inset 0 0 0 2px #4bd6a0,
    0 0 26px rgba(75, 214, 160, 0.3);
}

.bot-card.is-player.is-rival {
  box-shadow:
    inset 0 0 0 2px var(--red),
    inset 0 0 0 4px var(--amber),
    0 0 26px rgba(255, 185, 46, 0.3);
}

.bot-card.is-player::after,
.bot-card.is-rival::after,
.bot-card.is-p3::after,
.bot-card.is-p4::after {
  position: absolute;
  top: 6px;
  right: 0;
  z-index: 2;
  padding: 3px 8px 2px;
  font-family: var(--font-display);
  font-size: 0.56rem;
  letter-spacing: 0.18em;
  clip-path: polygon(8px 0, 100% 0, 100% 100%, 0 100%);
}

.bot-card.is-player::after {
  content: "YOU";
  color: #fff;
  background: linear-gradient(180deg, var(--red-hot), var(--red-deep));
}

.bot-card.is-rival::after {
  content: "RIVAL";
  color: #191203;
  background: linear-gradient(180deg, var(--yellow), var(--amber));
}

.bot-card.is-p3::after {
  content: "P3";
  color: #fff;
  background: linear-gradient(180deg, #b478f5, #6c2fb0);
}

.bot-card.is-p4::after {
  content: "P4";
  color: #04211a;
  background: linear-gradient(180deg, #6ef0be, #2aa87b);
}

.bot-card.is-player.is-rival::after {
  content: "YOU + RIVAL";
}

.bot-card-img {
  position: relative;
  display: block;
  flex: 0 0 auto;
  aspect-ratio: 4 / 3;
  min-height: 0;
  overflow: hidden;
  background:
    radial-gradient(ellipse at 50% 42%, rgba(255, 255, 255, 0.14), transparent 68%),
    #0d0f13;
  border-bottom: 1px solid var(--line);
}

.bot-card-img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.25s ease;
}

.bot-card-img::after {
  /* vignette that unifies mixed studio-photo backgrounds */
  content: "";
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 46px 14px rgba(8, 10, 14, 0.6);
  pointer-events: none;
}

.bot-card:hover .bot-card-img img {
  transform: scale(1.06);
}

.bot-card-name {
  margin: 6px 9px 0;
  font-family: var(--font-display);
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  transform: skewX(var(--skew));
  transform-origin: left bottom;
  color: var(--white);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.55);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bot-card-badge {
  align-self: flex-start;
  max-width: calc(100% - 18px);
  margin: 4px 9px 0;
  padding: 2px 8px 2px;
  font-size: 0.5rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  color: #0d0f13;
  background: var(--accent);
  clip-path: polygon(4px 0, 100% 0, calc(100% - 4px) 100%, 0 100%);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Stat pips (SPD/PWR/ARM) — rendered in the pod foot for the chosen bot. */
.stat {
  display: flex;
  align-items: center;
  gap: 8px;
}

.stat-label {
  width: 30px;
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  color: var(--muted);
}

.pips {
  display: inline-flex;
  gap: 3px;
}

.pip {
  width: 16px;
  height: 6px;
  background: rgba(255, 255, 255, 0.09);
  clip-path: polygon(3px 0, 100% 0, calc(100% - 3px) 100%, 0 100%);
}

.stat-spd .pip.on {
  background: linear-gradient(180deg, #fff, #aab5c2);
}

.stat-pwr .pip.on {
  background: linear-gradient(180deg, var(--red-hot), var(--red-deep));
}

.stat-arm .pip.on {
  background: linear-gradient(180deg, var(--yellow), #c98a10);
}

/* Random opponent — one more compact card at the end of the dock. */
.bot-card-random .random-glyph {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 2rem;
  color: var(--yellow);
  text-shadow: 0 0 18px rgba(255, 210, 61, 0.5), 0 3px 0 rgba(0, 0, 0, 0.6);
  background:
    repeating-linear-gradient(-45deg, rgba(255, 210, 61, 0.14) 0 14px, transparent 14px 28px),
    #0d0f13;
}

.random-note {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1.6;
  color: var(--muted);
}

/* ================================================================== RESULTS */

.screen-results {
  align-items: center;
  justify-content: center;
}

.results-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: min(560px, calc(100vw - 48px));
  padding: 30px 40px 34px;
  text-align: center;
}

.results-panel::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--cut);
  right: 0;
  height: 6px;
  background: linear-gradient(90deg, var(--red), var(--amber) 60%, transparent);
}

#res-kicker {
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: 0.5em;
  text-indent: 0.5em;
  text-transform: uppercase;
  color: var(--muted);
}

#res-kicker[data-tone="win"] {
  color: #6fe08a;
  text-shadow: 0 0 16px rgba(111, 224, 138, 0.5);
}

#res-kicker[data-tone="loss"] {
  color: var(--red-hot);
  text-shadow: 0 0 16px rgba(255, 93, 71, 0.45);
}

.res-image {
  --accent: var(--muted);
  width: min(300px, 60vw);
  aspect-ratio: 5 / 3;
  margin: 14px 0 4px;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  background: radial-gradient(ellipse at 50% 42%, rgba(255, 255, 255, 0.14), transparent 68%), #0d0f13;
  clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
  box-shadow: 0 0 34px color-mix(in srgb, var(--accent) 30%, transparent);
}

.res-image:empty {
  display: none;
}

.res-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

#res-winner-name {
  margin: 2px 0 0;
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 6vw, 3.8rem);
  letter-spacing: 0.05em;
  line-height: 1;
  text-transform: uppercase;
  transform: skewX(var(--skew));
  background: linear-gradient(180deg, #fff, #9aa5b4);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 3px 0 rgba(0, 0, 0, 0.55));
}

#res-method {
  font-family: var(--font-display);
  font-size: 1.05rem;
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  text-transform: uppercase;
  color: var(--amber);
}

#res-line {
  margin-top: 10px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  color: var(--muted);
}

.results-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-top: 24px;
}

/* =============================================================== RESPONSIVE */

@media (max-width: 1100px) {
  .pod-tag {
    display: none;
  }
}

@media (max-width: 960px) {
  .select-head {
    grid-template-columns: auto 1fr auto;
  }

  .pip {
    width: 12px;
  }

  .btn-xl {
    padding: 14px 36px;
    font-size: 1.3rem;
  }

  .pod-controls-hint {
    display: none;
  }
}

/* Narrow: pods sit side by side, the VS column drops below them as a row. */
@media (max-width: 880px) {
  .select-stage {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas:
      "p1 p2"
      "mid mid";
    gap: clamp(10px, 2vw, 16px);
  }

  .pod-player {
    grid-area: p1;
  }

  .pod-rival {
    grid-area: p2;
  }

  .select-mid {
    grid-area: mid;
    flex-direction: row;
    gap: 18px;
    padding: 4px 0 0;
  }
}

@media (max-height: 640px) {
  .bot-card-badge {
    display: none;
  }

  /* The roster is a fixed cost the stage has to be paid out of, and on a short
     window it is three rows tall whatever the cards' width, so the saving has
     to come out of each card's HEIGHT. A wider thumbnail crop and a smaller
     name give back about 20px a row, which is what keeps the pods at a usable
     size here instead of the screen having to scroll. */
  .bot-card-img {
    aspect-ratio: 16 / 10;
  }

  .bot-card-name {
    margin-top: 4px;
    margin-bottom: 2px;
    font-size: 0.7rem;
  }

  .pod-plate {
    min-height: 52px;
  }

  .pod-foot {
    min-height: 38px;
  }
}

/* ---------------------------------------------------- two-controller select
   With a second pad connected both sides of the card are human picks, so the
   AI level is meaningless and the YOU/RIVAL flags become P1/P2. */
body.is-duo .difficulty {
  display: none;
}

body.is-duo .bot-card.is-player::after {
  content: "P1";
}

body.is-duo .bot-card.is-rival::after {
  content: "P2";
}

body.is-duo .bot-card.is-player.is-rival::after {
  content: "P1 + P2";
}

/* The flag on a card is whoever holds it. The owner list lives in a data
   attribute rather than in one class per pairing — with four players who can
   all pick the same machine the pairings are a combinatorial mess, and the only
   thing worth showing is the list. */
body.is-duo .bot-card[data-owners]::after {
  content: attr(data-owners);
  color: #0d0f13;
  background: linear-gradient(180deg, #f2f5ff, #9aa6b8);
}

/* One owner keeps that player's own colour. */
body.is-duo .bot-card[data-owner-count="1"].is-player::after {
  color: #fff;
  background: linear-gradient(180deg, var(--red-hot), var(--red-deep));
}

body.is-duo .bot-card[data-owner-count="1"].is-rival::after {
  color: #191203;
  background: linear-gradient(180deg, var(--yellow), var(--amber));
}

body.is-duo .bot-card[data-owner-count="1"].is-p3::after {
  color: #fff;
  background: linear-gradient(180deg, #b478f5, #6c2fb0);
}

body.is-duo .bot-card[data-owner-count="1"].is-p4::after {
  color: #04211a;
  background: linear-gradient(180deg, #6ef0be, #2aa87b);
}

/* SHARED. Several people on one machine is allowed — a mirror match is a thing
   people want — and no single player colour can say that, because a card
   wearing two of them just looks like whichever rule wins the cascade. A white
   ring means "more than one of you", and the flag names them. */
body.is-duo .bot-card[data-owner-count="2"],
body.is-duo .bot-card[data-owner-count="3"],
body.is-duo .bot-card[data-owner-count="4"] {
  box-shadow:
    inset 0 0 0 2px var(--white),
    0 0 26px rgba(226, 234, 248, 0.32);
}
