/* One key, every game — the account widget's appearance.
 *
 * FIVE IDENTICAL COPIES, one per origin, checked by
 * accounts/tools/parity.py alongside account.js and accounts.py.
 *
 * WHY THIS IS A FILE AND NOT STYLES IN THE SCRIPT
 *
 * The gallery's CSP is `style-src 'self'` with no 'unsafe-inline', which blocks
 * style attributes and injected <style> blocks alike. A widget that styled
 * itself from JavaScript would render as unstyled markup on the busiest origin
 * in the fleet, and would do it quietly — a CSP violation is a console
 * message, not an exception.
 *
 * WHY EVERYTHING IS PREFIXED AND NOTHING INHERITS
 *
 * This drops into five documents with unrelated stylesheets: a dark gallery, a
 * 3D game's HUD, a tower-defence UI, a grid game's menu. Two rules follow.
 *
 * Every selector is prefixed `.sga-`, so nothing here can touch a host page.
 * And every property that affects legibility is stated rather than inherited —
 * font, size, line-height, colour, box-sizing — because a host page that sets
 * `font-size: 62.5%` on :root or a condensed display face on body would
 * otherwise reshape this panel in a way nobody testing the gallery would see.
 *
 * The palette is the gallery's (#0d1117 ground, #58a6ff accent) because it
 * reads as neutral dark UI in all four games, none of which are light.
 */

.sga-root {
  --sga-bg: #161b22;
  --sga-ink: #e6edf3;
  --sga-dim: #8b949e;
  --sga-line: #30363d;
  --sga-accent: #58a6ff;
  --sga-danger: #f85149;
  --sga-good: #3fb950;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  color: var(--sga-ink);
  /* Not paranoia — this list is the bug it prevents. The gallery mounts the
   * widget inside `.brand`, which is `text-transform: uppercase` with
   * `letter-spacing: 0.16em` and `font-weight: 700`. Inherited, that renders a
   * player's handle as "R O B I N" in caps and turns the panel's prose into a
   * shout. Each of these is a property a host page can plausibly set on an
   * ancestor, so each is stated here instead of hoped about. */
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
  font-style: normal;
  font-variant: normal;
  text-align: left;
  text-indent: 0;
  text-shadow: none;
  white-space: normal;
  word-spacing: normal;
}

.sga-root *,
.sga-root *::before,
.sga-root *::after {
  box-sizing: border-box;
}

/* The floating launcher in a game. Bottom-left rather than bottom-right or any
 * top corner: top-right is where every one of these games already puts a
 * close/settings control, and bottom-right is where phone browsers park their
 * own UI. z-index is high because it sits over a WebGL canvas and a HUD. */
.sga-floating {
  position: fixed;
  left: max(12px, env(safe-area-inset-left));
  bottom: max(12px, env(safe-area-inset-bottom));
  z-index: 9000;
}

.sga-inline {
  display: inline-block;
  position: relative;
}

/* ---- launcher ---------------------------------------------------------- */
.sga-launch {
  font: inherit;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  max-width: 12em;
  padding: 0.45em 0.85em;
  border: 1px solid var(--sga-line);
  border-radius: 999px;
  background: rgba(22, 27, 34, 0.92);
  color: var(--sga-ink);
  cursor: pointer;
}

.sga-launch:hover { border-color: var(--sga-accent); }

/* A visible focus ring, always. These sit on top of games whose own CSS
 * sometimes clears outlines globally, and this is the only way to operate the
 * widget from a keyboard. */
.sga-launch:focus-visible,
.sga-root button:focus-visible,
.sga-root input:focus-visible {
  outline: 2px solid var(--sga-accent);
  outline-offset: 2px;
}

.sga-launch::before {
  content: "";
  width: 0.55em;
  height: 0.55em;
  border-radius: 50%;
  background: var(--sga-dim);
  flex: none;
}

.sga-launch.sga-in::before { background: var(--sga-good); }

.sga-launch-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- the scrim --------------------------------------------------------- *
 * The sheet between the panel and whatever is behind it. It exists for the
 * clicks more than for the look: three of these four games read a click on
 * their canvas as "fire" or "place a building", so a click aimed at the panel
 * and landing an inch outside it used to be a shot taken by a player who was
 * reading their account key. It absorbs those, and dismisses on click, which
 * is what everything else on the web does with the space around a dialog.
 *
 * z-index 9000 against the panel's 9001 — one below, deliberately, so the two
 * numbers can be read as the pair they are. Both sit inside .sga-floating's
 * own stacking context in a game and against the page in the gallery, which
 * is the same arrangement the panel already relied on.
 *
 * Explicit sides rather than `inset`, because that shorthand is younger than
 * some of the tablet browsers these games get opened in and this rule failing
 * open would mean an invisible full-page click trap. */
