/* MK3 Online Battle Network - pairing site.
   Self-hosted fonts only; the page makes zero third-party requests. */

@font-face {
  font-family: "Chakra Petch";
  src: url("ChakraPetch-SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Rajdhani";
  src: url("Rajdhani-SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #121216;
  --panel: #1e1e24;
  --panel-edge: #2c2c34;
  --gold: #f5a524;
  --gold-dim: #c9871d;
  --text: #e8e8ea;
  --muted: #a0a0a8;
  --danger: #ff6b5e;
  --live: #4ad06a;
  --ui: "Chakra Petch", "Segoe UI", system-ui, sans-serif;
  --display: "Rajdhani", "Chakra Petch", "Segoe UI", system-ui, sans-serif;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* The page never scrolls: it is one screen with a header and a centred panel.
   100dvh rather than 100vh so mobile browsers that shrink the viewport when the
   address bar retracts do not leave a strip of body scrolling behind. */
html, body { height: 100%; }

body {
  margin: 0;
  overflow: hidden;
  background: var(--bg);
  /* A slow gold bloom behind the panel, so the page reads as lit rather than
     flat black. Pure CSS, no image request. */
  background-image:
    radial-gradient(ellipse 70% 50% at 50% 0%, rgba(245, 165, 36, 0.10), transparent 70%),
    linear-gradient(180deg, #16161b 0%, var(--bg) 45%);
  background-repeat: no-repeat;
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--ui);
  font-weight: 600;
  font-size: 16px;
  line-height: 1.55;
}

.shell {
  height: 100dvh;
  display: flex;
  flex-direction: column;
}

/* --- site header ------------------------------------------------------- */

.site-head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 22px;
  height: 62px;
  border-bottom: 1px solid var(--panel-edge);
  background: rgba(10, 10, 13, 0.72);
}

.logo {
  font-family: var(--display);
  font-size: 26px;
  line-height: 1;
  letter-spacing: 0.06em;
  color: var(--gold);
  text-decoration: none;
  text-shadow: 0 0 18px rgba(245, 165, 36, 0.30);
  white-space: nowrap;
}

/* The signed-in half of the header: the account name beside the sign-out
   control, in place of the LOGIN button. min-width:0 with an ellipsis because
   the name is the part of an email address before the @ and nothing bounds its
   length - without it, one long name pushes the sign-out button off a phone. */
.acct {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.acct-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--gold);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.08em;
}

/* --- stage: everything else, centred both ways ------------------------- */

.stage {
  flex: 1;
  min-height: 0;               /* lets the child shrink instead of pushing the page taller */
  display: grid;
  place-items: center;
  padding: 20px 16px;
  /* Only the stage may scroll, and only when the viewport is too short for the
     panel. The page itself still never does, which is the point. */
  overflow-y: auto;
}

.stage > * {
  width: 100%;
  max-width: 460px;
}

/* --- landing page ------------------------------------------------------ */

/* The landing page is one screenshot, centred. justify-items rather than a width
   on the image, so the image keeps its own size instead of being stretched to
   the column. */
.home {
  display: grid;
  justify-items: center;
}

/* The screenshot fits the space that is actually left, not a fixed size: the
   page must never scroll, and the room between the header and the footer varies
   with the window. Capping at the image's natural 964px stops it being scaled UP
   and going soft - it is pixel art, and enlarging it is worse than showing it
   small. min() rather than a media query because there is no breakpoint here,
   just "whichever runs out first". */
.shot {
  display: block;
  /* Both maxima, and NEITHER a width nor a height. That combination is the one
     that keeps the aspect ratio: the browser shrinks the image until it satisfies
     both bounds and stops. Setting width:100% alongside max-height instead makes
     the BOX full width while the height is clipped, so the element ends up the
     wrong shape and the border below frames empty space either side of the
     picture - which is exactly what it did. object-fit cannot rescue that; it
     only decides how the content sits inside a box that is already wrong. */
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: calc(100dvh - 190px);
  border: 1px solid var(--panel-edge);
  border-radius: 2px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
}

/* The landing page is the one page with enough content to threaten the
   no-scrollbar rule, and it was overflowing a 720px-tall viewport by about a
   dozen pixels. Trimming the stage's own padding here rather than globally,
   because the pairing panel is short and looks better with the room. */
.stage:has(> .home) { padding: 12px 16px; }

.stage > .home { max-width: 964px; }

/* --- panel ------------------------------------------------------------- */

.panel {
  background: var(--panel);
  border: 1px solid var(--panel-edge);
  border-top: 2px solid var(--gold);
  border-radius: 2px;
  padding: 26px 24px 24px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
}

.panel h1 {
  margin: 12px 0 10px;
  font-family: var(--display);
  font-size: 25px;
  line-height: 1.2;
  letter-spacing: 0.02em;
  font-weight: 600;
}

.panel p { margin: 0 0 12px; }
.panel p:last-child { margin-bottom: 0; }

.panel-notice, .panel-success { text-align: left; }

.gold { color: var(--gold); }
.muted { color: var(--muted); }
.small { font-size: 13.5px; line-height: 1.5; }

/* --- badges ------------------------------------------------------------ */

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 2px;
  font-size: 10.5px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  text-transform: uppercase;
}

