/* fheroes2 online battle lobby.
 *
 * Two screens share this: the host page (index.html) and the join page (spectate.html). Both are
 * a single centred card that walks one player through one decision at a time, so the styling here
 * is deliberately plain and unbranded -- the game's own artwork appears the moment the lobby is
 * dismissed, and a lobby that tried to compete with it only made the wait look busier.
 *
 * No image files and no web fonts: the guest downloads no game data at all, and the published
 * build carries none of the original game's assets. */

:root {
  /* Parchment and ink, the same materials as the site around it and as the chat and waiting panel
     inside the game. The lobby used to be a dark console bolted onto a page that is now a written
     one; the seam showed the moment anybody clicked through from the front page. */
  --fh2-ui-bg: rgba(239, 228, 198, 0.96);
  --fh2-ui-card: #f3e9cf;
  --fh2-ui-sunken: #e5d6ad;
  --fh2-ui-line: rgba(74, 52, 25, 0.3);
  --fh2-ui-text: #2c1d0c;
  --fh2-ui-dim: #6a563a;
  --fh2-ui-faint: #8b7551;
  --fh2-ui-gold: #8a6420;
  --fh2-ui-green: #46662f;
  --fh2-ui-red: #8c2f22;
  --fh2-ui-font: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --fh2-ui-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

#lobby {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--fh2-ui-bg);
  color: var(--fh2-ui-text);
  font-family: var(--fh2-ui-font);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Taller than the window on a short screen otherwise puts the buttons out of reach. */
  overflow-y: auto;
  padding: 24px;
  box-sizing: border-box;
}

#lobby[hidden] { display: none; }

