/* The Wolf Project website. Colours are the game client's design tokens
   (client/wolf/modules/wolfui/tokens.lua, Wolf.color). No external fonts or CDNs. */

:root {
  --ground: #12151a;
  --surface: #191d24;
  --surface-high: #212630;
  --line: #2b323d;
  --ink: #e8ebef;
  --ink-muted: #9aa4b1;
  --ink-faint: #6f7987;
  --accent: #2f6f9e;
  --accent-hover: #3a82b6;
  --accent-ink: #ffffff;
  --accent-soft: #17303f;
  --good: #4c9c6f;
  --warn: #d09a3c;
  --bad: #c0554d;

  --tight: 4px;
  --gap: 8px;
  --block: 16px;
  --gutter: 24px;
  --radius: 8px;
  --control: 44px;

  /* 2026-09-18, owner's choice: the interface face of whatever machine is reading, so the site looks current on
     every device and still downloads nothing (the no-external-fonts rule stands). The game client keeps its own
     bitmap faces - they were never the same fonts, only the same name. */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "DejaVu Sans", sans-serif;
  --mono: ui-monospace, "SF Mono", "DejaVu Sans Mono", Consolas, "Liberation Mono", monospace;
}

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

html { color-scheme: dark; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--ground);
  color: var(--ink);
  font: 16px/1.6 var(--font);
  letter-spacing: -0.003em;
  -webkit-text-size-adjust: 100%;
}

a { color: #7fb6dd; text-underline-offset: 2px; }
a:hover { color: #a7cfeb; }
:focus-visible { outline: 2px solid var(--accent-hover); outline-offset: 2px; }

h1, h2, h3 { line-height: 1.2; margin: 0 0 var(--block); font-weight: 650; text-wrap: balance; }
h1 { font-size: clamp(1.55rem, 1.2rem + 1.6vw, 2rem); letter-spacing: -0.02em; }
h2 { font-size: clamp(1.1rem, 1rem + 0.4vw, 1.25rem); letter-spacing: -0.01em; }
h3 { font-size: 1rem; margin-top: var(--gutter); letter-spacing: -0.005em; }
p { margin: 0 0 var(--block); }
code { font-family: var(--mono); font-size: 0.95em; background: var(--surface-high); padding: 1px 6px; border-radius: 4px; }

.muted { color: var(--ink-muted); }

.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: var(--block); top: var(--block); background: var(--accent); color: var(--accent-ink); padding: var(--gap); z-index: 10; }

/* Top bar */
.topbar { background: var(--surface); border-bottom: 1px solid var(--line); }
.topbar-inner {
  max-width: 1100px; margin: 0 auto; padding: 0 var(--block);
  min-height: 60px; display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap) var(--block);
}
.brand { display: flex; align-items: center; gap: var(--gap); color: var(--ink); text-decoration: none; font-weight: bold; letter-spacing: 0.02em; margin-right: auto; }
.brand:hover { color: var(--ink); }
.account-nav { display: flex; align-items: center; gap: var(--block); }
.account-nav a { color: var(--ink-muted); text-decoration: none; }
.account-nav a:hover, .account-nav a[aria-current="page"] { color: var(--ink); }
.account-nav a.button { color: var(--accent-ink); padding: 0 var(--block); }
.nav-form { margin: 0; }

.sections { border-top: 1px solid var(--line); background: var(--ground); }
.sections-inner { max-width: 1100px; margin: 0 auto; padding: 0 var(--gap); display: flex; gap: 2px; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: thin; }
.sections a { flex: none; display: flex; align-items: center; min-height: var(--control); padding: 0 12px; color: var(--ink-muted); text-decoration: none; white-space: nowrap; border-bottom: 2px solid transparent; }
.sections a:hover { color: var(--ink); }
.sections a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent-hover); }

/* Page */
.page { flex: 1; width: 100%; max-width: 1100px; margin: 0 auto; padding: var(--gutter) var(--block) 48px; }

.hero { padding: 32px 0 var(--gutter); }
.hero h1 { font-size: 2.2rem; margin-bottom: var(--gap); }
.eyebrow { color: var(--warn); text-transform: uppercase; letter-spacing: 0.12em; font-size: 0.8rem; margin-bottom: var(--gap); }
.lead { color: var(--ink-muted); font-size: 1.1rem; max-width: 60ch; }

.grid { display: grid; gap: var(--block); grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); align-items: start; }

.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--gutter); }
.card-narrow { max-width: 460px; margin: 0 auto; }
@media (max-width: 480px) { .card { padding: var(--block); } }

.crumbs { font-size: 0.9rem; color: var(--ink-muted); margin-bottom: var(--gap); }

