/* How pages are put together.
   .gate                   login and registration: one .card in the middle
   .home                   the front page, below
   .rail                   the site's menu: a column on the left, a bar on a narrow screen
   .page                   one column of panels (the profile), as wide as the admin panel
   .layout, .sidebar       a menu on the left and .content (the admin panel)
   .menu-button            on a phone the menu hides behind it, in the corner
   .chat-page, .chat       the chat: the screen full, only the messages scroll
   Columns are minmax(0, 1fr), not plain 1fr or auto: those never shrink below
   the widest unbreakable thing inside, a long address or a path in <code>,
   and push past the edge of a phone.                                        */

.gate {
  min-height: 100dvh;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--space-5);
  padding: var(--space-8) var(--gutter);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0 0 var(--space-6);
  color: var(--color-accent);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: 0.32em;
  text-decoration: none;
  text-transform: uppercase;
}

.brand:hover {
  color: var(--color-accent);
}

/* The site's menu (the owner, 03.10.2026, over a picture of the bar that stood on top,
   an arrow from it to the left edge: «перенеси потом меню сюда и адаптируй всё
   нормально»). On a wide screen a column down the left edge that stays while the page
   scrolls: the brand on top, the parts of the site under it, the account at its foot.
   On a narrower one a bar on top with the brand and a button, and the same menu opens
   under the bar over the whole screen. The pages are not told: on a wide screen the
   body keeps the column's width free on its left. 960 px is also in js/rail.js, which
   shuts the menu when the screen grows past it: change both. */
.rail .brand {
  margin: 0;
  padding: var(--space-2) var(--space-3);
}

.rail-nav {
  display: grid;
  gap: 2px;
}

.rail-nav a,
.sidebar a {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  font-weight: var(--weight-medium);
  text-decoration: none;
}

.rail-nav a:hover,
.sidebar a:hover {
  color: var(--color-text);
  background: var(--color-hover);
}

.rail-nav a[aria-current="page"],
.sidebar a[aria-current="page"] {
  color: var(--color-text);
  background: var(--color-accent-soft);
}

/* The count of what is unread stands at the end of «Чат». */
.rail-nav a {
  display: flex;
  align-items: center;
}

.rail-nav .count {
  margin-left: auto;
}

/* The parts of the front page, under «Главная» on it alone. */
.rail-sub {
  display: grid;
  gap: 2px;
  margin: 0 0 var(--space-1) var(--space-4);
  padding-left: var(--space-2);
  border-left: 1px solid var(--color-line);
}

.rail-sub a {
  font-size: var(--text-md);
}

/* Who is signed in and the way out, or the way in for a guest, at the menu's foot. */
.rail-account {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-line);
}

.rail-account > .btn:only-child {
  flex: 1;
}

/* The nickname is a way into the profile, as its button is (the owner, 28.09.2026:
   «сделай что бы имя профиля переходило в профиль как по кнопке»): it lights up under
   the pointer as the menu's links do. A long one ends in «…» before the way out. */
.who {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition:
    background-color var(--transition),
    color var(--transition);
}

.who:hover {
  color: var(--color-text);
  background: var(--color-hover);
}

.rail-toggle {
  display: none;
  place-items: center;
  width: var(--control-height);
  height: var(--control-height);
  padding: 0;
  border: 1px solid var(--color-line-strong);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text);
  cursor: pointer;
  transition: background-color var(--transition);
}

.rail-toggle:hover {
  background: var(--color-hover);
}

@media (min-width: 961px) {
  body:has(> .rail) {
    padding-left: var(--width-rail);
  }

  .rail {
    position: fixed;
    inset: 0 auto 0 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    width: var(--width-rail);
    padding: var(--space-5) var(--space-3);
    border-right: 1px solid var(--color-line);
    background: rgba(11, 14, 19, 0.8);
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--color-line-strong) transparent;
  }

  .rail-menu {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--space-6);
  }

  .rail-account {
    margin-top: auto;
  }
}