.lobby-card {
  margin: auto;
  background: linear-gradient(180deg, #fbf3de, var(--fh2-ui-card));
  border: 1px solid var(--fh2-wood, #4a3419);
  border-radius: 5px;
  padding: 30px 32px;
  max-width: 520px;
  width: 100%;
  box-shadow: 0 10px 34px rgba(74, 52, 25, 0.28), inset 0 0 0 1px rgba(255, 255, 255, 0.5);
}

.lobby-card h1 {
  margin: 0 0 6px;
  font-size: 1.55rem;
  line-height: 1.2;
  color: var(--fh2-ui-text);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.lobby-card .subtitle {
  margin: 0 0 22px;
  color: var(--fh2-ui-dim);
  font-size: 0.92rem;
  line-height: 1.55;
}

.lobby-card h2 {
  margin: 0 0 10px;
  font-size: 0.72rem;
  color: var(--fh2-ui-gold);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 600;
}

.lobby-step[hidden] { display: none; }

.lobby-card a,
.lobby-note a { color: var(--fh2-ui-gold); text-underline-offset: 3px; }
.lobby-card a:hover,
.lobby-note a:hover { color: var(--fh2-ui-text); }

/* ---- buttons ---- */

.lobby-card button {
  font-family: inherit;
  font-size: 0.95rem;
  color: var(--fh2-ui-text);
  background: rgba(255, 252, 240, 0.75);
  border: 1px solid var(--fh2-ui-line);
  border-radius: 4px;
  padding: 12px 16px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}

.lobby-card button:hover { background: #fffdf4; border-color: var(--fh2-wood, #4a3419); }
.lobby-card button:active { transform: translateY(1px); }
.lobby-card button:focus-visible { outline: 2px solid var(--fh2-ui-gold); outline-offset: 2px; }
.lobby-card button:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }
.lobby-card button:disabled:hover { background: rgba(255, 252, 240, 0.75); }

.lobby-card button.primary {
  background: linear-gradient(180deg, #4f7238, #3c5a2a);
  border-color: #2f4a20;
  color: #f2e8cd;
}
.lobby-card button.primary:hover { background: linear-gradient(180deg, #5a8140, #456630); }

.lobby-card button.ghost {
  background: transparent;
  color: var(--fh2-ui-dim);
}
.lobby-card button.ghost:hover { background: #fffdf4; color: var(--fh2-ui-text); }

.lobby-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

/* The display above would otherwise beat `hidden` (see .listing-private[hidden]): the spectate page's
   "Rejoin your tournament ()" button and the solo page's load escape both showed when they shouldn't. */
.lobby-actions[hidden] { display: none; }

.lobby-actions.stack { flex-direction: column; }
.lobby-actions.end { justify-content: flex-end; }
.lobby-actions button { flex: 1; min-width: 130px; }
.lobby-actions.end button { flex: 0 0 auto; }

/* The two front-door choices. Each carries a second line saying what it means, because "Host"
   and "Join" alone leave the player guessing which one needs their game files. */
button.choice {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  padding: 15px 18px;
  text-align: left;
}

.btn-title { font-size: 1rem; font-weight: 600; }
.btn-sub { font-size: 0.78rem; opacity: 0.78; font-weight: 400; }

/* ---- room code ---- */

.room-code {
  font-family: var(--fh2-ui-mono);
  font-size: 2.1rem;
  font-weight: 600;
  /* The indent balances the trailing letter-space so the code stays optically centred. */
  letter-spacing: 0.28em;
  text-indent: 0.28em;
  text-align: center;
  padding: 18px 12px;
  background: var(--fh2-ui-sunken);
  border: 1px solid var(--fh2-ui-line);
  border-radius: 10px;
  color: var(--fh2-ui-gold);
  user-select: all;
  cursor: copy;
}

.room-code.placeholder { color: rgba(74, 52, 25, 0.35); }

/* The code sits under the match name and only while the game is private, so it needs a line saying
   why it is suddenly there. */
#host-code-block {
  margin-top: 16px;
}

.code-label {
  margin: 0 0 8px;
  font-size: 0.76rem;
  color: var(--fh2-ui-dim);
}

.code-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.code-actions button {
  flex: 1;
  font-size: 0.82rem;
  padding: 9px 12px;
}

.code-input {
  width: 100%;
  box-sizing: border-box;
  text-align: center;
  font-family: var(--fh2-ui-mono);
  font-size: 1.9rem;
  font-weight: 600;
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  text-transform: uppercase;
  padding: 16px 10px;
  background: var(--fh2-ui-sunken);
  border: 1px solid var(--fh2-ui-line);
  border-radius: 10px;
  color: var(--fh2-ui-text);
}

.code-input:focus {
  outline: none;
  border-color: var(--fh2-ui-gold);
  box-shadow: 0 0 0 3px rgba(217, 180, 90, 0.16);
}

.code-input::placeholder { color: rgba(74, 52, 25, 0.4); }

/* ---- the name a host is listed under ----
 *
 * Not a .code-input: that one is sized for six monospaced characters read out over a call, and a
 * name is ordinary prose. It borrows the frame and the focus ring so the two still look related.
 */

.listing {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--fh2-ui-line);
}

.listing-label {
  display: block;
  margin-bottom: 6px;
  font-size: 0.78rem;
  color: var(--fh2-ui-dim);
}

.name-row {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

.name-input {
  flex: 1;
  min-width: 0;
  box-sizing: border-box;
  font-family: inherit;
  font-size: 0.95rem;
  padding: 10px 12px;
  background: var(--fh2-ui-sunken);
  border: 1px solid var(--fh2-ui-line);
  border-radius: 8px;
  color: var(--fh2-ui-text);
}

.name-input:focus {
  outline: none;
  border-color: var(--fh2-ui-gold);
  box-shadow: 0 0 0 3px rgba(217, 180, 90, 0.16);
}

button.name-save {
  flex: 0 0 auto;
  padding: 10px 16px;
  font-size: 0.84rem;
}

/* Greyed rather than hidden: a button that appears only once you have typed is a button nobody
   knows is coming, and the disabled state is itself the answer to "is there anything to save?". */
button.name-save:disabled {
  opacity: 0.4;
  cursor: default;
}

/* ---- what the name field is currently saying ---- */

.name-status {
  margin: 8px 0 0;
  font-size: 0.76rem;
  line-height: 1.45;
  color: var(--fh2-ui-faint);
}

.name-status.hint { color: var(--fh2-ui-gold); }
.name-status.ok { color: var(--fh2-ui-green); }
.name-status.error { color: var(--fh2-ui-red); }

.listing.is-dirty .name-input { border-color: var(--fh2-ui-gold); }

.listing.is-saved .name-input {
  border-color: var(--fh2-ui-green);
  animation: fh2-name-saved 1.4s ease-out;
}

/* A single outward pulse: enough to catch the eye that was on the button, gone before it nags. */
@keyframes fh2-name-saved {
  from { box-shadow: 0 0 0 0 rgba(79, 164, 107, 0.45); }
  to { box-shadow: 0 0 0 8px rgba(79, 164, 107, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .listing.is-saved .name-input { animation: none; }
}

/* ---- the scenario picker ----
   The engine's own map list, on the page, because the map has to be settled before the room can be
   listed - see fheroes2::WebBridge::publishMapList. Shaped like the match-name field below it: the
   two sit in the same card, one above the other, and reading as one form is the point. */
.map-select {
  width: 100%;
  box-sizing: border-box;
  font-family: inherit;
  font-size: 0.95rem;
  padding: 10px 12px;
  background: var(--fh2-ui-sunken);
  border: 1px solid var(--fh2-ui-line);
  border-radius: 8px;
  color: var(--fh2-ui-text);
}

.map-select:focus {
  outline: none;
  border-color: var(--fh2-ui-gold);
  box-shadow: 0 0 0 3px rgba(217, 180, 90, 0.16);
}

/* Size, kingdoms and difficulty, in the engine's own terms. Monospaced and spaced out so it reads
   as a row of facts rather than a sentence, and cannot be mistaken for the map maker's prose below. */
.map-facts {
  margin-top: 12px;
  font-family: var(--fh2-ui-mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fh2-ui-gold);
}

/* The map maker's own description, which can run long; the engine already cuts it to 400 bytes. */
.map-description {
  margin: 8px 0 0;
  font-size: 0.87rem;
  line-height: 1.55;
  color: var(--fh2-ui-dim);
}

.listing-private {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 10px;
  font-size: 0.78rem;
  color: var(--fh2-ui-faint);
  line-height: 1.45;
  cursor: pointer;
}

/* Any author rule that sets `display` beats the browser's own [hidden] { display: none }, whatever
   the specificity, so a `display: flex` above silently makes the `hidden` attribute do nothing.
   Only one of these rows is ever toggled -- "hide the map while it is not their turn", which is
   offered for a scenario and not for a single battle -- but the row was showing in both. */
.listing-private[hidden] {
  display: none;
}

.listing-private input {
  /* Nudged down so the box lines up with the first line of text rather than its top edge. */
  margin: 1px 0 0;
  accent-color: var(--fh2-ui-gold);
  flex: 0 0 auto;
}

/* ---- the list of open games ----
 *
 * Capped in height on purpose: the code box below it has to stay reachable without scrolling on a
 * short screen, whether there is one game open or forty.
 */

/* The list and the host/join choice are two different decisions -- "is anyone here?" and "what do I
   do about it?" -- so they need to read as two blocks rather than one run-on stack. Only on the host
   page: the join page already separates them with the "or enter a code" rule, and two dividers a few
   pixels apart look like a mistake. */
#open-games.lobby-block {
  margin-bottom: 26px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--fh2-ui-line);
}

.games-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.games-head h2 {
  margin: 0;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fh2-ui-dim);
}

.games-head .linklike { font-size: 0.78rem; }

.games-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 232px;
  overflow-y: auto;
}

/* Set by mountOpenGames() only while there is more below. Fading the cut row is what turns a
   guillotined name into an obvious "keep scrolling". */
.games-list.is-scrollable {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 40px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 40px), transparent);
}

.games-list:empty { display: none; }

/* The whole row is clickable, but the Join button is the thing that says so -- "there is a game
   here" and "you may take it" are different statements and the second one needs a control. */
.game-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px 10px 14px;
  background: var(--fh2-ui-sunken);
  border: 1px solid var(--fh2-ui-line);
  border-radius: 10px;
  cursor: pointer;
}

.game-row:hover {
  border-color: var(--fh2-ui-gold);
  background: rgba(255, 252, 240, 0.6);
}

.game-who {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* min-width:0 is what actually lets the name ellipsis inside a flex row. */
  min-width: 0;
  flex: 1;
}

/* A host's own text, so it cannot be trusted to be short or to contain anything to break at. */
.game-name {
  font-size: 1rem;
  font-weight: 600;
  color: var(--fh2-ui-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The second line of a row: what kind of game it is, then how long it has been waiting. Kept on one
   line so a row stays two lines tall however long the name is. */
.game-line {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.game-wait {
  font-size: 0.76rem;
  color: var(--fh2-ui-faint);
  white-space: nowrap;
}

/* A scenario is picked out because it is the one that costs the player their evening; a battle is
   the ordinary case and is left quiet. Colour is not doing the work on its own -- the words differ
   too, which is what a player reads. */
.game-kind {
  font-size: 0.76rem;
  color: var(--fh2-ui-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Red, like the Experimental label the two pages carry: in the listing this line is the only thing that
   says which of the two modes a row is, so it should warn in the same colour rather than in the
   card's ordinary gold. */
.game-kind.scenario { color: var(--fh2-ui-red); }

/* The badge sits in a small row, so it is scaled down from the one on the cards - and leads the
   line rather than trailing it, because it is what the eye should reach first. */
.game-kind .mode-tag {
  margin: 0 7px 0 0;
  padding: 1px 6px;
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  box-shadow: none;
}

.game-kind .mode-tag[hidden] { display: none; }

/* A continued game carries two badges and how far in it is, which no longer fits on one line beside
   the waiting time - and cut short, the date is the part that goes. So that row takes two lines:
   what the game is, then how long it has been waiting. */
.game-line.continued {
  flex-wrap: wrap;
  row-gap: 2px;
}

.game-line.continued .game-kind {
  flex: 1 1 100%;
  white-space: normal;
}

.game-line.continued .game-kind::after { content: none; }

.game-kind::after {
  content: "·";
  margin-left: 8px;
  color: var(--fh2-ui-faint);
}

button.game-join {
  flex: 0 0 auto;
  min-width: 92px;
  padding: 11px 20px;
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.games-empty {
  margin: 0;
  padding: 14px 2px;
  font-size: 0.82rem;
  color: var(--fh2-ui-faint);
  line-height: 1.5;
}

/* Separates the two ways in, and says the code is the lesser one. */
.or-code {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 18px 0 10px;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fh2-ui-faint);
}

.or-code::before,
.or-code::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--fh2-ui-line);
}

/* ---- status line ---- */

.status {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 16px;
  padding: 11px 13px;
  background: var(--fh2-ui-sunken);
  border: 1px solid var(--fh2-ui-line);
  border-radius: 9px;
  font-size: 0.86rem;
  line-height: 1.45;
  color: var(--fh2-ui-dim);
}

.status[hidden] { display: none; }

.status .dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--fh2-ui-gold);
  animation: fh2-pulse 1.4s ease-in-out infinite;
}

.status.ok { color: #3c5a2a; border-color: rgba(70, 102, 47, 0.5); }
.status.ok .dot { background: var(--fh2-ui-green); animation: none; }

.status.error { color: var(--fh2-ui-red); border-color: rgba(140, 47, 34, 0.5); background: rgba(150, 60, 45, 0.1); }
.status.error .dot { background: var(--fh2-ui-red); animation: none; }

/* Background progress the player is not waiting on: visible, but never competing with the status
   line that is about what they are doing. Last, so it stays quiet even when it turns green. */
.status.quiet {
  margin-top: 10px;
  padding: 8px 13px;
  background: none;
  border-color: transparent;
  font-size: 0.8rem;
  opacity: 0.72;
}

@keyframes fh2-pulse { 0%, 100% { opacity: 0.3; } 50% { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .status .dot { animation: none; }
}

/* ---- explanatory blocks ---- */

.how {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--fh2-ui-line);
}

ol.steps {
  margin: 0;
  padding-left: 1.15rem;
  color: var(--fh2-ui-dim);
  font-size: 0.86rem;
  line-height: 1.55;
}

ol.steps li { margin-bottom: 8px; }
ol.steps li:last-child { margin-bottom: 0; }
ol.steps li::marker { color: var(--fh2-ui-gold); font-weight: 600; }
/* Colour, not weight. The card's serif stack (Iowan Old Style / Palatino / Georgia) carries no
   semibold face, so a 600 here is rounded up to the bold one by the browser - and with a lead-in on
   every step, the whole block came out bold. Ink against the dim body text separates them just as
   well and leaves bold to mean something again: the buttons, and the work-in-progress warning. */
ol.steps b { color: var(--fh2-ui-text); font-weight: 400; }

.lobby-note {
  margin-top: 16px;
  font-size: 0.8rem;
  color: var(--fh2-ui-faint);
  line-height: 1.55;
}

.lobby-note code {
  background: rgba(255, 252, 240, 0.7);
  padding: 1px 5px;
  border-radius: 3px;
  font-family: var(--fh2-ui-mono);
  font-size: 0.92em;
}

/* Marks the one mode that is genuinely new. The battles have been played for weeks; whole
   scenarios are days old, so they carry this wherever somebody chooses between the two - the mode
   picker, the map step, the lobby listing - and the battles carry nothing.
   Named for what it is rather than for the word it currently holds: "experimental" was "beta" and
   may be something else again. */
.mode-tag {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 9px;
  border: 1px solid #6b2318;
  border-radius: 4px;
  /* Filled red rather than a tinted outline: this is the one thing on the card that has to be seen
     before the choice is made, and an outline in the card's own gold read as decoration. */
  background: var(--fh2-ui-red);
  color: #f7ece0;
  font-family: var(--fh2-ui-mono);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  vertical-align: middle;
  box-shadow: 0 1px 2px rgba(74, 52, 25, 0.3);
}

/* A listed scenario that is a saved game being carried on rather than a fresh start. It changes what
   joining means - straight into a game already under way - so it is a badge like the one above, but
   green: it is news, not a warning. */
.mode-tag.continued {
  border-color: #2f4520;
  background: var(--fh2-ui-green);
}

/* The saved games on the map step, above the new-game picker. Ruled off like the open-games block on
   the front page, because continuing and starting afresh are two different decisions. */
.save-block {
  margin: 18px 0 22px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--fh2-ui-line);
}

.save-block[hidden],
#new-game-heading[hidden] { display: none; }

.save-block .name-status { margin-top: 10px; }

/* Unfinished-feature notice. Deliberately hard to miss: someone hitting a failed connection
   should already know it is expected rather than assume they did something wrong. */
.lobby-note.wip {
  padding: 10px 12px;
  border-left: 3px solid #b3711f;
  background: rgba(179, 113, 31, 0.13);
  border-radius: 6px;
  color: var(--fh2-ui-text);
}

.footer-link {
  margin: 20px 0 0;
  font-size: 0.83rem;
  color: var(--fh2-ui-faint);
  text-align: center;
}

.footer-link a { color: var(--fh2-ui-dim); }
.footer-link a:hover { color: var(--fh2-ui-text); }

/* ---- one-time game data setup ---- */

/* This step is a heading and one button, with no subtitle between them to open up the gap every
   other step gets for free. */
#step-assets .lobby-actions { margin-top: 18px; }

#load-progress {
  width: 100%;
  margin-top: 6px;
  height: 8px;
}

#load-progress[hidden] { display: none; }

/* ---- small screens ---- */

@media (max-width: 600px) {
  #lobby { padding: 14px; }
  .lobby-card { padding: 22px 18px; border-radius: 12px; }
  .lobby-card h1 { font-size: 1.35rem; }
  .room-code { font-size: 1.6rem; }
  .code-input { font-size: 1.5rem; }
  .lobby-actions { flex-direction: column; }
  .code-actions { flex-direction: column; }
}

/* ---------------------------------------------------------------------------------------------
   In-game furniture. Everything below is shown once the lobby is gone.
   --------------------------------------------------------------------------------------------- */

#turn-banner {
  position: fixed;
  top: 8px;
  /* Centred on the GAME, not the window. The message panel takes its width off the right-hand
     side, so centring on the viewport pushes this visibly to the right of the battlefield. */
  left: calc((100vw - var(--fh2-chat-width, 0px)) / 2);
  transform: translateX(-50%);
  z-index: 50;
  padding: 6px 14px;
  background: rgba(0, 0, 0, 0.75);
  color: #fff;
  font-family: var(--fh2-ui-font);
  font-size: 0.85rem;
  border-radius: 4px;
  pointer-events: none;
}