.facts { margin: 0 0 var(--block); display: grid; gap: var(--gap); }
.facts > div { display: grid; grid-template-columns: minmax(120px, 40%) 1fr; gap: var(--gap); padding-bottom: var(--gap); border-bottom: 1px solid var(--line); }
.facts > div:last-child { border-bottom: 0; }
.facts dt { color: var(--ink-muted); }
.facts dd { margin: 0; overflow-wrap: anywhere; }

.badge { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 0.8rem; background: var(--surface-high); border: 1px solid var(--line); color: var(--ink-muted); }
.badge-good { color: #bfe6cf; border-color: var(--good); background: rgba(76, 156, 111, 0.15); }
.badge-warn { color: #f2d49c; border-color: var(--warn); background: rgba(208, 154, 60, 0.15); }

/* Alerts */
.alert { border-radius: var(--radius); padding: 12px var(--block); margin-bottom: var(--block); border: 1px solid; }
.alert-good { border-color: var(--good); background: rgba(76, 156, 111, 0.12); }
.alert-bad { border-color: var(--bad); background: rgba(192, 85, 77, 0.12); }

/* Forms */
.form { display: grid; gap: var(--block); margin-bottom: var(--block); }
.field { display: grid; gap: var(--tight); }
.field label { font-weight: bold; font-size: 0.92rem; }
.field input {
  width: 100%; min-height: var(--control); padding: 0 12px;
  background: var(--ground); color: var(--ink); border: 1px solid var(--line); border-radius: 6px;
  font: inherit;
}
.field textarea {
  width: 100%; padding: 10px 12px; resize: vertical;
  background: var(--ground); color: var(--ink); border: 1px solid var(--line); border-radius: 6px;
  font: inherit;
}
.field input:hover, .field textarea:hover { border-color: var(--ink-faint); }
.field input:focus, .field textarea:focus { border-color: var(--accent-hover); outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }
.field-invalid input { border-color: var(--bad); }
.hint { margin: 0; font-size: 0.85rem; color: var(--ink-faint); }
.field-error { margin: 0; font-size: 0.88rem; color: #ec9a93; }
.form-links { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--gap); margin: 0; font-size: 0.92rem; }

.button, .link-button { font: inherit; cursor: pointer; }
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--gap);
  min-height: var(--control); padding: 0 20px; border-radius: 6px; border: 1px solid var(--accent);
  background: var(--accent); color: var(--accent-ink); text-decoration: none; font-weight: bold;
}
.button:hover { background: var(--accent-hover); color: var(--accent-ink); }
.button:disabled { opacity: 0.6; cursor: progress; }
.button-small { min-height: 36px; }
.button-block { width: 100%; }
.button-quiet { background: transparent; color: var(--ink); border-color: var(--line); }
.button-quiet:hover { background: var(--surface-high); color: var(--ink); }
.button-danger { background: transparent; color: #ec9a93; border-color: var(--bad); }
.button-danger:hover { background: rgba(192, 85, 77, 0.15); color: #f3b8b3; }
.link-button { background: none; border: 0; padding: 0; color: var(--ink-muted); }
.link-button:hover { color: var(--ink); }
.actions { display: flex; flex-wrap: wrap; gap: var(--gap); margin: var(--block) 0 0; }

.qr { display: block; background: #fff; border-radius: 6px; margin-bottom: var(--block); max-width: 100%; height: auto; }
.secret { display: inline-block; word-break: break-all; letter-spacing: 0.08em; }
.codes { list-style: none; padding: 0; margin: 0 0 var(--block); display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--gap); }
.codes code { display: block; text-align: center; padding: var(--gap); font-size: 1rem; }

/* Tables, choices (W1) */
.card-wide { margin-bottom: var(--block); }
.card-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--gap); margin-bottom: var(--block); }
.card-head h2 { margin: 0; }
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.table th, .table td { text-align: left; padding: 10px var(--gap); border-bottom: 1px solid var(--line); white-space: nowrap; }
.table th { color: var(--ink-muted); font-weight: bold; font-size: 0.85rem; }
.table tbody tr:hover { background: var(--surface-high); }
.actions-cell { text-align: right; }
.actions-cell form { margin: 0; }
.badge-bad { color: #f3b8b3; border-color: var(--bad); background: rgba(192, 85, 77, 0.15); }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

.choice { border: 1px solid var(--line); border-radius: 6px; padding: var(--gap) 12px 12px; margin: 0; display: flex; flex-wrap: wrap; gap: var(--gap) var(--block); }
.choice legend { font-weight: bold; font-size: 0.92rem; padding: 0 var(--tight); }
.choice-option { display: inline-flex; align-items: center; gap: 6px; min-height: var(--control); cursor: pointer; }
.choice-option input { width: 18px; height: 18px; accent-color: var(--accent-hover); }
.choice.field-invalid { border-color: var(--bad); }
.choice .field-error { flex-basis: 100%; }
.field select {
  width: 100%; min-height: var(--control); padding: 0 12px;
  background: var(--ground); color: var(--ink); border: 1px solid var(--line); border-radius: 6px; font: inherit;
}
.field-invalid select { border-color: var(--bad); }
.alert ul { margin: var(--gap) 0 0; padding-left: 20px; }
.alert p { margin: 0; }

/* Public pages (W2) */
.section { margin-top: var(--gutter); }
.news-card { margin-bottom: var(--block); }
.news-card h2 a, .news-card h3 a { color: var(--ink); text-decoration: none; }
.news-card h2 a:hover, .news-card h3 a:hover { color: #a7cfeb; }
.prose { overflow-wrap: anywhere; }
.prose h2, .prose h3, .prose h4 { margin-top: var(--gutter); }
.prose pre { overflow-x: auto; background: var(--ground); padding: 12px; border-radius: 6px; }
.prose pre code { background: none; padding: 0; }
.prose blockquote { margin: 0 0 var(--block); padding-left: var(--block); border-left: 3px solid var(--line); color: var(--ink-muted); }
.prose table { border-collapse: collapse; margin-bottom: var(--block); }
.prose th, .prose td { border: 1px solid var(--line); padding: 6px 10px; }
.steps { padding-left: 20px; margin: 0 0 var(--block); }
.steps li { margin-bottom: var(--gap); }
.pagination { display: flex; align-items: center; justify-content: center; gap: var(--block); margin: var(--block) 0; }
.filters { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--block); margin-bottom: var(--block); }
.filters .field { min-width: 180px; }
.hash { font-size: 0.78rem; word-break: break-all; white-space: normal; }
.table td .hash { display: inline-block; max-width: 22ch; }
.deaths { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--gap); }
.deaths li { padding-bottom: var(--gap); border-bottom: 1px solid var(--line); }
.deaths li:last-child { border-bottom: 0; }
.plain-list { list-style: none; padding: 0; margin: 0; }
.plain-list li { min-height: var(--control); display: flex; align-items: center; }
.card-span { grid-column: span 2; }
@media (max-width: 760px) { .card-span { grid-column: auto; } }

