/* SOMWORLD site stylesheet — clean neutral, light/dark via design tokens.
 *
 * Theme resolution, in priority order:
 *   1. <html data-theme="light|dark">  — the ACCOUNT setting, server-rendered
 *      for a signed-in member who has chosen (follows them across devices).
 *   2. prefers-color-scheme            — the device default, for anonymous
 *      visitors and members who never touched the toggle.
 * The dark token block therefore appears twice: once under the media query
 * (guarded so an explicit light choice beats a dark device), once under the
 * explicit attribute. Same values, two doors.
 */

:root {
  --bg: #fafafa;
  --surface: #ffffff;
  --text: #1a1d21;
  --muted: #5c6570;
  --border: #d9dde2;
  --accent: #3b5b7c;          /* restrained slate-blue: links, focus, buttons */
  --accent-contrast: #ffffff;
  --nav-bg: #ffffff;
  --shadow: 0 1px 3px rgba(0, 0, 0, 0.07);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #15181c;
    --surface: #1d2126;
    --text: #e4e7ea;
    --muted: #9aa4ae;
    --border: #343a41;
    --accent: #7da7cd;
    --accent-contrast: #12151a;
    --nav-bg: #1a1e23;
    --shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  }
}
:root[data-theme="dark"] {
  --bg: #15181c;
  --surface: #1d2126;
  --text: #e4e7ea;
  --muted: #9aa4ae;
  --border: #343a41;
  --accent: #7da7cd;
  --accent-contrast: #12151a;
  --nav-bg: #1a1e23;
  --shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

/* ---- base ---------------------------------------------------------------- */

* { box-sizing: border-box; }

html { color-scheme: light dark; }
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  line-height: 1.55;
}

main {
  max-width: 52rem;
  margin: 0 auto;
  padding: 1.25rem 1rem 4rem;
}
/* Article pages that carry a stat grid get the screen (beta feedback 2026-08-13:
 * "on a large screen there is a lot of wasted space"). Prose is NOT widened with
 * it — a 1150px line length is unreadable — so everything in the body except the
 * table keeps the reading measure. Raising a max-width changes nothing below an
 * 832px viewport, so every phone renders exactly as before. */
main.wide { max-width: 72rem; }
main.wide article > :not(table) { max-width: 46rem; }

a { color: var(--accent); }
a:hover { text-decoration-thickness: 2px; }

h1, h2, h3 { line-height: 1.25; }
h1 { font-size: 1.6rem; }
h2 { font-size: 1.25rem; margin-top: 1.75em; }

hr { border: 0; border-top: 1px solid var(--border); }

small, .muted { color: var(--muted); }

/* ---- nav bar ------------------------------------------------------------- */
/* The <nav> tag itself stays attribute-free: tests_navigation's crawler
 * splits the page on the literal "<nav>". Style the element, not a class. */

nav {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--nav-bg);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  padding: 0.55rem 1rem;
}

nav .brand {
  font-weight: 700;
  letter-spacing: 0.04em;
  text-decoration: none;
  color: var(--text);
  font-size: 1.05rem;
  margin-right: 0.5rem;
}

nav a { text-decoration: none; color: var(--text); padding: 0.25rem 0.1rem; }
nav a:hover { color: var(--accent); }

nav .nav-user {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--muted);
  font-size: 0.9rem;
}

nav form { display: inline; margin: 0; }

/* Hamburger: CSS-only. The checkbox lives right inside <nav>; the label is
 * hidden on wide screens and the menu collapses under it on small ones. */
#nav-toggle { display: none; }
nav .nav-burger {
  display: none;
  margin-left: auto;
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.15rem 0.4rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  user-select: none;
}

@media (max-width: 640px) {
  nav .nav-burger { display: block; }
  nav .nav-links, nav .nav-user {
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.35rem;
    margin-left: 0;
    padding-top: 0.5rem;
  }
  #nav-toggle:checked ~ .nav-links,
  #nav-toggle:checked ~ .nav-user { display: flex; }
}
@media (min-width: 641px) {
  nav .nav-links { display: flex; gap: 1rem; align-items: center; }
}

/* ---- buttons & forms ----------------------------------------------------- */