/* A narrower screen has no bar at all: the menu is a round button in the bottom right
   corner, under the thumb, as the admin panel's own is on a phone (the owner,
   03.10.2026: «сделай для маленьких экранов только бургер меню снизу с права»). Open,
   the menu stands over the page above the button and the page dims; a tap on the dimmed
   page shuts the menu without reaching what is under it (js/rail.js). */
@media (max-width: 960px) {
  .rail .brand {
    display: none;
  }

  .rail-toggle {
    position: fixed;
    right: var(--gutter);
    bottom: var(--gutter);
    z-index: calc(var(--layer-menu) + 3);
    display: grid;
    width: var(--control-height-lg);
    height: var(--control-height-lg);
    border: 0;
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    color: var(--color-on-accent);
    box-shadow: var(--shadow-card);
  }

  .rail-toggle:hover {
    background: var(--color-accent-hover);
  }

  .rail-menu {
    display: none;
  }

  .rail:has(.rail-toggle[aria-expanded="true"]) .rail-menu {
    position: fixed;
    right: var(--gutter);
    bottom: calc(var(--gutter) + var(--control-height-lg) + var(--space-2));
    z-index: calc(var(--layer-menu) + 3);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    width: min(var(--width-rail), calc(100% - 2 * var(--gutter)));
    max-height: calc(100dvh - 2 * var(--gutter) - var(--control-height-lg) - var(--space-2));
    padding: var(--space-2);
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--color-line-strong);
    border-radius: var(--radius);
    background: var(--color-surface-solid);
    box-shadow: var(--shadow-card);
    transition:
      opacity var(--transition),
      transform var(--transition);
  }

  .rail:has(.rail-toggle[aria-expanded="true"])::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: calc(var(--layer-menu) + 2);
    background: var(--color-backdrop);
  }

  /* Rises out of the button. */
  @starting-style {
    .rail:has(.rail-toggle[aria-expanded="true"]) .rail-menu {
      opacity: 0;
      transform: translateY(var(--space-2));
    }
  }

  /* Lines a fingertip high. */
  .rail-nav a {
    min-height: var(--control-height);
  }

  .rail-account {
    padding-top: var(--space-2);
  }

  /* Toasts come in above the button, not over it; the chat has them on top already. */
  body:has(> .rail):not(.chat-page) .toasts {
    bottom: calc(var(--gutter) + var(--control-height-lg) + var(--space-3));
  }

  /* The chat's form to write leaves the corner to the button, «Отправить» beside it. */
  .chat-form-row {
    margin-right: calc(var(--control-height-lg) + var(--space-2));
  }
}

/* In the admin panel on a phone its own button holds the menu — its parts, and under
   them the site's (.sidebar-site) — so there is one button in the corner, not two. */
@media (max-width: 720px) {
  body:has(.menu-button) .rail {
    display: none;
  }
}

.page {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
  width: min(var(--width-wide), 100%);
  margin: 0 auto;
  padding: var(--space-8) var(--gutter) var(--space-12);
}

.layout {
  display: grid;
  grid-template-columns: var(--width-sidebar) minmax(0, 1fr);
  gap: var(--space-6);
  width: min(var(--width-wide), 100%);
  margin: 0 auto;
  padding: var(--space-6) var(--gutter) var(--space-12);
}

/* Room to scroll the end of a page clear of the button in the corner — the site's menu
   (.rail) from 960 px, the admin panel's own from 720. After .page and .layout: their
   padding would undo it. The front page ends in its footer, whose words stand in the
   middle. */
@media (max-width: 960px) {
  .page,
  .layout {
    padding-bottom: calc(var(--gutter) + var(--control-height-lg) + var(--space-6));
  }
}

.sidebar {
  display: grid;
  align-content: start;
  gap: var(--space-1);
}