/* Guilds and houses (W3) */
.card-head h1 { margin: 0; }
.guild-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--block); margin-bottom: var(--block); }
.guild-head h1 { margin: 0 0 var(--tight); }
.guild-head p { margin: 0; }
.guild-head > div { flex: 1; min-width: 200px; }
.logo { display: inline-flex; align-items: center; justify-content: center; width: 64px; height: 64px; flex: none; border-radius: 6px; background: var(--ground); border: 1px solid var(--line); object-fit: contain; }
.logo-small { width: 32px; height: 32px; border-radius: 4px; }
.logo-empty { color: var(--ink-muted); font-weight: bold; font-size: 1.6rem; text-transform: uppercase; }
.logo-small.logo-empty { font-size: 0.9rem; }
.logo-cell { width: 48px; }
.motd { margin: 0; overflow-wrap: anywhere; }
.guild-description { margin: 0; white-space: pre-line; overflow-wrap: anywhere; }
.score { font-weight: bold; }
.inline-form { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--gap); margin: 0; }
.inline-form form { margin: 0; }
td .inline-form { justify-content: flex-start; }
.actions-cell .inline-form { justify-content: flex-end; }
.inline-form input[type="text"] { min-height: 36px; width: 14ch; padding: 0 8px; background: var(--ground); color: var(--ink); border: 1px solid var(--line); border-radius: 6px; font: inherit; }
.inline-form input[type="text"]:focus { border-color: var(--accent-hover); outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }
.rank-form { justify-content: flex-start; margin-bottom: var(--gap); }
.rank-form label { min-width: 100px; color: var(--ink-muted); }
.field input[type="file"] { padding: 8px; min-height: auto; }
.split { justify-content: space-between; gap: var(--gap); border-bottom: 1px solid var(--line); }
.split:last-child { border-bottom: 0; }
.split form { margin: 0; }