.badge-dead {
  color: var(--danger);
  background: rgba(255, 107, 94, 0.10);
  border: 1px solid rgba(255, 107, 94, 0.34);
}

.badge-live {
  color: var(--live);
  background: rgba(74, 208, 106, 0.10);
  border: 1px solid rgba(74, 208, 106, 0.34);
}

/* .badge-info is gone with the panel it existed for. It was the neutral badge on
   the "no code was supplied" page, and that page no longer exists: /link with no
   code is the site's sign-in form now, not a notice about where sign-in starts.
   Nothing else used it. */

/* The pairing code used to be rendered here as a large input for the player to
   compare against their game screen. Both the markup and these rules are gone:
   the code is no longer shown, because the loopback redirect proves the browser
   and the game share a machine and no human comparison is asked for. */

/* --- tabs -------------------------------------------------------------- */

.tabs {
  display: flex;
  gap: 2px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--panel-edge);
}

.tab {
  flex: 1 1 0;
  appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: 10px 6px;
  color: var(--muted);
  font-family: var(--ui);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-indent: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.12s linear, border-color 0.12s linear;
}

.tab:hover { color: var(--text); }

.tab.is-active {
  color: var(--gold);
  border-bottom-color: var(--gold);
}

/* --- form -------------------------------------------------------------- */

.field { margin-bottom: 16px; }