/* On a wide screen the menu stays in sight while a long page scrolls under it, and a
   menu taller than the screen scrolls in its own box (the owner, 02.10.2026: «сделай
   что бы меню левое прокручивалось с экраном вместе если много контента, а если и в
   меню не влазит пункты то что бы пункты прокручивались в своём окне»). A grid
   stretches its items to the row, and a menu as tall as the page has nowhere to
   stick: it is as tall as itself here. Its padding, given back by the margin, keeps
   the focus ring of a line at its edge inside the box that scrolls. On a phone the
   menu is a box over the page and scrolls in it already (below). */
@media (min-width: 721px) {
  .sidebar {
    position: sticky;
    top: var(--space-6);
    align-self: start;
    max-height: calc(100dvh - 2 * var(--space-6));
    margin: calc(-1 * var(--space-1));
    padding: var(--space-1);
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--color-line-strong) transparent;
  }
}

/* «Настройки Valheim»: a line of the menu that opens a dialog of the pages behind it,
   not a page of its own. Under its name, gold, the one of them open now. */
.sidebar .sidebar-group {
  display: grid;
  gap: 2px;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  font-weight: var(--weight-medium);
  text-align: left;
  cursor: pointer;
}

.sidebar .sidebar-group:hover {
  color: var(--color-text);
  background: var(--color-hover);
}

.sidebar .sidebar-group[aria-current="page"] {
  color: var(--color-text);
  background: var(--color-accent-soft);
}

.sidebar-group-now {
  color: var(--color-accent);
  font-size: var(--text-sm);
  font-weight: var(--weight-normal);
}

/* A link out of the panel's own sections, set apart from them. */
.sidebar .sidebar-out {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-line);
  border-radius: 0;
}

/* The site's own parts, in the panel's menu on a phone alone, where the site's menu
   gives the corner to it (.rail). */
.sidebar-site {
  display: none;
}

.sidebar-logout {
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  font: inherit;
  font-weight: var(--weight-medium);
  text-align: left;
  cursor: pointer;
}

.sidebar-logout:hover {
  color: var(--color-text);
  background: var(--color-hover);
}

/* On a phone the menu is not a row of tabs above the page but a list behind a
   round button in the bottom right corner, under the thumb (the owner, 27.09.2026:
   «спрячь это в бургер меню»). The row took two lines there, and «Доступ на
   сервер» three. Open, the list stands over the page above the button, the page
   dims, and a tap on it closes the list without reaching what is under it: there
   are switches on the page that act at once. Whether it is open is the button's
   aria-expanded and nothing else; js/admin.js turns it. */
.menu-button {
  position: fixed;
  right: var(--gutter);
  bottom: var(--gutter);
  z-index: calc(var(--layer-menu) + 1);
  display: none;
  place-items: center;
  width: var(--control-height-lg);
  height: var(--control-height-lg);
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  color: var(--color-on-accent);
  box-shadow: var(--shadow-card);
  cursor: pointer;
  transition: background-color var(--transition);
}

.menu-button:hover {
  background: var(--color-accent-hover);
}

/* Three lines: the middle one is the element, the other two its ::before and
   ::after. Open, the middle one goes and the other two cross into a ×. */
.menu-icon,
.menu-icon::before,
.menu-icon::after {
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 1px;
  background: currentColor;
  transition:
    background-color var(--transition),
    transform var(--transition);
}

.menu-icon {
  position: relative;
}

.menu-icon::before,
.menu-icon::after {
  content: "";
  position: absolute;
  left: 0;
}

.menu-icon::before {
  top: -6px;
}

.menu-icon::after {
  top: 6px;
}

.menu-button[aria-expanded="true"] .menu-icon,
.rail-toggle[aria-expanded="true"] .menu-icon {
  background-color: transparent;
}

.menu-button[aria-expanded="true"] .menu-icon::before,
.rail-toggle[aria-expanded="true"] .menu-icon::before {
  transform: translateY(6px) rotate(45deg);
}

.menu-button[aria-expanded="true"] .menu-icon::after,
.rail-toggle[aria-expanded="true"] .menu-icon::after {
  transform: translateY(-6px) rotate(-45deg);
}