/* Admin panel (W4) */
.admin-nav { display: flex; flex-wrap: wrap; gap: var(--tight) var(--gap); margin-bottom: var(--gutter); padding-bottom: var(--gap); border-bottom: 1px solid var(--line); }
.admin-nav a { display: inline-flex; align-items: center; min-height: 36px; padding: 0 12px; border-radius: 6px; color: var(--ink-muted); text-decoration: none; }
.admin-nav a:hover, .admin-nav a[aria-current="page"] { background: var(--surface-high); color: var(--ink); }
.admin-subnav { margin-bottom: var(--block); border-bottom: 0; }
.stats { display: grid; gap: var(--gap); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); margin-bottom: var(--block); }
.stat { display: block; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 12px var(--block); color: var(--ink); text-decoration: none; }
.stat:hover { border-color: var(--ink-faint); color: var(--ink); }
.stat strong { display: block; font-size: 1.4rem; }
.admin-forms { margin-bottom: var(--block); }
.admin-forms h3 { margin-top: 0; }
.admin-forms h3 + form + h3 { margin-top: var(--gutter); }
.admin-inline { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); align-items: end; }
.table td.wrap { white-space: normal; overflow-wrap: anywhere; min-width: 14ch; max-width: 40ch; }
.field textarea.news-body { min-height: 360px; font-family: var(--mono); font-size: 0.92rem; }
.inline-form input[type="text"]::placeholder { color: var(--ink-faint); }
.table td.depth-1 { padding-left: 28px; }
.table td.depth-2 { padding-left: 48px; }
.table td.depth-3 { padding-left: 68px; }
.table td.depth-4 { padding-left: 88px; }
.table td.depth-5 { padding-left: 108px; }
.table td.depth-6 { padding-left: 128px; }
.table td.depth-7 { padding-left: 148px; }
.table td.depth-8 { padding-left: 168px; }

/* Footer */
.footer { border-top: 1px solid var(--line); background: var(--surface); }
.footer-inner { max-width: 1100px; margin: 0 auto; padding: var(--block); display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--gap); font-size: 0.85rem; }

/* Home page atmosphere (2026-09-18, owner's "Den" direction). Tokens above are unchanged: this only adds depth,
   a larger wolf mark and a clearer hierarchy to what was a flat stack of cards. */

.hero-den {
  position: relative;
  overflow: hidden;
  margin: 0 calc(-1 * var(--block)) var(--gutter);
  padding: 48px var(--block) 36px;
  background:
    radial-gradient(1100px 380px at 18% -12%, rgba(47, 111, 158, 0.28), transparent 68%),
    radial-gradient(760px 300px at 92% 0%, rgba(208, 154, 60, 0.10), transparent 70%);
  border-bottom: 1px solid var(--line);
}
/* The mark is decoration: it carries no meaning a screen reader needs, so it lives in CSS rather than the markup. */
.hero-den::after {
  content: "";
  position: absolute;
  top: -34px; right: -28px;
  width: 340px; height: 340px;
  background: url("../img/wolf-mark.svg") no-repeat center / contain;
  opacity: 0.09;
  pointer-events: none;
}
.hero-den > * { position: relative; }
.hero-den h1 { font-size: 2.5rem; letter-spacing: -0.01em; text-wrap: balance; margin-bottom: 10px; }
.hero-den .lead { font-size: 1.02rem; max-width: 46ch; margin-bottom: var(--gutter); }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--gap); }
@media (max-width: 560px) {
  .hero-den { padding: 32px var(--block) 28px; }
  .hero-den h1 { font-size: 1.9rem; }
  .hero-den::after { width: 220px; height: 220px; top: -20px; right: -40px; }
}

/* Cards catch a little light from above and answer the pointer. */
.card {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.028), transparent 42%), var(--surface);
  transition: border-color 120ms ease, transform 120ms ease;
}
.card:hover { border-color: var(--ink-faint); }
a.card:hover, .card a.stat:hover { transform: translateY(-1px); }

/* The most-read block on the page should not look like every other list. */
.status-card { border-color: var(--accent); box-shadow: inset 0 0 0 1px rgba(47, 111, 158, 0.22); }
.status-card .badge-good { font-weight: bold; }

/* A section heading with a rule that fades out, instead of a bare h2. */
.section > .card-head { margin-bottom: var(--gap); }
.section > .card-head + .section-rule { height: 1px; background: linear-gradient(90deg, var(--line), transparent); margin-bottom: var(--block); }

/* The brand mark was 28px, which read as a favicon rather than an identity. */
.brand img { width: 34px; height: 34px; }
.brand span { font-size: 1.02rem; }

/* The rest of the site (2026-09-18). The home page got the "Den" treatment first; these rules carry the same
   vocabulary to every other page WITHOUT touching 50 templates, each of which writes its own bare <h1>. */

/* A page heading now reads as a heading of a page: larger, with a rule that fades the way the home page's
   section rule does. `.page > h1` only catches the bare ones, so a heading inside a card (rules, a guild, a
   character) keeps its own size and is handled below. */
.page > h1 {
  font-size: 1.9rem;
  letter-spacing: -0.01em;
  text-wrap: balance;
  margin-bottom: var(--gap);
  padding-bottom: 12px;
  position: relative;
}
.page > h1::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--accent), var(--line) 30%, transparent);
}
/* The sentence under a page heading, where a page writes one. */
.page > h1 + p.muted, .page > h1 + p.lead { margin-top: calc(-1 * var(--gap)); margin-bottom: var(--gutter); max-width: 70ch; }
.card > h1 { font-size: 1.6rem; }