#turn-banner[hidden] { display: none; }

/* Shown while the host has the engine's scenario list to themselves, before the game is opened for
   joining. Same shape as the turn banner, in the gold the lobby uses for what the player is being
   asked to do, so it does not read as a turn announcement. */
#setup-banner {
  position: fixed;
  top: 8px;
  left: calc((100vw - var(--fh2-chat-width, 0px)) / 2);
  transform: translateX(-50%);
  z-index: 50;
  padding: 6px 14px;
  background: rgba(0, 0, 0, 0.8);
  color: var(--fh2-ui-gold);
  font-family: var(--fh2-ui-font);
  font-size: 0.85rem;
  border-radius: 4px;
  pointer-events: none;
  text-align: center;
}

#setup-banner[hidden] { display: none; }

/* The host's own view, covered while the other player takes their turn in "hidden turns" mode.
   Opaque rather than dimmed: a dimmed map is still a readable map, and the point is that neither
   player watches the other's turn.

   z-index sits above #canvas (10) and below the chat panel and control bar, so the host can still
   talk and still take control back. pointer-events: none because the input gate already refuses
   the host's clicks while the guest holds control -- swallowing them here as well would only make
   the page feel dead. */
#host-blackout {
  position: fixed;
  inset: 0;
  z-index: 20;
  background: #0d0b09;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