.sga-scrim {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 9000;
  background: rgba(1, 4, 9, 0.55);
}

/* The panel below sets no `display`, so the UA's [hidden] rule is enough for
 * it; this one does not either, but it is stated for both so that a host page
 * with an aggressive `div { display: block }` cannot leave either of them on
 * screen. */
.sga-scrim[hidden] { display: none; }

/* There was a `@media (prefers-color-scheme: light)` here that thinned the
 * scrim to 32%, on the reasoning that 55% black over white is a slab. The
 * reasoning was fine; the question was wrong. prefers-color-scheme reports the
 * OS setting, and not one of the five documents this file drops into asks the
 * OS anything. Four are dark whatever the laptop says — <meta name="theme-color">
 * is #0d1117 on the gallery and Tank Arena, #070a11 on Landfall, #0c1410 on
 * Perennial — and Crosskeep is a pale sky gradient whatever the laptop says.
 * So the override fired on the wrong four pages and not on the one it was
 * written for: a player on a light-set laptop, which is most of them, got a
 * scrim over Tank Arena so thin the game read straight through a modal dialog
 * holding their account key.
 *
 * Keyed off the signal the widget itself uses, the answer is a constant. Every
 * palette above is a fixed dark one, chosen once and not conditional on
 * anything, and the scrim is part of that panel rather than part of the page
 * behind it — so it is the dark-page veil declared above, on all five origins.
 * Crosskeep pays a slightly heavier veil than it needs, which is the ordinary
 * look of a dark modal over a light page and nobody's bug.
 *
 * If a host page ever gains a real light mode it will need a signal a
 * stylesheet can see — a class or attribute on <html>, set by that page — and
 * this is where the rule hanging off it goes. There is no such signal today,
 * and guessing at one from the OS was worse than not asking. */

/* ---- panel ------------------------------------------------------------- */
.sga-panel {
  position: fixed;
  /* Centred and clamped rather than anchored to the launcher: the launcher is
   * bottom-left in a game and inline in a header, and a panel that hung off it
   * would need two layouts and would fall off a small screen in one of them. */
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(30rem, calc(100vw - 2rem));
  max-height: min(40rem, calc(100vh - 2rem));
  overflow-y: auto;
  z-index: 9001;
  background: var(--sga-bg);
  border: 1px solid var(--sga-line);
  border-radius: 12px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.6);
  padding: 0;
  /* -webkit-overflow-scrolling so the achievement list scrolls with momentum
   * inside the panel on iOS instead of dragging the page behind it. */
  -webkit-overflow-scrolling: touch;
}

.sga-panel[hidden] { display: none; }

.sga-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1.1rem;
  border-bottom: 1px solid var(--sga-line);
  position: sticky;
  top: 0;
  background: var(--sga-bg);
}

.sga-head h2 {
  font-size: 1.05rem;
  margin: 0;
  font-weight: 600;
}

.sga-close {
  font: inherit;
  font-size: 1.4rem;
  line-height: 1;
  padding: 0 0.3em;
  border: 0;
  background: none;
  color: var(--sga-dim);
  cursor: pointer;
}

.sga-close:hover { color: var(--sga-ink); }

.sga-body { padding: 1.1rem; }

.sga-body > * + * { margin-top: 0.75rem; }

.sga-note { margin: 0; color: var(--sga-ink); }
.sga-fine { margin: 0; color: var(--sga-dim); font-size: 0.85rem; }
.sga-msg { margin: 0; color: var(--sga-dim); font-size: 0.9rem; min-height: 1.2em; }

.sga-label {
  display: block;
  font-size: 0.85rem;
  color: var(--sga-dim);
  margin: 0;
}

.sga-input {
  font: inherit;
  width: 100%;
  padding: 0.55em 0.7em;
  border: 1px solid var(--sga-line);
  border-radius: 8px;
  background: #0d1117;
  color: var(--sga-ink);
  /* A key is upper-case grouped text and gets read back character by character
   * off a piece of paper, so it is set in a monospace face where 0/O and 1/l
   * are distinguishable — the same reason keys.py leaves those letters out of
   * the alphabet in the first place. */
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  letter-spacing: 0.04em;
}

.sga-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
}

.sga-row .sga-input { flex: 1 1 12rem; }

.sga-primary,
.sga-secondary,
.sga-danger {
  font: inherit;
  padding: 0.5em 1em;
  border-radius: 8px;
  border: 1px solid transparent;
  cursor: pointer;
  /* 44px is the touch target these four games already build their menus to,
   * and this widget is opened mid-match on a phone. */
  min-height: 44px;
}