/* Tables carry most of this site - highscores, who is online, downloads, guilds, houses, the admin logs. */
.table-wrap { border: 1px solid var(--line); border-radius: var(--radius); background: var(--ground); }
.card .table-wrap { background: transparent; border-color: transparent; }
.table thead th {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.72rem;
  color: var(--ink-faint);
}
.table tbody tr { transition: background-color 120ms ease; }
.table tbody tr:hover { background: var(--surface-high); }
/* Figures line up when they are in columns. */
.table td { font-variant-numeric: tabular-nums; }
.table td:first-child, .table th:first-child { padding-left: 12px; }
.table td:last-child, .table th:last-child { padding-right: 12px; }

/* Ranked lists read better when the rank itself is quiet and the name is not. */
.table td a { text-decoration: none; }
.table td a:hover { text-decoration: underline; }

/* The filter row above a table (highscores, the admin logs) sits on the same shelf as its table. */
.filters {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--block);
}

/* Long-form pages: rules, news, the changelog. Reading measure, and headings that breathe. */
.prose { max-width: 72ch; }
.prose h2 { font-size: 1.15rem; padding-bottom: 6px; border-bottom: 1px solid var(--line); }
.prose h3 { font-size: 1rem; color: var(--ink); }
.prose li { margin-bottom: 4px; }
.prose a { text-underline-offset: 3px; }

/* Numbers that matter (the admin dashboard, and anywhere .stat is used). */
.stat strong { font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
.stat { transition: border-color 120ms ease, transform 120ms ease; }

/* Fact lists (a character, a guild, the server) are the site's second most common block after tables. */
.facts dd { font-variant-numeric: tabular-nums; }

/* Pagination as a control, not two loose links. */
.pagination a, .pagination strong {
  display: inline-flex; align-items: center; min-height: 36px; padding: 0 14px;
  border: 1px solid var(--line); border-radius: 6px; text-decoration: none;
}
.pagination strong { background: var(--surface-high); }
.pagination a:hover { border-color: var(--ink-faint); }

/* The footer is the last thing on every page and was a bare line of text. */
.footer-inner { align-items: center; }
.footer-inner span:first-child { font-weight: bold; color: var(--ink-muted); }

/* Anyone who asks their system for less motion gets none of the movement added above. */
@media (prefers-reduced-motion: reduce) {
  .card, .stat, .table tbody tr { transition: none; }
  a.card:hover, .card a.stat:hover, .stat:hover { transform: none; }
}

/* Forms are the site's second most common block after cards - 24 of the templates are one: logging in,
   registering, the whole account panel, every admin action. They were as flat as everything else. */

/* A form that stands alone on its page (login, register, password) reads as one object, not a floating box. */
.card-narrow { border-color: var(--line); }
.card-narrow h1, .card-narrow h2 { padding-bottom: 12px; border-bottom: 1px solid var(--line); margin-bottom: var(--gutter); }

/* The label is the question, the hint is the aside: they should not weigh the same. */
.field label { letter-spacing: 0.01em; color: var(--ink); }
.field input:focus, .field textarea:focus, .field select:focus { background: var(--surface); }

/* One badge vocabulary across the site: 15 templates use them, for staff, bans, house states, ban history. */
.badge { letter-spacing: 0.02em; font-variant-numeric: tabular-nums; }

/* The row of buttons under a form: the primary action leads, the rest stay quiet. */
.actions { align-items: center; }
.form-links { color: var(--ink-muted); }

/* Modernising pass (2026-09-18). The palette is unchanged; what changes is weight, spacing and behaviour. */

/* The top bar follows the reader instead of scrolling away, and the page behind it shows through. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
@supports not (backdrop-filter: blur(4px)) { .topbar { background: var(--surface); } }
html { scroll-behavior: smooth; scroll-padding-top: 116px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* Elevation instead of a flat plane: a card sits on the page, a panel sits under the reader's hand. */
.card { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28); }
.card:hover { box-shadow: 0 6px 18px rgba(0, 0, 0, 0.30); }
.button { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35); }
.button:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) { .button:active { transform: none; } }

/* A heading row that is a heading row: the title leads, its action sits opposite, quietly. */
.card-head h2 { letter-spacing: -0.01em; }
.card-head > a, .card-head > span { font-size: 0.9rem; }

/* Tabs read as a control strip, not as a line of links. */
.sections a { border-radius: 6px 6px 0 0; transition: background-color 120ms ease, color 120ms ease; }
.sections a:hover { background: var(--surface); }
.sections a[aria-current="page"] { background: var(--surface); }
@media (prefers-reduced-motion: reduce) { .sections a { transition: none; } }