#host-blackout[hidden] { display: none; }

/* ---- the waiting panel ----
 *
 * Half of a scenario is spent watching somebody else play, so this is on screen as long as anything
 * in the game. It is dressed like the rest of the furniture - the chat's planks and parchment, the
 * game's own kingdom colours, a serif face - because a plain dark box in system type next to all
 * that reads as a debugging overlay somebody forgot to remove.
 *
 * z-index 30 puts it above the game surface (10) and above #host-blackout (20), so in hidden-turns
 * mode it fills the cover that used to carry one line of text - and below #turn-frame (40),
 * #turn-banner (50) and #fh2-net-ui (60), because "take control back" must never end up underneath
 * something decorative. The chat (70/71) stays on top of everything: talking wins.
 *
 * pointer-events: none on the whole panel. Nothing in it is interactive, and the input gate is
 * spared having to know it exists.
 */
#fh2-meanwhile {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  /* The right edge stops at the chat, so it centres on the game rather than on the window - the same
     reasoning the turn banner and the ownership ring already follow. */
  right: var(--fh2-chat-width, 0px);
  z-index: 30;
  pointer-events: none;

  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;

  font-family: Georgia, "Times New Roman", serif;
  font-size: 0.9rem;
  color: var(--fh2-ink);

  background:
    linear-gradient(rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.5)),
    repeating-linear-gradient(90deg, var(--fh2-wood) 0 7px, #3d2a17 7px 9px, var(--fh2-wood) 9px 16px);
}

/* One page rather than a background per block: painting them separately left visible seams where
 * the gradients met, which is not how a sheet of parchment looks. */

#fh2-meanwhile .mw-sheet {
  width: 100%;
  max-width: 470px;
  padding: 22px 26px 20px;

  background:
    linear-gradient(rgba(255, 255, 255, 0.10), rgba(0, 0, 0, 0.06)),
    linear-gradient(var(--fh2-parchment), var(--fh2-parchment-dim));
  border: 2px solid var(--fh2-wood-dark);
  border-radius: 3px;
  box-shadow:
    inset 0 0 0 1px rgba(217, 180, 90, 0.5),
    0 6px 22px rgba(0, 0, 0, 0.6);
}

#fh2-meanwhile .mw-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: #2a1c0a;
}




/* The acting kingdom's colour, drawn as the game draws a shield: a disc with a dark rim. */
#fh2-meanwhile .mw-swatch {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  flex: none;
  box-shadow: 0 0 0 1.5px var(--fh2-ink), inset 0 1px 1px rgba(255, 255, 255, 0.4);
}

#fh2-meanwhile .mw-swatch[hidden] { display: none; }

#fh2-meanwhile .mw-chip {
  font-family: system-ui, sans-serif;
  font-size: 0.6rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 1px 6px 2px;
  border-radius: 2px;
  background: rgba(58, 42, 20, 0.16);
  box-shadow: inset 0 0 0 1px rgba(58, 42, 20, 0.28);
  color: #4a3517;
}

#fh2-meanwhile .mw-chip[hidden] { display: none; }

#fh2-meanwhile .mw-clock-row {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 10px;
  padding-top: 2px;
}


#mw-clock {
  font-variant-numeric: tabular-nums;
  font-size: 1.1rem;
  color: #2a1c0a;
}



#mw-clock-compare,
#mw-map,
#mw-net,
#mw-footer {
  color: #6b563a;
  font-size: 0.74rem;
  font-style: italic;
}

#mw-date {
  color: #4a3517;
  text-align: center;
  padding-bottom: 6px;
}


/* A ruled line rather than a border: the sheet should read as one page with entries on it. */
#mw-self,
#mw-rivals {
  padding-top: 8px;
  margin-top: 2px;
  border-top: 1px solid rgba(58, 42, 20, 0.22);
}

#mw-self[hidden],
#mw-rivals[hidden],
#mw-date[hidden],
#mw-map[hidden],
#mw-net[hidden],
#mw-footer[hidden] { display: none; }

#fh2-meanwhile .mw-self-title,
#fh2-meanwhile .mw-rivals-title {
  font-family: system-ui, sans-serif;
  color: #6b563a;
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: 2px;
}

#fh2-meanwhile .mw-gold {
  color: #2a1c0a;
  font-size: 1.02em;
}

#fh2-meanwhile .mw-income { color: #6b563a; font-size: 0.86em; }
#fh2-meanwhile .mw-counts,
#fh2-meanwhile .mw-hero,
#fh2-meanwhile .mw-strength { color: #4a3517; }

#mw-self.fallen .mw-self-title { color: #8c2f22; }