/* The requests waiting, as beside «Заявки» in the admin panel's menu, and on the
   site's own button what is unread in the chat: with a menu shut the number would be
   out of sight. A ring of the page's colour parts it from the button, gold on gold. The
   chat lists its unread itself, room by room and live, and its button goes without. */
.menu-button .count,
.rail-toggle .count {
  position: absolute;
  top: -2px;
  right: -2px;
  margin: 0;
  box-shadow: 0 0 0 2px var(--color-bg);
}

.menu-button[aria-expanded="true"] .count,
.rail-toggle[aria-expanded="true"] .count {
  display: none;
}

.menu-shade {
  position: fixed;
  inset: 0;
  z-index: var(--layer-menu);
  display: none;
  background: var(--color-backdrop);
}

.content {
  min-width: 0;
}

.content section {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
}

/* ==== The front page =======================================================
   .home            its column: the hero, then its parts one under another
   .hero            the title, the words under it and the two ways in
   .home-section    a part of the page with its title
   .server-grid     a card to each game server (.server-card), three to a row
   .steps           the numbered way onto a server, a box to each .step
   .choices         the same boxes for a choice, with no numbers: the ways to our mod
   .site-foot       the last line of the page                                */

.home {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-12);
  width: min(var(--width-home), 100%);
  margin: 0 auto;
  padding: var(--space-8) var(--gutter) var(--space-12);
}

.hero {
  display: grid;
  justify-items: start;
  gap: var(--space-4);
  padding: var(--space-10) 0 var(--space-2);
}

.hero h1 {
  margin: 0;
  font-size: var(--text-hero);
  font-weight: var(--weight-heavy);
  line-height: 1.1;
}

.hero-accent {
  color: var(--color-accent);
}

.hero-lead {
  max-width: 62ch;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-lg);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.home-section {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  scroll-margin-top: var(--space-4);
}

.home-section > h2 {
  margin: 0;
  font-size: var(--text-2xl);
}

/* auto-fill: a lone server's card keeps its width and does not take the whole row
   (the owner, 28.09.2026: «сделай карточку сервера поменьше их же потом будет
   много»); a card takes the whole row only on a phone. */
.server-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(var(--width-server-card), 100%), 1fr));
  gap: var(--space-4);
}