/* Long tables keep their header in view while the rows scroll under it. The header must stay OPAQUE wherever it
   sits: an earlier rule makes it transparent inside a card, and a transparent sticky header lets the rows scroll
   visibly through the column names. */
.table-wrap { max-height: min(72vh, 900px); overflow-y: auto; }
.table thead th { position: sticky; top: 0; z-index: 1; background: var(--surface-high); }
.card .table thead th { background: var(--surface); }

/* Controls: one radius, one focus ring, one height everywhere. */
.field input, .field select, .field textarea, .button, .inline-form input[type="text"] { border-radius: 8px; }
.button { letter-spacing: 0.01em; }

/* Phone: the page stops feeling like a shrunken desktop. */
@media (max-width: 560px) {
  .page { padding: var(--block) 12px 32px; }
  .topbar-inner { padding: 0 12px; min-height: 56px; }
  .brand span { font-size: 0.95rem; }
  .card { padding: var(--block); }
  .table th, .table td { padding: 12px var(--gap); }
  .hero-actions .button { flex: 1 1 auto; }
}

/* A character's equipment (2026-09-18). The pictures come from the game client's own sprites, generated by
   scripts/item_sprites.py and served by /items/<id>.png; a missing picture shows the item id instead, because the
   set can lag behind a server that adds items. */
.doll-empty { font: 0.62rem var(--mono); color: var(--ink-faint); }
.doll-count {
  position: absolute; right: 2px; bottom: 1px;
  font: bold 0.68rem var(--mono); color: var(--ink);
  text-shadow: 0 0 3px #000, 0 0 3px #000;
  font-variant-numeric: tabular-nums;
}

/* The account panel's inventory IS the client's equipment window, rebuilt in CSS from the client's own sources:
   the frame of WolfSidePanel (/modules/wolfui/images/panel, a 12x12 image drawn as a 5px nine-slice), the doll of
   wolf_inventory/inventory.otui (ten 44px slots on a 50px pitch, 144x194 in all, feet under the middle column),
   WolfSlot's colours from styles/30-overlay.otui (#191d24 on a 1px #2b323d edge, square, no radius), the slot art
   the client draws under an empty slot at #ffffff60, and WolfFigure's 96x96 box for the character. The colours
   below are named because the site's palette was taken from the client's tokens and the values already match. */
.gear-list { display: flex; flex-wrap: wrap; gap: var(--block); }
.gear-char h3 { margin: 0 0 var(--gap); font-size: 1rem; }
.gear-window {
  display: inline-flex; align-items: flex-start; gap: 10px;
  background: var(--ground);
  padding: 8px;
  border: 5px solid transparent;
  border-image: url("../img/panel.png") 5 fill repeat;
}
.gear-doll {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 44px); grid-auto-rows: 44px; gap: 6px;
  width: 144px;
}
.gear-slot {
  --slot-art: none;
  position: relative;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
}
/* WolfEquipSlot's image-source: the slot's own picture, under the item, dimmed the way image-color #ffffff60
   dims it. It stays visible behind a worn item exactly as it does in the game. */
.gear-slot::before {
  content: ""; position: absolute; inset: 0;
  background: var(--slot-art) center / 34px 34px no-repeat;
  opacity: 0.38;
}
.gear-slot img, .gear-slot .doll-empty { position: relative; }
.gear-slot img { display: block; image-rendering: pixelated; }
.gear-gap { visibility: hidden; }

.slot-neck { --slot-art: url("../img/slots/neck.png"); }
.slot-head { --slot-art: url("../img/slots/head.png"); }
.slot-back { --slot-art: url("../img/slots/back.png"); }
.slot-right-hand { --slot-art: url("../img/slots/right-hand.png"); }
.slot-body { --slot-art: url("../img/slots/body.png"); }
.slot-left-hand { --slot-art: url("../img/slots/left-hand.png"); }
.slot-finger { --slot-art: url("../img/slots/finger.png"); }
.slot-legs { --slot-art: url("../img/slots/legs.png"); }
.slot-ammo { --slot-art: url("../img/slots/ammo.png"); }
.slot-feet { --slot-art: url("../img/slots/feet.png"); }

.gear-figure {
  width: 96px; height: 96px;
  display: grid; place-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
}
.gear-figure img { display: block; image-rendering: pixelated; transform: scale(2); }

@media (max-width: 480px) {
  .gear-list { gap: var(--gap); }
  .gear-window { gap: var(--gap); }
}