#fh2-meanwhile .mw-res {
  display: flex;
  flex-wrap: wrap;
  gap: 3px 6px;
  margin: 3px 0 4px;
}

#fh2-meanwhile .mw-res-chip {
  font-family: system-ui, sans-serif;
  font-size: 0.64rem;
  color: #5c4526;
  padding: 0 4px 1px;
  border-radius: 2px;
  background: rgba(58, 42, 20, 0.09);
}

#fh2-meanwhile .mw-rival {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 0;
}

#fh2-meanwhile .mw-rival + .mw-rival { border-top: 1px dotted rgba(58, 42, 20, 0.18); }
#fh2-meanwhile .mw-rival.lost { opacity: 0.55; }
#fh2-meanwhile .mw-rival.lost .mw-rival-name { text-decoration: line-through; }

#fh2-meanwhile .mw-rival-swatch {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
  box-shadow: 0 0 0 1.5px var(--fh2-ink);
}

#fh2-meanwhile .mw-rival-name { color: #2a1c0a; font-weight: 700; }
#fh2-meanwhile .mw-rival-facts { color: #6b563a; font-size: 0.72rem; margin-left: auto; }

#mw-map { padding-top: 8px; text-align: center; }

#mw-net.good { color: #46662f; }
#mw-net.fair { color: #6b563a; }
#mw-net.poor { color: #8c2f22; }

#mw-footer { text-align: center; padding-top: 4px; }

/* Last, and deliberately so: .full sets display:flex and has the same specificity as this rule, so
 * source order is the only thing that decides which wins. With this written first, a panel that had
 * been switched off went on being displayed - empty, because the render had already returned. */
#fh2-meanwhile[hidden] { display: none; }

/* On a narrow window the corner card would sit on top of the game rather than beside it, so it
 * spans the top instead - the same width the chat gives up at that size. */

/* ---- which of the two games to play ----
 *
 * Radios rather than two more big buttons: hosting is already the button below, and turning it into
 * four would make the front page a wall of near-identical choices. This is a property of the game
 * about to be hosted, so it reads as a setting.
 */

.mode-pick { margin-bottom: 18px; }

.mode-option {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 10px 12px;
  border: 1px solid var(--fh2-ui-line);
  border-radius: 9px;
  cursor: pointer;
  margin-bottom: 8px;
  background: var(--fh2-ui-sunken);
}

.mode-option:hover { border-color: var(--fh2-wood, #4a3419); }
.mode-option:has(input:checked) { border-color: var(--fh2-ui-gold); }
.mode-option input { margin-top: 3px; flex: 0 0 auto; }
.mode-option b { display: block; font-size: 0.92rem; font-weight: 600; }

.mode-option small {
  display: block;
  margin-top: 3px;
  font-size: 0.76rem;
  line-height: 1.45;
  color: var(--fh2-ui-dim);
}

#host-blackout-text {
  color: #c8b998;
  font-size: 1.05rem;
  letter-spacing: 0.02em;
}

/* The kingdom colours, taken from the game's own palette rather than guessed: these are the KB.PAL
   indices the engine itself uses for players (see the COLOR_* enum in interface_radar.cpp), which is
   what it paints a unit's flag, its entry in the turn order, the radar, and - during an online game -
   the contour around whichever unit is acting. A near-enough CSS blue would not read as the same side.

   A battle only ever uses blue and red; a scenario can use all six. */
:root {
  --fh2-side-blue: rgb(64, 76, 180);    /* 0x47 */
  --fh2-side-green: rgb(72, 144, 60);   /* 0x5D */
  --fh2-side-red: rgb(168, 32, 32);     /* 0xBD */
  --fh2-side-yellow: rgb(236, 212, 80); /* 0x70 */
  --fh2-side-orange: rgb(236, 184, 96); /* 0xCA */
  --fh2-side-purple: rgb(180, 140, 208);/* 0x87 */
}

/* Whose turn it is, said around the edge of the picture rather than in a label at the top. The banner
   is easy to tune out while the eye is on the middle of the battlefield; a ring the width of the
   screen is not. Its colour matches the contour the engine draws around the acting unit, so the two
   cues agree.

   A separate element rather than a border on the canvas or the video: an inset box-shadow on a
   replaced element paints underneath its content and would be invisible, and a real border would
   change the layout the guest's pointer coordinates are normalised against. */
#turn-frame {
  position: fixed;
  top: 0;
  left: 0;
  /* Yields the message panel's width, exactly as #guest-video does, so the ring frames the game and
     not the chat. */
  width: calc(100vw - var(--fh2-chat-width, 0px));
  height: 100vh;
  z-index: 40;
  /* Must never swallow a click: the host plays on the canvas underneath this. */
  pointer-events: none;
  box-shadow: inset 0 0 0 5px var(--fh2-turn-frame-color, transparent);
  transition: box-shadow 120ms ease-out;
}

#turn-frame[hidden] { display: none; }

/* Waiting: a dark, desaturated ring. Deliberately not the opponent's own colour - the point of the
   frame is "yours / not yours", and painting the screen in their colour invites reading it as theirs
   at a glance. */
#turn-frame.waiting {
  --fh2-turn-frame-color: rgba(90, 78, 70, 0.85);
}

#guest-video {
  position: fixed;
  top: 0;
  left: 0;
  /* Yields the panel's width rather than sitting under it. Stated as an explicit width rather than
     by pinning left and right: a video is a replaced element, so `width: auto` would fall back to
     the stream's own 640x400 and sit unscaled in the corner. object-fit keeps the picture's shape
     inside whatever is left, and pictureRect() in multiplayer.js measures the element every time,
     so the pointer keeps landing on the cell it is over. */
  width: calc(100vw - var(--fh2-chat-width, 0px));
  height: 100vh;
  object-fit: contain;
  background: #000;
  z-index: 10;
}

/* Waiting state for the turn banner: shown to whichever side may not act right now. */
#turn-banner.waiting {
  background: rgba(120, 60, 20, 0.85);
}

/* Shown to whichever side may not act right now, on the surface they would otherwise play on: the
   host's canvas and the guest's video. A greyed-out "no entry" reads as "not yours to touch"
   immediately, where a normal arrow invites a click that is then silently swallowed by the gate.
   Drawn inline rather than taken from the game's own cursor art: the guest never downloads any
   game files, so nothing from the AGG can be used on that side.

   Dark halo first, grey glyph over it, so it stays legible on both the bright battlefield and the
   dark interface panels. The two numbers after the url() put the hotspot in the middle of the
   circle instead of the default top-left. */