.sga-primary { background: var(--sga-accent); color: #08131f; font-weight: 600; }
.sga-secondary { background: transparent; border-color: var(--sga-line); color: var(--sga-ink); }
.sga-danger { background: transparent; border-color: var(--sga-danger); color: var(--sga-danger); }

.sga-primary:hover { filter: brightness(1.08); }
.sga-secondary:hover { border-color: var(--sga-accent); }
.sga-danger:hover { background: rgba(248, 81, 73, 0.12); }

.sga-primary[disabled],
.sga-secondary[disabled],
.sga-danger[disabled] { opacity: 0.55; cursor: default; }

.sga-link {
  font: inherit;
  padding: 0;
  border: 0;
  background: none;
  color: var(--sga-accent);
  text-decoration: underline;
  cursor: pointer;
}

.sga-alt { margin: 0; }

/* ---- the key ----------------------------------------------------------- */
.sga-key {
  margin: 0;
  padding: 0.7em 0.6em;
  border: 1px dashed var(--sga-accent);
  border-radius: 8px;
  background: #0d1117;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  /* clamp so a twenty-two character key fits a 320px phone without wrapping
   * mid-group, and still reads large on a desktop. */
  font-size: clamp(0.95rem, 4.4vw, 1.4rem);
  letter-spacing: 0.06em;
  text-align: center;
  /* all-around select, so a double-tap on a phone takes the whole key rather
   * than one dash-separated group of it. */
  user-select: all;
  -webkit-user-select: all;
  word-break: break-all;
}

.sga-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding-top: 0.25rem;
  border-top: 1px solid var(--sga-line);
}

/* ---- the record -------------------------------------------------------- */
.sga-stats > * + * { margin-top: 1rem; }

.sga-game h3 {
  font-size: 0.95rem;
  margin: 0 0 0.4rem;
  padding-bottom: 0.25rem;
  border-bottom: 1px solid var(--sga-line);
  font-weight: 600;
}

.sga-dl {
  display: grid;
  /* Two columns of label/value pairs on anything wider than a phone, one on a
   * phone. auto-fit rather than a media query so it also does the right thing
   * inside the gallery's inline placement, which is narrower than the page. */
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0.15rem 1rem;
  margin: 0;
}

.sga-dl dt { color: var(--sga-dim); font-size: 0.85rem; }
.sga-dl dd { margin: 0 0 0.35rem; font-variant-numeric: tabular-nums; }

.sga-awards {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.3rem;
}

.sga-awards li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.5rem;
  padding: 0.35em 0.5em;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.03);
}

.sga-awards li::before {
  content: "\2713";
  grid-row: span 2;
  align-self: center;
  color: var(--sga-good);
  font-weight: 700;
}

.sga-locked { opacity: 0.5; }
.sga-locked::before { content: "\25cb"; color: var(--sga-dim); font-weight: 400; }

.sga-aname { font-weight: 600; font-size: 0.9rem; }
.sga-ahint { color: var(--sga-dim); font-size: 0.82rem; }

/* Respect a person who has asked for less motion; there is no animation here
 * to speak of, but the hover filter is enough to be worth switching off. */
@media (prefers-reduced-motion: reduce) {
  .sga-primary:hover { filter: none; }
}

/* ---- the native menu button -------------------------------------------- *
 * Three of the four games put a "Show my key" entry in their own menu, and
 * none of them has a general-purpose button class to hang it on — their menu
 * buttons are styled by id (#playBtn, #mplay). Rather than add a rule to three
 * more stylesheets, the button wears this class, and it lives here because
 * this file is already loaded on all five origins.
 *
 * Crosskeep is the exception and uses its own `big-btn alt` / `tiny-btn`,
 * because it HAS those classes and a native-looking button is better than a
 * near-miss.
 *
 * Colours are literal rather than the custom properties above: those are
 * declared on `.sga-root`, and this button sits inside the game's menu, well
 * outside it. Inheriting nothing is the whole point.
 */
.sga-menu-btn {
  display: block;
  width: 100%;
  margin: 0.5rem 0 0;
  padding: 0.6em 1em;
  min-height: 44px;
  font: inherit;
  font-size: 0.9rem;
  /* The three host menus are variously uppercase, letter-spaced and bold. Same
   * reasoning as the reset on .sga-root: stated, not inherited. */
  text-transform: none;
  letter-spacing: normal;
  font-weight: 500;
  color: #8b949e;
  background: transparent;
  border: 1px solid #30363d;
  border-radius: 8px;
  cursor: pointer;
}

.sga-menu-btn:hover {
  color: #e6edf3;
  border-color: #58a6ff;
}

.sga-menu-btn:focus-visible {
  outline: 2px solid #58a6ff;
  outline-offset: 2px;
}

/* [hidden] loses to the display above on specificity grounds, and this button
 * ships hidden — account.js reveals it only once it knows accounts work.
 * Without this rule the button would be visible on every box, including the
 * ones where pressing it does nothing. */
.sga-menu-btn[hidden] {
  display: none;
}