.field label {
  display: block;
  margin-bottom: 6px;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-indent: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.field input {
  display: block;
  width: 100%;
  padding: 11px 12px;
  background: #141419;
  border: 1px solid var(--panel-edge);
  border-radius: 2px;
  color: var(--text);
  font-family: var(--ui);
  font-weight: 600;
  font-size: 16px; /* 16px keeps iOS Safari from zooming on focus */
  line-height: 1.3;
  transition: border-color 0.12s linear, box-shadow 0.12s linear;
}

.field input::placeholder { color: #5c5c66; }

.field input:focus {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 2px rgba(245, 165, 36, 0.18);
}

.field input:disabled { opacity: 0.55; }

/* --- in-field controls: clear, and show/hide password ------------------- */

/* app.js wraps each input in this and puts the button inside, so the markup
   stays free of five near-identical copies of the same two controls. */
.field-box {
  position: relative;
  display: block;
}

/* Room for the button, so a long address does not run underneath it. */
.field-box input { padding-right: 40px; }

.field-btn {
  position: absolute;
  right: 5px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

.field-btn:hover { color: var(--text); background: #22222a; }

.field-btn:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: -2px;
}

.field-btn svg {
  width: 17px;
  height: 17px;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The clear button only exists while there is something to clear; the eye is
   always there. Hidden with display:none rather than visibility so it cannot be
   tabbed to while invisible. */
.field-btn[hidden] { display: none; }

/* Edge and Chrome draw their own reveal control inside password inputs. Without
   these the field would show two eyes side by side, one of them ours. */
.field-box input::-ms-reveal,
.field-box input::-ms-clear { display: none; }

/* --- buttons ----------------------------------------------------------- */

.btn {
  display: block;
  width: 100%;
  padding: 13px 16px;
  border: 1px solid var(--gold);
  border-radius: 2px;
  background: var(--gold);
  color: #17130a;
  font-family: var(--ui);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.18em;
  text-indent: 0.18em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.12s linear, border-color 0.12s linear;
}

.btn:hover { background: #ffb63c; border-color: #ffb63c; }
.btn:active { background: var(--gold-dim); border-color: var(--gold-dim); }

.btn:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

/* The header's LOGIN. Outlined rather than filled: the filled gold button is
   the one action inside the panel, and two solid golds competing on one screen
   would leave neither reading as the primary. */
.btn-ghost {
  display: inline-block;
  width: auto;
  padding: 9px 20px;
  background: transparent;
  border: 1px solid var(--gold);
  color: var(--gold);
  font-size: 12px;
}

.btn-ghost:hover { background: rgba(245, 165, 36, 0.12); border-color: #ffb63c; color: #ffb63c; }
.btn-ghost:active { background: rgba(245, 165, 36, 0.20); }

/* --- panel close ------------------------------------------------------- */

.panel { position: relative; }

/* An <a href="/"> now, not a button: closing the panel means going to the
   landing page. Flex centring and text-decoration:none are here because an
   anchor does neither on its own, where a button centred its label for free. */
.panel-close {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--muted);
  text-decoration: none;
  font-family: var(--ui);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
}

.panel-close:hover { color: var(--text); background: #26262e; }

.panel-close:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: -2px;
}

.btn[disabled], .btn[aria-busy="true"] {
  background: #4a4436;
  border-color: #4a4436;
  color: #8d8878;
  cursor: progress;
}

.btn-large {
  margin-top: 18px;
  padding: 17px 16px;
  font-size: 15px;
}

/* --- messages ---------------------------------------------------------- */

/* Qualified with .panel deliberately. A bare .alt loses to `.panel p` above,
   which is a class plus an element and therefore more specific - so the 14px
   top margin written here never actually applied, and "Forgot password?" sat
   flush against the SIGN IN button. Anything that needs to override `.panel p`
   has to be at least as specific. */
/* Both forms occupy the same grid cell, so the panel is always as tall as the
   taller of the two and switching tabs cannot resize it. The sign-in pane is the
   taller one - it carries the "Forgot password?" line - and without this the box
   jumped every time somebody moved between the tabs.

   The inactive pane keeps its box and is hidden with visibility, which also
   takes it out of the tab order and away from screen readers. Overriding
   [hidden] this way is deliberate: the script still sets the attribute, so the
   semantics stay honest, but display:none would collapse the cell and bring the
   jump straight back. */
.panes { display: grid; }

.panes > .pane { grid-area: 1 / 1; }

.panes > .pane[hidden] {
  display: block;
  visibility: hidden;
}

.panel .alt {
  margin: 14px 0 0;
  text-align: center;
  font-size: 13.5px;
}

/* "Forgot password?" only. A modifier rather than changing .alt itself, because
   the other .alt on this screen is the multi-line note under the register form,
   and a right-aligned ragged-left paragraph reads badly. */
.panel .alt-right {
  margin-top: 18px;
  text-align: right;
}

.alt a, .foot a { color: var(--gold); text-decoration: none; }
.alt a:hover, .foot a:hover { text-decoration: underline; }

.error {
  margin: 16px 0 0;
  padding: 10px 12px;
  background: rgba(255, 107, 94, 0.09);
  border: 1px solid rgba(255, 107, 94, 0.36);
  border-left: 2px solid var(--danger);
  border-radius: 2px;
  color: var(--danger);
  font-size: 14px;
  line-height: 1.45;
}

.error[hidden] { display: none; }

/* --- lists and callouts ------------------------------------------------ */

.steps {
  margin: 0 0 14px;
  padding-left: 20px;
  color: var(--muted);
}

.steps li { margin-bottom: 6px; }
.steps strong { color: var(--text); }

.callout {
  margin: 18px 0;
  padding: 14px 16px;
  background: #17171c;
  border: 1px solid var(--panel-edge);
  border-left: 2px solid var(--gold);
  border-radius: 2px;
}

.callout-label {
  display: block;
  margin-bottom: 10px;
  font-size: 10.5px;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

.callout .steps { margin-bottom: 0; }

/* --- admin ladder ------------------------------------------------------ */

/* The ladder takes the whole screen, unlike every other page here. Those are
   forms and notices - a 460px column is the readable width for them, and
   stretching one across a wide monitor would only put more air between a label
   and its field. A table is the opposite: every extra pixel is another row
   visible without scrolling, and the columns have somewhere useful to put the
   width.

   Two rules do it. place-items:stretch overrides the .stage centring for this
   page only, so the panel fills the cell instead of sitting in the middle of
   it, and max-width:none lifts the 460px cap that .stage > * applies. */
.stage:has(> .admin) {
  place-items: stretch;
  padding: 14px 16px;
}

.stage > .admin { max-width: none; }

/* A column, so the table can be told to take whatever height is left after the
   heading, the figures and the note above it. */
.admin {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.admin { text-align: left; }
.admin h1 { text-align: left; }
.admin-count { margin-bottom: 14px; flex: none; }

/* Title on the left, refresh on the right, baselines aligned. The h1 carries a
   top margin from .panel h1 that would push the button out of line, so it is
   cancelled here rather than by weakening the shared rule. */
.admin-head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.admin-head h1 { margin-top: 0; }

.admin-refresh { flex: none; }

/* The live figures. auto-fit so they wrap rather than crush on a phone, but
   capped at 180px each and packed to the left: now that the panel is full
   width, three 1fr columns would blow three small numbers up to a third of a
   monitor each. */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(90px, 180px));
  justify-content: start;
  gap: 10px;
  margin: 4px 0 14px;
  flex: none;
}

.stat {
  padding: 10px 12px;
  background: #17171c;
  border: 1px solid var(--panel-edge);
  border-radius: 2px;
}

.stat-num {
  display: block;
  font-family: var(--display);
  font-size: 26px;
  line-height: 1.1;
}

.stat-label {
  display: block;
  margin-top: 2px;
  font-size: 10.5px;
  letter-spacing: 0.16em;
  text-indent: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* The scroll belongs here and nowhere else. The page never scrolls and .stage
   only does when the viewport is too short for the panel itself, so a long
   ladder has to move inside its own box - otherwise a hundred accounts push the
   footer off the screen and the header row out of sight with it.

   flex:1 with min-height:0 rather than a calc() of dvh minus a guessed pixel
   count. The old sum had to be kept in step by hand with the height of the
   heading, the figures and the note - it was already wrong once, and a second
   media query existed only to patch it. The flex version measures whatever is
   actually there. min-height:0 is the part that is easy to forget: without it a
   flex item refuses to shrink below its content and the table pushes the panel
   past the bottom of the screen instead of scrolling. */
.table-wrap {
  flex: 1;
  min-height: 120px;
  overflow-y: auto;
  border: 1px solid var(--panel-edge);
  border-radius: 4px;
}

/* Keyboard scrolling needs the container focusable, and a focusable container
   needs a visible focus ring - it is the only affordance saying it is the thing
   that moves. */
.table-wrap:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.ladder {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

/* Sticky rather than a separately-scrolled header table: one table keeps the
   columns aligned by construction, where two tables have to be kept in step by
   hand and drift the moment a long address widens a column. The header needs
   its own opaque background, since rows scroll underneath it. */
.ladder thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: #24242c;
  border-bottom: 1px solid var(--panel-edge);
  padding: 10px 12px;
  font-family: var(--ui);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-indent: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: left;
  white-space: nowrap;
}

.ladder tbody td {
  padding: 9px 12px;
  border-bottom: 1px solid rgba(44, 44, 52, 0.7);
  color: var(--text);
  font-weight: 600;
}

.ladder tbody tr:last-child td { border-bottom: none; }
.ladder tbody tr:nth-child(even) td { background: rgba(255, 255, 255, 0.018); }
.ladder tbody tr:hover td { background: rgba(245, 165, 36, 0.06); }

/* Column widths, now that the table is as wide as the window. Left to itself
   the browser gives the slack to the widest column, so the email would sprawl
   and the three numbers would sit marooned against the right edge with a hand's
   width of nothing before them.
   
   Percentages rather than pixels so it holds at any size: the two text columns
   share the space and the numeric ones stay just wide enough for their headings.
   table-layout is deliberately NOT fixed - these are hints, and a narrow phone
   should still be allowed to give the email whatever it needs. */
.ladder .col-email {
  width: 45%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ladder .col-name { width: 25%; color: var(--muted); white-space: nowrap; }

.ladder th.col-num, .ladder td.col-num {
  width: 10%;
  text-align: right;
  white-space: nowrap;
}
.ladder .rating { color: var(--gold); font-family: var(--display); font-size: 16px; }

/* --- footer ------------------------------------------------------------ */

.foot {
  flex: none;
  text-align: center;
  padding: 10px 16px 14px;
  font-size: 11px;
  letter-spacing: 0.1em;
  color: #6c6c76;
}

.foot .dot { margin: 0 8px; }

/* --- narrow screens ---------------------------------------------------- */

@media (max-width: 420px) {
  .site-head { height: 54px; padding: 0 14px; }
  .logo { font-size: 21px; }
  .btn-ghost { padding: 8px 14px; font-size: 11px; letter-spacing: 0.1em; text-indent: 0.1em; }
  .stage { padding: 16px 12px; }
  .panel { padding: 22px 16px 20px; }
  .panel h1 { font-size: 22px; }
  .tab { font-size: 11px; letter-spacing: 0.08em; text-indent: 0.08em; }
  .btn { letter-spacing: 0.12em; text-indent: 0.12em; }
  /* The ladder drops to the essentials on a phone: the local part identifies
     the account well enough there, and dropping the column is better than an
     email cell squeezed to three characters and an ellipsis. */
  .ladder { font-size: 13px; }
  .ladder thead th, .ladder tbody td { padding: 8px 8px; }
  .ladder .col-email { display: none; }
}

/* A short viewport - a laptop with devtools docked, or a phone in landscape -
   must not clip the form. The stage scrolls internally; the page still does not. */
@media (max-height: 620px) {
  .panel { padding: 20px 20px 18px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