:root {
  --fh2-blocked-cursor:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26'%3E%3Cg fill='none' stroke='%23000' stroke-opacity='.55' stroke-width='5.5' stroke-linecap='round'%3E%3Ccircle cx='13' cy='13' r='8.5'/%3E%3Cline x1='7' y1='7' x2='19' y2='19'/%3E%3C/g%3E%3Cg fill='none' stroke='%23b4bac1' stroke-width='2.6' stroke-linecap='round'%3E%3Ccircle cx='13' cy='13' r='8.5'/%3E%3Cline x1='7' y1='7' x2='19' y2='19'/%3E%3C/g%3E%3C/svg%3E") 13 13,
    not-allowed;
}

/* !important because SDL sets an inline `cursor: none` on the canvas while the engine draws its
   own cursor into the frame buffer, and an inline style would otherwise win. Without this the
   host has no pointer at all on their own screen during the opponent's turn. */
#canvas.fh2-no-control,
#guest-video.fh2-no-control {
  cursor: var(--fh2-blocked-cursor) !important;
}

/* Two pointers on purpose, doing two different jobs.

   The engine draws the real game cursor into the video -- the contextual battle one that says move
   / attack from this side / out of reach -- but it can only arrive a round trip late, so on its own
   it feels like the mouse is dragging something heavy. The dot below is drawn by the guest's own
   browser at the true pointer position, so it is exact and instant, and the eye tracks it while the
   drawn cursor a little behind supplies the meaning.

   Hiding this and leaving only the drawn cursor was tried and felt markedly laggier. A full arrow
   was tried too and competed with the game cursor for attention; a small ring reads as "you are
   here" without pretending to be the pointer that matters. */
#guest-video.fh2-own-control {
  cursor:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15'%3E%3Ccircle cx='7.5' cy='7.5' r='5' fill='none' stroke='%23000' stroke-opacity='.6' stroke-width='3.4'/%3E%3Ccircle cx='7.5' cy='7.5' r='5' fill='none' stroke='%23fff' stroke-width='1.6'/%3E%3Ccircle cx='7.5' cy='7.5' r='1' fill='%23fff'/%3E%3C/svg%3E") 7 7,
    crosshair;
}

/* Host-side control bar. Deliberately outside the engine canvas so the input gate never intercepts
   it -- "Take control back" has to work while the guest holds control.

   Top right, not bottom centre: the engine puts its own controls along the bottom edge -- Battle
   Only's START/EXIT row and, in a fight, the status bar and turn order -- and a bar centred there
   covers them, so the host cannot click START at all at common window sizes. */
#fh2-net-ui {
  position: fixed;
  top: 10px;
  right: calc(var(--fh2-chat-width, 0px) + 54px);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 12px;
  background:
    linear-gradient(rgba(255, 255, 255, 0.10), rgba(0, 0, 0, 0.06)),
    linear-gradient(var(--fh2-parchment), var(--fh2-parchment-dim));
  border: 1px solid var(--fh2-wood-dark);
  border-radius: 3px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  font-family: var(--fh2-ui-font);
  font-size: 0.8rem;
  color: var(--fh2-ink);
}

#fh2-net-ui[hidden] { display: none; }

#fh2-net-pill {
  padding: 3px 9px;
  border-radius: 2px;
  background: #3c5a2a;
  color: #f0e2bd;
  white-space: nowrap;
}

#fh2-net-pill.inactive { background: #7a3d12; }

#fh2-net-ui button {
  padding: 5px 10px;
  font-size: 0.8rem;
  font-family: inherit;
  color: var(--fh2-ink);
  background: rgba(255, 252, 240, 0.8);
  border: 1px solid var(--fh2-ui-line);
  border-radius: 5px;
  cursor: pointer;
}

#fh2-net-ui button:hover { background: #fffdf4; }
#fh2-net-ui button[hidden] { display: none; }
#btn-sound {
  position: fixed;
  top: 8px;
  right: calc(var(--fh2-chat-width, 0px) + 54px);
  z-index: 60;
  padding: 7px 13px;
  font-family: var(--fh2-ui-font);
  font-size: 0.85rem;
  color: var(--fh2-ink);
  background:
    linear-gradient(rgba(255, 255, 255, 0.10), rgba(0, 0, 0, 0.06)),
    linear-gradient(var(--fh2-parchment), var(--fh2-parchment-dim));
  border: 1px solid var(--fh2-wood-dark);
  border-radius: 3px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  cursor: pointer;
}

#btn-sound[hidden] { display: none; }

/* ---------------------------------------------------------------------------------------------
   Message panel beside the game.

   Styled to sit next to the engine's own artwork rather than compete with it: aged parchment for
   the reading surface, dark tooled wood for the frame, and the gold the game uses for its own
   headings. All of it is CSS -- no image files -- so the guest still needs no downloads and the
   published build still carries none of the original game's assets.

   The width is published as a variable so both pages can subtract it from the game surface. It is
   zero unless the panel is actually open, which keeps the game full-bleed until someone talks.
   --------------------------------------------------------------------------------------------- */
:root {
  --fh2-chat-width: 0px;
  --fh2-parchment: #e4d3a8;
  --fh2-parchment-dim: #cbb787;
  --fh2-ink: #3a2a14;
  --fh2-wood: #45301a;
  --fh2-wood-dark: #2b1d0f;
  --fh2-gold: #d9b45a;
}

body.fh2-chat-open {
  --fh2-chat-width: 310px;
}

/* Below this the game would be squeezed harder than the conversation is worth. */
@media (max-width: 900px) {
  body.fh2-chat-open { --fh2-chat-width: 0px; }
  #fh2-chat { display: none; }
}

#fh2-chat {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--fh2-chat-width);
  z-index: 70;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  padding: 10px;
  gap: 8px;

  background:
    linear-gradient(rgba(0, 0, 0, 0.18), rgba(0, 0, 0, 0.34)),
    repeating-linear-gradient(90deg, var(--fh2-wood) 0 7px, #3d2a17 7px 9px, var(--fh2-wood) 9px 16px);
  border-left: 3px solid var(--fh2-wood-dark);
  box-shadow: inset 3px 0 0 rgba(217, 180, 90, 0.28), -6px 0 14px rgba(0, 0, 0, 0.55);
  font-family: Georgia, "Times New Roman", serif;
}

#fh2-chat[hidden] { display: none; }

#fh2-chat-title {
  flex: none;
  text-align: center;
  padding-bottom: 6px;
  color: var(--fh2-gold);
  font-size: 1.05rem;
  font-variant: small-caps;
  letter-spacing: 0.14em;
  text-shadow: 0 1px 0 #000;
  border-bottom: 1px solid rgba(217, 180, 90, 0.4);
}