button, input[type="submit"] {
  font: inherit;
  background: var(--accent);
  color: var(--accent-contrast);
  border: 0;
  border-radius: 6px;
  padding: 0.45rem 0.9rem;
  cursor: pointer;
}
button:hover, input[type="submit"]:hover { filter: brightness(1.08); }

/* Quiet buttons: logout + theme toggle in the nav shouldn't shout. */
nav button {
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  padding: 0.25rem 0.6rem;
  font-size: 0.85rem;
}
nav button:hover { color: var(--accent); border-color: var(--accent); filter: none; }

input[type="text"], input[type="email"], input[type="password"], input[type="search"],
select, textarea {
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.45rem 0.6rem;
  max-width: 100%;
}
input:focus, select:focus, textarea:focus, button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

form p { margin: 0.7rem 0; }
form label { display: block; margin-bottom: 0.2rem; color: var(--muted); font-size: 0.92rem; }
.helptext { display: block; color: var(--muted); font-size: 0.85rem; }
ul.errorlist { color: #b3392f; padding-left: 1rem; margin: 0.25rem 0; }
:root[data-theme="dark"] ul.errorlist { color: #e08a82; }

/* The beta site's standing banner. Same treatment as a flash message on purpose — the
 * reader already knows that shape means "the site is telling you something" — but a
 * different element, because messages drain when iterated and must render exactly once.
 * Every value here is a theme token, so it follows dark mode with no second rule and
 * stays clear of somworld/tests.py's "this fragment appears exactly twice" assertions. */
.site-banner p {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: 6px;
  padding: 0.6rem 0.9rem;
  margin: 0.5rem 0;
  color: var(--muted);
  font-size: 0.9rem;
}

ul.messages { list-style: none; padding: 0; }
ul.messages li {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: 6px;
  padding: 0.6rem 0.9rem;
  margin: 0.5rem 0;
}

/* ---- tables (the stat grids) --------------------------------------------- */
/* display:block + overflow-x lets a 15-column platoon grid scroll INSIDE the
 * page on a phone instead of blowing the layout out sideways. */

table {
  border-collapse: collapse;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  display: block;
  max-width: 100%;
  overflow-x: auto;
  margin: 1rem 0;
}
th, td {
  border: 1px solid var(--border);
  padding: 0.2rem 0.5rem;
  text-align: left;
  white-space: nowrap;
}
th { background: var(--surface); }

/* nowrap is right for a dense grid and wrong for a draft guide. A table with
 * FEWER THAN 8 columns is never one of the dense numeric grids (6,856 of the
 * corpus's 7,880 tables have >=8), and 79 of the 81 tables carrying a prose
 * column sit in that narrow set — so let every cell wrap there. Numbers hold no
 * spaces and cannot break; what stops breaking the layout is the comments column,
 * which today forces the whole table into a horizontal scroll and drags the
 * player name off-screen with it (beta feedback 2026-08-13). The dense grids keep
 * nowrap and keep scrolling, which is what makes THEM readable.
 * :has() is baseline-2023; where it is unsupported the rule drops whole and the
 * behaviour is exactly what it was. */
table:not(:has(tr > :nth-child(8))) :is(th, td) { white-space: normal; }

/* Legacy stat cells carry their own inline light background colors
 * (background:#CCFFCC and friends). In dark mode those cells KEEP their light
 * fill, so their text must stay dark — target exactly the cells that declare
 * a background of their own. */
:root[data-theme="dark"] td[style*="background"],
:root[data-theme="dark"] th[style*="background"] { color: #1a1d21; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) td[style*="background"],
  :root:not([data-theme="light"]) th[style*="background"] { color: #1a1d21; }
}

/* The mirror case (beta feedback 2026-08-12): cells with an inline COLOR but
 * no background — color:black / dark navies from spreadsheet exports, 888
 * articles' worth — sit on the page's dark ground and vanish. They must
 * inherit the theme text color instead. Unlike the rule above, an inline
 * color EXISTS here and has to lose, hence !important. Cells that declare
 * their own background remain self-contained worlds and are excluded.
 * Inline red is semantic (negative stats) — remap it readable, don't flatten;
 * the extra attribute selector outranks the blanket rule. */
:root[data-theme="dark"] td:not([style*="background"]),
:root[data-theme="dark"] th:not([style*="background"]) { color: inherit !important; }
:root[data-theme="dark"] td[style*="color:red"]:not([style*="background"]),
:root[data-theme="dark"] th[style*="color:red"]:not([style*="background"]) { color: #e57373 !important; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) td:not([style*="background"]),
  :root:not([data-theme="light"]) th:not([style*="background"]) { color: inherit !important; }
  :root:not([data-theme="light"]) td[style*="color:red"]:not([style*="background"]),
  :root:not([data-theme="light"]) th[style*="color:red"]:not([style*="background"]) { color: #e57373 !important; }
}

/* ---- article body -------------------------------------------------------- */

article h1 { margin-top: 0.25rem; }
article p { max-width: 46rem; }

/* Restored legacy images (2026-08-19). The source markup carries intrinsic pixel
 * sizes — 549x227 card scans, 1115x458 tool screenshots, 120x120 headshots — and
 * the width/height attributes are kept so the browser reserves the space rather
 * than reflowing the article as each one loads. These two rules make that size a
 * CEILING rather than a fixed size, which is what stops a 1115px screenshot from
 * forcing a horizontal scrollbar on a phone.
 *
 * `height: auto` is load-bearing next to `max-width`: without it a shrunken
 * image keeps its attribute height and stretches. */
article img {
  max-width: 100%;
  height: auto;
}
/* An image alone in its paragraph is a figure, not a run of text — 83% of them
 * are, and `article p` above would otherwise cap them at the 46rem prose measure
 * even on a wide table page. Images inside table cells are left alone: they are
 * sized by the grid around them. */
article p > img:only-child {
  display: block;
  margin: 0.4rem 0;
}
/* Dark mode: card scans and screenshots are photographic and mostly light-ground,
 * so they sit on a dark page as bright rectangles. A hairline border gives them
 * an edge instead of letting them bleed into the background. Declared under BOTH
 * theme doors — DarkModeCellRuleTests requires every dark rule to exist under
 * data-theme AND prefers-color-scheme, and has caught that drift before. */
:root[data-theme="dark"] article img { border: 1px solid var(--border); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) article img { border: 1px solid var(--border); }
}

/* ---- league management --------------------------------------------------- */
/* The commissioner's team list. It used to be four `display:inline` forms per
 * team, which wrapped into one ragged flow — a button landing between two
 * unrelated inputs, wrap points shifting with the length of the team name. A
 * tester's screenshot of it came with "I had a hard time trying to figure out
 * which field to set" (2026-08-13). Each action is now its own block, and
 * .team-field keeps an input welded to the button that consumes it. */

.teams { list-style: none; padding-left: 0; }
.team {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.6rem 0.9rem;
  margin: 0.8rem 0;
}
.team-name { margin: 0 0 0.4rem; }
.team-managers { list-style: none; padding-left: 0; margin: 0 0 0.6rem; }
.team-managers li {
  display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin: 0.25rem 0;
}
.team-managers button {
  background: transparent; color: var(--muted); border: 1px solid var(--border);
  padding: 0.15rem 0.5rem; font-size: 0.8rem;
}
.team-extra { color: var(--muted); font-size: 0.9rem; }
.team-action { margin: 0.7rem 0; }
.team-field { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.team-rename summary { color: var(--muted); cursor: pointer; font-size: 0.9rem; }
.grant-extra {
  border: 1px solid var(--accent); border-radius: 6px; padding: 0.9rem 1.1rem;
  margin: 1rem 0;
}

/* ---- copy-table ---------------------------------------------------------- */
/* The button and the note are both INJECTED by copytable.js — the site's only
 * JavaScript. With scripts off neither element exists, so there is nothing here
 * to hide and the tables render exactly as they did before. */

.copy-table {
  display: block;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  padding: 0.2rem 0.55rem;
  font-size: 0.8rem;
  margin: 1rem 0 -0.5rem;
}
.copy-table:hover { color: var(--accent); border-color: var(--accent); filter: none; }

/* The note is only TRUE in dark mode, so CSS decides it, not JS: a theme read in
 * JavaScript would have to reproduce BOTH doors (the account stamp and the device
 * preference) and would flash on load. Same two-context hand-sync as the cell
 * rules above — DarkModeCellRuleTests counts this fragment in both places. */
.copy-note { font-size: 0.85rem; color: var(--muted); max-width: 46rem; display: none; }
:root[data-theme="dark"] .copy-note { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .copy-note { display: block; }
}