/* The upgrade chronicle. The level colours are the client's own (wolf/modules/wolfui/tokens.lua,
   Wolf.color.upgradeLevel): +3, +6 and +9 are the trait slots and +5 is where an attempt starts to risk the
   item, which is why the ramp turns warm at the top. */
.up-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.up-row {
  display: flex; gap: var(--gap); align-items: flex-start;
  padding: var(--gap) 0;
  border-top: 1px solid var(--line);
}
.up-list > .up-row:first-child { border-top: 0; }
.up-item {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
}
.up-item img { display: block; image-rendering: pixelated; }
.up-what { min-width: 0; }
.up-line { margin: 0; display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; }
.up-meta { margin: 2px 0 0; font-size: 0.85rem; }
.up-arrow { color: var(--ink-faint); }
.up-trait { color: var(--ink-accent, #5aa0d8); }
.up-level {
  font: bold 0.78rem var(--mono);
  padding: 1px 6px;
  border-radius: 999px;
  color: #0d1014;
  background: var(--line);
  font-variant-numeric: tabular-nums;
}
.lv-1 { background: #6fae86; } .lv-2 { background: #4c9c6f; } .lv-3 { background: #3f9f92; }
.lv-4 { background: #3f92b4; } .lv-5 { background: #5aa0d8; } .lv-6 { background: #7f93e0; }
.lv-7 { background: #a487dc; } .lv-8 { background: #c98fc0; } .lv-9 { background: #d09a3c; }
.lv-10 { background: #d9665d; }
.up-outcome { font-size: 0.82rem; padding: 1px 8px; border-radius: 999px; border: 1px solid var(--line); }
.up-success .up-outcome { color: var(--good); border-color: var(--good); }
.up-failed .up-outcome { color: var(--ink-muted); }
.up-dropped .up-outcome { color: var(--bad); border-color: var(--bad); }
.up-protected .up-outcome { color: var(--warn); border-color: var(--warn); }
.up-rerolled .up-outcome { color: var(--ink-accent, #5aa0d8); }
/* Level 0 is not part of the client's ramp: in game an unupgraded item simply has no badge, so the palette
   starts at +1. On a page the badge still has to be drawn, and without its own rule it fell through to the
   generic chip - near-black text on a dark grey ground, which is unreadable. It gets a deliberately quiet
   treatment instead: this is the "not upgraded yet" end of every first attempt. */
.lv-0 { background: var(--surface-high); color: var(--ink-muted); border: 1px solid var(--line); }

/* The item library. The pictures are the client's own sprites, so they keep their hard pixel edges, and the
   numeric columns line up under one another for comparing two weapons at a glance. */
.lib td.num { text-align: right; font-variant-numeric: tabular-nums; }
.lib-pic { width: 44px; }
.lib-pic img { display: block; image-rendering: pixelated; }
.lib-desc { font-size: 0.85em; }
.lib td { vertical-align: top; }
.field-check { align-self: center; }
.field-check label { display: flex; align-items: center; gap: 6px; font-weight: normal; }
.filters select {
  min-height: var(--control); padding: 0 12px;
  background: var(--ground); color: var(--ink); border: 1px solid var(--line); border-radius: 6px; font: inherit;
}
.filters select:hover { border-color: var(--ink-faint); }
.filters select:focus { border-color: var(--accent-hover); outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }

/* The outfit previewer. The swatch colours themselves live in the generated palette.css, because the
   Content-Security-Policy allows no inline styles. */
.try { display: grid; gap: var(--block); grid-template-columns: minmax(220px, 300px) 1fr; align-items: start; margin-bottom: var(--block); }
@media (max-width: 720px) { .try { grid-template-columns: 1fr; } }
.try-stage { text-align: center; }
.try-figure {
  min-height: 160px; display: grid; place-items: center;
  background: var(--ground); border: 1px solid var(--line); margin-bottom: var(--gap);
}
.try-figure img { image-rendering: pixelated; transform: scale(2); transform-origin: center; }
.try-name { font-weight: 650; margin: 0 0 var(--gap); }
.try-addons { display: flex; gap: var(--gap); justify-content: center; margin: 0; }
.try-sex { display: flex; gap: var(--tight); }
.swatch-title { margin: var(--block) 0 var(--tight); font-size: 0.85rem; color: var(--ink-muted); text-transform: uppercase; letter-spacing: 0.08em; }
.swatches { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 3px; }
.swatch {
  display: block; width: 20px; height: 20px; border-radius: 3px;
  border: 1px solid rgba(0, 0, 0, 0.45);
}
.swatch:hover { outline: 2px solid var(--ink); outline-offset: 1px; }
.swatch-on { outline: 2px solid var(--accent-hover); outline-offset: 1px; }
.wardrobe { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--gap); grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
.wardrobe-item { position: relative; text-align: center; }
.wardrobe-item a { display: block; padding: var(--gap) 4px; border: 1px solid var(--line); background: var(--ground); color: var(--ink); text-decoration: none; }
.wardrobe-item a:hover { border-color: var(--ink-faint); background: var(--surface-high); }
.wardrobe-on a { border-color: var(--accent-hover); }
.wardrobe-pic { display: grid; place-items: center; height: 64px; }
.wardrobe-pic img { image-rendering: pixelated; }
.wardrobe-name { display: block; font-size: 0.8rem; margin-top: 4px; overflow-wrap: anywhere; }
.wardrobe-item .badge { position: absolute; top: 2px; right: 2px; font-size: 0.66rem; }

/* The page shell. Without a rail it stays exactly what it was: one centred column. With one, the page and the
   rail become two columns in a slightly wider container, and below 1000px the rail simply drops under the page,
   so a phone reads the content first and the changelog after it. */
.shell { flex: 1; width: 100%; }
.shell-rail {
  max-width: 1420px; margin: 0 auto;
  display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--gutter);
  align-items: start; padding-right: var(--block);
}
.shell-rail > .page { max-width: none; margin: 0; padding-right: 0; }
.rail { padding: var(--gutter) 0 48px; position: sticky; top: var(--block); }
.rail-card { padding: var(--block); }
.rail-card h2 { font-size: 1rem; margin-bottom: var(--gap); }
.rail-build { margin: 0 0 var(--block); font-size: 0.85rem; }
.rail-entry { border-top: 1px solid var(--line); padding-top: var(--gap); margin-bottom: var(--gap); }
.rail-entry:first-of-type { border-top: 0; padding-top: 0; }
.rail-entry h3 { font-size: 0.86rem; margin: 0 0 4px; line-height: 1.35; }
.rail-entry ul { margin: 0; padding-left: 18px; font-size: 0.82rem; color: var(--ink-muted); }
.rail-entry li { margin-bottom: 2px; }
.rail-more { margin: var(--gap) 0 0; font-size: 0.85rem; }

@media (max-width: 1000px) {
  .shell-rail { display: block; max-width: 1100px; padding-right: 0; }
  .rail { position: static; padding: 0 var(--block) var(--gutter); }
}

/* The main menu, grouped (2026-09-19). Thirteen links in one row scrolled sideways even at 1100px, so five of the
   six top-level items are <details> groups. Two things below are load-bearing rather than decorative:
     * the row must NOT be a scroll container any more - `overflow-x: auto` on .sections-inner would clip the
       dropdown panel, which is absolutely positioned;
     * the panel opens on click, not hover, so it works the same with a finger, a mouse and a keyboard. */
.sections-inner { overflow: visible; flex-wrap: wrap; gap: 2px; align-items: stretch; }
.sections .section-link, .sections summary {
  flex: none; display: flex; align-items: center; gap: 6px;
  min-height: var(--control); padding: 0 14px;
  color: var(--ink-muted); text-decoration: none; white-space: nowrap; cursor: pointer;
  border-bottom: 2px solid transparent; border-radius: 6px 6px 0 0;
}
.sections .section-link:hover, .sections summary:hover { color: var(--ink); background: var(--surface); }
.sections .section-link[aria-current="page"] { color: var(--ink); background: var(--surface); border-bottom-color: var(--accent-hover); }
.sections .group-here > summary { color: var(--ink); border-bottom-color: var(--accent-hover); }

.group { position: relative; }
.group > summary { list-style: none; }
.group > summary::-webkit-details-marker { display: none; }
.group-arrow { width: 0; height: 0; border: 4px solid transparent; border-top-color: currentColor; margin-top: 2px; }
.group[open] > summary { background: var(--surface-high); color: var(--ink); }
.group[open] .group-arrow { transform: rotate(180deg); margin-top: -2px; }

.group-menu {
  position: absolute; z-index: 20; top: 100%; left: 0; min-width: 190px;
  display: flex; flex-direction: column; padding: 6px;
  background: var(--surface-high); border: 1px solid var(--line); border-radius: 0 6px 6px 6px;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.45);
}
.group-menu a {
  padding: 9px 12px; border-radius: 4px;
  color: var(--ink-muted); text-decoration: none; white-space: nowrap;
}
.group-menu a:hover { background: var(--surface); color: var(--ink); }
.group-menu a[aria-current="page"] { color: var(--ink); background: var(--accent-soft); }

@media (max-width: 700px) {
  /* On a phone the panel stops floating and simply opens in place, so nothing is hidden off-screen. */
  .group-menu { position: static; box-shadow: none; border-radius: 6px; margin: 2px 0 6px; }
  .sections-inner { padding: 0 12px 4px; }
}
@media (prefers-reduced-motion: reduce) { .group-arrow { transition: none; } }