#fh2-chat-log {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 9px 10px;
  box-sizing: border-box;

  /* Parchment: a warm base, a slight vertical ageing, and a mottling of soft blotches. */
  background-color: var(--fh2-parchment);
  background-image:
    radial-gradient(ellipse at 22% 18%, rgba(150, 116, 62, 0.18), transparent 62%),
    radial-gradient(ellipse at 78% 68%, rgba(150, 116, 62, 0.15), transparent 58%),
    linear-gradient(var(--fh2-parchment), var(--fh2-parchment-dim));
  border: 1px solid #6b4d28;
  border-radius: 2px;
  box-shadow: inset 0 0 22px rgba(120, 88, 42, 0.5);

  color: var(--fh2-ink);
  font-size: 0.86rem;
  line-height: 1.42;
  word-break: break-word;
}

.fh2-chat-line { margin-bottom: 5px; }

.fh2-chat-who {
  font-variant: small-caps;
  font-weight: 700;
  letter-spacing: 0.04em;
  margin-right: 5px;
}

.fh2-chat-own .fh2-chat-who { color: #1f4a70; }
.fh2-chat-peer .fh2-chat-who { color: #7c2418; }

.fh2-chat-notice {
  font-style: italic;
  color: #6a5433;
  text-align: center;
  margin: 8px 0;
}

#fh2-chat-form {
  flex: none;
  display: flex;
  gap: 6px;
}

#fh2-chat-input {
  flex: 1;
  min-width: 0;
  box-sizing: border-box;
  padding: 6px 8px;
  background: #f0e2bd;
  border: 1px solid #6b4d28;
  border-radius: 2px;
  color: var(--fh2-ink);
  font-family: inherit;
  font-size: 0.85rem;
}

#fh2-chat-input:focus {
  outline: none;
  border-color: var(--fh2-gold);
  box-shadow: 0 0 0 1px rgba(217, 180, 90, 0.6);
}

#fh2-chat-send {
  flex: none;
  padding: 6px 12px;
  background: linear-gradient(#6a4a26, #4a3218);
  border: 1px solid var(--fh2-wood-dark);
  border-radius: 2px;
  color: var(--fh2-parchment);
  font-family: inherit;
  font-variant: small-caps;
  letter-spacing: 0.06em;
  cursor: pointer;
}

#fh2-chat-send:hover { background: linear-gradient(#7d5930, #583c1d); }
#fh2-chat-send:active { background: linear-gradient(#4a3218, #6a4a26); }

/* Sits clear of the panel when it is open and against the edge when it is not. */
#fh2-chat-toggle {
  position: fixed;
  top: 10px;
  right: calc(var(--fh2-chat-width) + 10px);
  z-index: 71;
  width: 34px;
  height: 34px;
  padding: 0;
  background: linear-gradient(#6a4a26, #4a3218);
  border: 1px solid var(--fh2-wood-dark);
  border-radius: 3px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
  color: var(--fh2-gold);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

#fh2-chat-toggle[hidden] { display: none; }

#fh2-chat-unread {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  box-sizing: border-box;
  background: #8d2b1c;
  border-radius: 999px;
  color: #fff;
  font-family: var(--fh2-ui-font);
  font-size: 0.6rem;
  line-height: 15px;
  text-align: center;
}

#fh2-chat-unread[hidden] { display: none; }

/* A quiet, secondary way out of the front page: replacing the game files is rare, and should not
   compete with the two things nearly everyone came here to do. */
.replace-files {
  margin-top: 18px;
  font-size: 0.82rem;
}