.server-card {
  display: grid;
  align-content: start;
  gap: var(--space-3);
  padding: var(--space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: var(--radius);
}

.server-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

.server-game {
  margin: 0;
  color: var(--color-accent);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.server-name {
  margin: 0;
  font-size: var(--text-xl);
  overflow-wrap: anywhere;
}

.server-state {
  align-items: flex-end;
}

.server-seen {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  white-space: nowrap;
}

/* The card's table names its rows by their words, on one line, and not in the width
   a list's names take: in a card a third of the page wide, that width left the values
   no room, and names broken in two made every row two lines tall. */
.server-card .table-compact tbody th {
  width: auto;
  white-space: nowrap;
}

.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}

.step {
  display: grid;
  align-content: start;
  gap: var(--space-2);
  padding: var(--space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: var(--radius);
  counter-increment: step;
}

/* The step's number, gold in a circle. */
.step::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: var(--control-height-sm);
  height: var(--control-height-sm);
  border-radius: var(--radius-pill);
  background: var(--color-accent-soft);
  color: var(--color-accent);
  font-weight: var(--weight-bold);
}

.step h3,
.step p {
  margin: 0;
}

.step p {
  color: var(--color-text-muted);
}

.choices .step::before {
  content: none;
}

.mod-game {
  display: grid;
  gap: var(--space-3);
}

.mod-about {
  max-width: 62ch;
  margin: 0;
  color: var(--color-text-muted);
}

.site-foot {
  padding: var(--space-6) var(--gutter) var(--space-8);
  border-top: 1px solid var(--color-line);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  text-align: center;
}

.site-foot p {
  margin: 0;
}

@media (max-width: 560px) {
  .hero {
    padding-top: var(--space-4);
  }
}

@media (max-width: 480px) {
  .hero h1 {
    font-size: var(--text-3xl);
  }

  .server-card {
    padding: var(--space-5) var(--space-4);
  }
}

/* 720 px is also in js/admin.js, which closes the menu when the screen grows past
   it: change both. */
@media (max-width: 720px) {
  .layout {
    grid-template-columns: minmax(0, 1fr);
    padding-top: var(--space-4);
  }

  .menu-button {
    display: grid;
  }

  .sidebar {
    display: none;
  }

  .menu-button[aria-expanded="true"] ~ .sidebar {
    position: fixed;
    right: var(--gutter);
    bottom: calc(var(--gutter) + var(--control-height-lg) + var(--space-2));
    z-index: calc(var(--layer-menu) + 1);
    display: grid;
    width: min(var(--width-sidebar), calc(100% - 2 * var(--gutter)));
    max-height: calc(100dvh - 2 * var(--gutter) - var(--control-height-lg) - var(--space-2));
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--space-2);
    border: 1px solid var(--color-line-strong);
    border-radius: var(--radius);
    background: var(--color-surface-solid);
    box-shadow: var(--shadow-card);
    transition:
      opacity var(--transition),
      transform var(--transition);
  }

  .menu-button[aria-expanded="true"] ~ .menu-shade {
    display: block;
    transition: opacity var(--transition);
  }

  /* Rises out of the button. It goes at once: the page it uncovers is the answer. */
  @starting-style {
    .menu-button[aria-expanded="true"] ~ .sidebar {
      opacity: 0;
      transform: translateY(var(--space-2));
    }

    .menu-button[aria-expanded="true"] ~ .menu-shade {
      opacity: 0;
    }
  }

  /* A line a fingertip high. */
  .sidebar a {
    display: flex;
    align-items: center;
    min-height: var(--control-height);
  }

  .sidebar .sidebar-group {
    align-content: center;
    min-height: var(--control-height);
  }

  .sidebar .sidebar-out {
    margin-top: var(--space-1);
    padding-top: var(--space-2);
  }

  .sidebar-site {
    display: grid;
    gap: 2px;
    margin-top: var(--space-1);
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-line);
  }

  .sidebar-logout {
    min-height: var(--control-height);
  }

  /* Toasts come in above the menu's button, not over it. */
  body:has(.menu-button) .toasts {
    bottom: calc(var(--gutter) + var(--control-height-lg) + var(--space-3));
  }
}

@media (max-width: 480px) {
  .card {
    padding: 28px var(--space-5);
  }

  h1 {
    font-size: var(--text-xl);
  }

  .panel {
    padding: var(--space-5) var(--space-4);
  }
}

/* The chat (/chat): the bar on top and, under it, the list of rooms and the open room,
   filling the screen; only the messages and the list scroll, each in its own box. On a
   phone one of the two at a time, as data-view on .chat says (js/chat.js): the list, or
   the room with «←» back to it. */
.chat-page {
  display: flex;
  flex-direction: column;
  height: 100dvh;
  overflow: hidden;
}

.chat {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: var(--width-chat-side) minmax(0, 1fr);
  gap: var(--space-4);
  width: min(var(--width-wide), 100%);
  margin: 0 auto;
  padding: var(--space-4) var(--gutter);
}

/* The form to write is at the bottom of the chat: toasts come in at the top there,
   over the bar, not over the button that sends. */
.chat-page .toasts {
  top: var(--gutter);
  bottom: auto;
}

@media (min-width: 721px) {
  .chat-back {
    display: none;
  }
}

/* 720 px is also in js/chat.js, which opens the first room by itself on a wider screen. */
@media (max-width: 720px) {
  .chat {
    grid-template-columns: minmax(0, 1fr);
    padding: var(--space-2);
  }

  .chat[data-view="rooms"] .chat-room,
  .chat[data-view="room"] .chat-side {
    display: none;
  }
}