.linklike,
button.linklike {
  padding: 0;
  background: none;
  border: 0;
  color: var(--fh2-ui-gold);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

.linklike:hover,
button.linklike:hover { color: var(--fh2-ui-text); }

/* ---- back to the site ----
 *
 * Sits in the card rather than over the canvas, and therefore disappears with the card the moment
 * the game starts drawing. A link floating above a battle is one misclick away from ending it, and
 * the browser's own Back button already covers anyone who wants out mid-game.
 *
 * Outside the .lobby-step elements on purpose, so it survives every step change: whichever screen
 * a player gets stuck on -- loading, the folder picker, waiting for an opponent -- there is a way
 * out that is not the address bar. */
.lobby-back {
  display: inline-block;
  margin: 0 0 18px;
  color: var(--fh2-ui-faint);
  font-size: 0.86rem;
  text-decoration: none;
}

.lobby-back:hover { color: var(--fh2-ui-gold); }

.lobby-back b { color: var(--fh2-ui-dim); font-weight: 600; }
.lobby-back:hover b { color: var(--fh2-ui-gold); }

/* ---------------------------------------------------------------------------------------------
   Battle tournaments (tournament.js): the bracket panel both pages draw, and its trophy button.
   The panel sits over the game between battles; the button keeps it a click away during them.
   --------------------------------------------------------------------------------------------- */

.ghost-link {
  align-self: center;
  padding: 12px 16px;
  color: var(--fh2-ui-dim);
  font-size: 0.95rem;
  text-decoration: none;
}
.ghost-link:hover { color: var(--fh2-ui-text); }

.tn-toggle {
  position: fixed;
  top: 10px;
  left: 10px;
  z-index: 71;
  padding: 6px 10px;
  background: linear-gradient(#6a4a26, #4a3218);
  border: 1px solid var(--fh2-wood-dark, #2e1f0e);
  border-radius: 3px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
  color: var(--fh2-gold, #e8c66a);
  font-family: var(--fh2-ui-font);
  font-size: 0.85rem;
  cursor: pointer;
}
.tn-toggle[hidden] { display: none; }

.tn-panel {
  position: fixed;
  top: 0;
  left: 0;
  /* Covers the game only, never the message panel, so people can keep talking over the bracket. */
  width: calc(100vw - var(--fh2-chat-width, 0px));
  height: 100vh;
  z-index: 70;
  background: rgba(13, 11, 9, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  box-sizing: border-box;
  overflow-y: auto;
}
.tn-panel[hidden] { display: none; }

.tn-card {
  margin: auto;
  width: 100%;
  max-width: 640px;
  box-sizing: border-box;
  background: linear-gradient(180deg, #fbf3de, var(--fh2-ui-card));
  border: 1px solid var(--fh2-wood, #4a3419);
  border-radius: 5px;
  padding: 18px 22px 20px;
  color: var(--fh2-ui-text);
  font-family: var(--fh2-ui-font);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.45);
}

.tn-head { display: flex; align-items: flex-start; gap: 12px; }
.tn-title { flex: 1; margin: 0; font-size: 1.3rem; line-height: 1.2; }

.tn-card button {
  font-family: inherit;
  color: var(--fh2-ui-text);
  background: rgba(255, 252, 240, 0.75);
  border: 1px solid var(--fh2-ui-line);
  border-radius: 4px;
  cursor: pointer;
}
.tn-card button:hover { background: #fffdf4; border-color: var(--fh2-wood, #4a3419); }
.tn-card button:disabled { opacity: 0.45; cursor: not-allowed; }
.tn-card button.primary {
  background: linear-gradient(180deg, #4f7238, #3c5a2a);
  border-color: #2f4a20;
  color: #f2e8cd;
}

.tn-close { font-size: 1.3rem; line-height: 1; padding: 2px 9px; }

.tn-phase { margin: 4px 0 12px; color: var(--fh2-ui-dim); font-size: 0.9rem; }
.tn-phase.champion { color: var(--fh2-ui-gold); font-size: 1.05rem; font-weight: 700; }

.tn-next {
  border: 1px solid var(--fh2-ui-gold);
  border-radius: 4px;
  background: var(--fh2-ui-sunken);
  padding: 10px 12px;
  margin-bottom: 14px;
}
.tn-next[hidden] { display: none; }
.tn-next-label {
  font-size: 0.72rem;
  color: var(--fh2-ui-gold);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 600;
}
.tn-next-pair { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 6px; font-size: 1.05rem; font-weight: 600; }
.tn-vs { color: var(--fh2-ui-faint); font-weight: 400; font-style: italic; }
.tn-fighter { display: inline-flex; align-items: center; gap: 6px; }
.tn-side { width: 11px; height: 11px; border-radius: 2px; flex: 0 0 auto; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35); }
.tn-next-note { margin: 6px 0 0; font-size: 0.82rem; color: var(--fh2-ui-dim); line-height: 1.45; }
.tn-small { margin-top: 8px; padding: 6px 12px; font-size: 0.85rem; }

.tn-name-row { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; }
.tn-name-row[hidden] { display: none; }
.tn-name-label { font-size: 0.8rem; color: var(--fh2-ui-dim); }
.tn-name-input {
  flex: 1;
  min-width: 120px;
  font-family: inherit;
  font-size: 0.95rem;
  padding: 6px 8px;
  border: 1px solid var(--fh2-ui-line);
  border-radius: 4px;
  background: #fffdf4;
  color: var(--fh2-ui-text);
}
.tn-name-save { padding: 6px 12px; font-size: 0.85rem; }

/* Rounds side by side, each column spreading its matches over the height of the first round, which
   is what makes it read as a bracket. Scrolls sideways inside itself on a narrow screen rather than
   pushing the page wider. */
.tn-bracket {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  padding-bottom: 4px;
  margin-bottom: 14px;
}
.tn-bracket[hidden] { display: none; }
.tn-round { flex: 1 0 140px; display: flex; flex-direction: column; }
.tn-round-name {
  font-size: 0.7rem;
  color: var(--fh2-ui-gold);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 600;
  margin-bottom: 6px;
}
.tn-matches { flex: 1; display: flex; flex-direction: column; justify-content: space-around; gap: 8px; }
.tn-match {
  border: 1px solid var(--fh2-ui-line);
  border-radius: 4px;
  background: rgba(255, 252, 240, 0.7);
  font-size: 0.85rem;
  overflow: hidden;
}
.tn-match.current { border-color: var(--fh2-ui-gold); box-shadow: 0 0 0 2px rgba(138, 100, 32, 0.25); }
.tn-match.fighting { border-color: var(--fh2-ui-red); box-shadow: 0 0 0 2px rgba(140, 47, 34, 0.25); }
.tn-match.pickable { cursor: pointer; }
.tn-match.pickable:hover { border-color: var(--fh2-wood, #4a3419); background: #fffdf4; }
.tn-slot { padding: 4px 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tn-slot + .tn-slot { border-top: 1px solid var(--fh2-ui-line); }
.tn-slot.empty { color: var(--fh2-ui-faint); font-style: italic; }
.tn-slot.won { font-weight: 700; }
.tn-slot.won::after { content: " ✓"; color: var(--fh2-ui-green); }
.tn-slot.lost { color: var(--fh2-ui-faint); text-decoration: line-through; }
.tn-slot.me { background: rgba(138, 100, 32, 0.12); }

.tn-sub {
  margin: 0 0 6px;
  font-size: 0.72rem;
  color: var(--fh2-ui-gold);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 600;
}

.tn-players { list-style: none; margin: 0 0 10px; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 4px 12px; }
.tn-players.signup { grid-template-columns: 1fr; margin-bottom: 16px; }
.tn-player { display: flex; align-items: center; gap: 7px; font-size: 0.9rem; min-width: 0; }
.tn-player.open { color: var(--fh2-ui-faint); font-style: italic; padding-left: 16px; }
.tn-player.away { color: var(--fh2-ui-dim); }
.tn-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--fh2-ui-green); flex: 0 0 auto; }
.tn-player.away .tn-dot { background: var(--fh2-ui-red); }
.tn-away { font-size: 0.78rem; color: var(--fh2-ui-faint); }
.lobby-card .tn-remove { margin-left: auto; padding: 3px 9px; font-size: 0.78rem; }

.tn-notice { margin: 6px 0 0; font-size: 0.88rem; color: var(--fh2-ui-text); font-style: italic; }
.tn-notice[hidden] { display: none; }
.tn-actions { display: flex; gap: 8px; flex-wrap: wrap; }

@media (max-width: 560px) {
  .tn-card { padding: 14px 14px 16px; }
  .tn-round { flex-basis: 120px; }
}

/* The tournament setup card's text fields stand alone rather than in a .name-row beside a button. */
#step-setup .name-input { width: 100%; box-sizing: border-box; }

/* The host's controls for the match on screen: swap, take over a side, award it. */
.tn-host-controls { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.tn-host-controls > .tn-small { align-self: flex-start; }
.tn-fighter-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.tn-fighter-controls .tn-fighter { min-width: 8em; font-weight: 600; }
.tn-fighter-controls .tn-small { margin-top: 0; }
.tn-card button.tn-armed { background: var(--fh2-ui-red); border-color: #5e1f16; color: #f2e8cd; }
.tn-strong { color: var(--fh2-ui-text); font-weight: 600; }

/* "How this tournament works" in the bracket panel. */
.tn-rules {
  margin: 0 0 12px;
  border: 1px solid var(--fh2-ui-line);
  border-radius: 4px;
  background: rgba(255, 252, 240, 0.55);
  font-size: 0.86rem;
  line-height: 1.5;
}
.tn-rules summary { cursor: pointer; padding: 7px 10px; color: var(--fh2-ui-gold); font-weight: 600; }
.tn-rules ul { margin: 0; padding: 0 14px 10px 30px; color: var(--fh2-ui-dim); }
.tn-rules li + li { margin-top: 4px; }
