:root {
    --bg: #14100c;
    --panel: #241d16;
    --panel-alt: #2e251c;
    --panel-dark: #1c1711;
    --border: #4a3b2a;
    --text: #e6ddcc;
    --text-soft: #cabca5;
    --muted: #a6957c;
    --faint: #6f6152;
    --accent: #c8a250;
    --accent-light: #e0bd6e;
    --accent-dark: #9c7a33;
    --danger: #b4453c;
    --success: #4f8a4a;
    --pixel: "Press Start 2P", ui-monospace, monospace;
    --display: "Cinzel", Georgia, serif;
    --mono: ui-monospace, SFMono-Regular, Menlo, monospace;

    /* The parts of a form control the page cannot reach — the up and down
       arrows on a number box, a dropdown's list, the scrollbars — are drawn by
       the browser, and it draws them for a light page unless told otherwise.
       On a page this dark they arrive as a white slab in the middle of a field
       that is otherwise ours. */
    color-scheme: dark;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: "Segoe UI", Tahoma, Verdana, sans-serif;
    font-size: 15px;
    line-height: 1.6;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-light); text-decoration: underline; }
::selection { background: var(--accent-dark); color: #1a1410; }

.container {
    width: 100%;
    max-width: 1120px;
    margin: 0 auto;
    padding: 0 16px;
}

/* Header ---------------------------------------------------------------- */

.site-header { background: var(--panel); border-bottom: 2px solid var(--border); }

.header-inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding-top: 16px;
    padding-bottom: 16px;
}

.brand { display: flex; align-items: center; gap: 14px; }
.brand:hover { text-decoration: none; }

/* The logo is pixel art, so it is scaled with hard edges rather than blurred. */
.brand-mark {
    width: 52px; height: 52px;
    display: block;
    object-fit: contain;
    image-rendering: pixelated;
}

.brand-name { display: block; font-family: var(--pixel); font-size: 15px; color: var(--accent); letter-spacing: 0.5px; }
.brand-sub { display: block; margin-top: 4px; font-size: 11px; color: var(--muted); letter-spacing: 1.6px; text-transform: uppercase; }

.header-account { display: flex; align-items: center; gap: 12px; }
.header-account .who { text-align: right; line-height: 1.3; }
.header-account .who strong { display: block; }
.header-account .who span { font-size: 12px; color: var(--muted); }

.inline-form { display: inline; margin: 0; }

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

/* Main navigation ------------------------------------------------------- */

.main-nav { border-top: 1px solid var(--border); background: var(--panel-dark); }
.main-nav .container { display: flex; flex-wrap: wrap; gap: 2px; }

.main-nav a {
    padding: 13px 16px;
    border-bottom: 3px solid transparent;
    color: var(--muted);
    font-family: var(--pixel);
    font-size: 10px;
    letter-spacing: 0.5px;
    text-transform: uppercase;
}
.main-nav a:hover { color: var(--accent-light); text-decoration: none; }
.main-nav a.is-active { background: var(--panel); border-bottom-color: var(--accent); color: var(--accent); }

/* Page frame ------------------------------------------------------------ */

.site-main {
    display: flex;
    flex-wrap: wrap;
    gap: 24px;
    align-items: flex-start;
    padding-top: 24px;
    padding-bottom: 56px;
}

.content-column { flex: 5 1 560px; min-width: 0; display: flex; flex-direction: column; gap: 24px; }
.sidebar { flex: 1 1 280px; max-width: 300px; min-width: 0; display: flex; flex-direction: column; gap: 20px; }

/* Panels ---------------------------------------------------------------- */

.panel {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 24px;
    margin: 0;
}

.panel-flush { padding: 0; overflow-x: auto; }
.panel h1 { margin: 0 0 10px; font-family: var(--display); font-size: 26px; color: var(--accent); }
.panel h2 { margin: 0 0 14px; font-family: var(--display); font-size: 20px; color: var(--accent); }
.panel h1 + .lead { margin-top: -4px; }
.lead { margin: 0 0 20px; color: var(--muted); }

.panel-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 12px; }

.hero { padding: 0; overflow: hidden; }
.hero-art {
    height: 220px;
    border-bottom: 1px solid var(--border);
    background: repeating-linear-gradient(135deg, var(--panel-alt) 0 12px, var(--panel) 12px 24px);
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
}
.hero-art .slot-label { font-family: var(--pixel); font-size: 10px; color: var(--muted); }
.hero-art .slot-note { font-family: var(--mono); font-size: 12px; color: var(--faint); }
.hero-body { padding: 28px 28px 32px; }
.hero-body h1 { font-size: 34px; line-height: 1.15; letter-spacing: 0.5px; }
.hero-body p { margin: 0 0 22px; max-width: 62ch; color: var(--text-soft); text-wrap: pretty; }

.actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.form-panel { max-width: 460px; }
.muted { color: var(--muted); font-size: 14px; }

/* Sprite placeholders --------------------------------------------------- */

.sprite {
    border: 1px solid var(--border);
    background: repeating-linear-gradient(45deg, var(--panel-alt) 0 4px, var(--panel-dark) 4px 8px);
}
.sprite-lg {
    aspect-ratio: 1;
    background: repeating-linear-gradient(135deg, var(--panel-alt) 0 8px, var(--panel-dark) 8px 16px);
    display: flex; align-items: center; justify-content: center; text-align: center;
}
.sprite-lg span { font-family: var(--mono); font-size: 11px; color: var(--faint); padding: 8px; }
.sprite-44 { width: 44px; height: 44px; }
.sprite-52 { width: 52px; height: 52px; }
.sprite-96 { width: 96px; height: 96px; }

/* Buttons --------------------------------------------------------------- */

.button {
    display: inline-block;
    padding: 9px 18px;
    background: var(--accent-dark);
    border: 1px solid var(--accent);
    border-radius: 4px;
    color: #1a1410;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
}
.button:hover { background: var(--accent); color: #1a1410; text-decoration: none; }

.button-lg { padding: 11px 22px; }
.button-sm { padding: 6px 12px; font-size: 13px; }
.button-block { display: block; width: 100%; text-align: center; }

.button-secondary { background: var(--panel-alt); border-color: var(--border); color: var(--text); }
.button-secondary:hover { background: var(--border); color: var(--text); }

/* Irreversible actions, so the button does not look like the ordinary one. */
.button-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.button-danger:hover { background: #c95347; border-color: #c95347; color: #fff; }

/* A button that is a picture instead of a word, for a row where the words would
   take more room than the thing they sit beside. The picture carries no meaning
   of its own — the button's `aria-label` and `title` say what it does, for a
   screen reader and for anyone who hovers and wonders. */
.button-icon { display: inline-flex; align-items: center; justify-content: center; padding: 6px 10px; }
.button-icon img { display: block; width: 16px; height: 16px; }

/* The quiet way into one, sitting among ordinary character actions. */
.link-danger { color: var(--muted); font-size: 13px; }
.link-danger:hover { color: var(--danger); }

/* Forms ----------------------------------------------------------------- */

.field { margin-bottom: 18px; }
.field label { display: block; margin-bottom: 6px; font-weight: 600; }

/* The dropdown belongs here as much as the text boxes do: a `.field` holding a
   picker and a number box side by side — giving gold to a guild, bidding on a
   house — had the box in the site's colours and the picker in the browser's. */
.field input,
.field select,
.filter-bar input,
.filter-bar select {
    width: 100%;
    padding: 9px 10px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text);
    font: inherit;
}

.field input:focus,
.field select:focus,
.filter-bar input:focus,
.filter-bar select:focus { outline: none; border-color: var(--accent); }

.field small { display: block; margin-top: 5px; color: var(--muted); font-size: 13px; }
.field-error { margin: 6px 0 0; color: #e08a82; font-size: 13px; }
.form-footer { margin-bottom: 0; color: var(--muted); font-size: 14px; }

/* Radio groups (character gender) */
.field-label { display: block; margin-bottom: 8px; font-weight: 600; }
.radio-row { display: flex; flex-wrap: wrap; gap: 10px; }

.radio {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 0;
    padding: 9px 16px 9px 12px;
    background: var(--panel-dark);
    border: 1px solid var(--border);
    border-radius: 4px;
    font-weight: normal;
    cursor: pointer;
}
.radio:hover { border-color: var(--accent-dark); }
.radio:has(input:checked) { border-color: var(--accent); color: var(--accent-light); }
.radio input { width: auto; accent-color: var(--accent); }

/* Where a new character starts. Each block is one place, and the radios inside
   it are the vocations that place allows — picking one picks the whole set of
   starting conditions, which is why they are not two separate fields. */
.start-place {
    padding: 14px 16px;
    background: var(--panel-dark);
    border: 1px solid var(--border);
    border-radius: 4px;
    margin-bottom: 10px;
}
.start-place:last-of-type { margin-bottom: 0; }
.start-place:has(input:checked) { border-color: var(--accent-dark); }

.start-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px; }
.start-name { font-family: var(--display); font-size: 17px; color: var(--accent); }
.start-facts { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.start-note { margin: 4px 0 10px; }
.start-head + .radio-row { margin-top: 10px; }

.filter-bar { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.filter-bar label { display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--muted); }
.filter-bar select { min-width: 150px; font-size: 14px; }
.filter-bar .grow { flex: 1 1 260px; }

.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.chip {
    padding: 7px 14px;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: 3px;
    color: var(--muted);
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 1px;
    text-transform: uppercase;
    cursor: pointer;
}
.chip:hover { color: var(--accent-light); text-decoration: none; }
.chip.is-active { background: var(--accent-dark); border-color: var(--accent); color: #1a1410; }

/* Skill picker ---------------------------------------------------------- */

/* The highscore lists, picked by their pixel icon instead of by name. The
   name is in the tooltip and in the aria-label, and the heading above the
   table always spells out which list is being shown, so nothing is lost on a
   touch screen that never hovers. */

.skill-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 16px;
    padding: 14px;
    background: var(--panel-dark);
    border: 1px solid var(--border);
    border-radius: 3px;
}

.skill-tile {
    position: relative;
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: 3px;
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, .35);
    transition: background .12s, border-color .12s;
}
.skill-tile:hover,
.skill-tile:focus-visible {
    background: #3a2f22;
    border-color: var(--accent-dark);
    text-decoration: none;
}
.skill-tile.is-active {
    background: #3f321f;
    border-color: var(--accent);
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, .35), 0 0 0 1px var(--accent);
}

/* Unselected lists sit back a little so the current one reads at a glance. */
.skill-icon {
    width: 32px;
    height: 32px;
    display: block;
    image-rendering: pixelated;
    opacity: .62;
    transition: opacity .12s;
}
.skill-tile:hover .skill-icon,
.skill-tile:focus-visible .skill-icon,
.skill-tile.is-active .skill-icon { opacity: 1; }

.skill-tip {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    padding: 6px 9px;
    background: #0d0b08;
    border: 1px solid var(--accent);
    border-radius: 3px;
    color: var(--text);
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 1px;
    text-transform: uppercase;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity .12s;
    z-index: 2;
}
.skill-tile:hover .skill-tip,
.skill-tile:focus-visible .skill-tip { opacity: 1; }

/* Alerts ---------------------------------------------------------------- */

.alert {
    margin: 0 0 20px;
    padding: 12px 16px;
    border: 1px solid var(--border);
    border-left-width: 4px;
    border-radius: 4px;
    background: var(--panel-alt);
}
.alert-success { border-left-color: var(--success); }
.alert-error   { border-left-color: var(--danger); }
.alert-info    { border-left-color: var(--accent); }

/* Key/value tables ------------------------------------------------------ */

.data-table { width: 100%; border-collapse: collapse; margin-bottom: 6px; }
.data-table th,
.data-table td { padding: 9px 12px; border-bottom: 1px solid var(--border); text-align: left; }
.data-table th { width: 35%; color: var(--muted); font-weight: 600; }
.data-table tr:last-child th,
.data-table tr:last-child td { border-bottom: 0; }

/* Stat grid ------------------------------------------------------------- */

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 1px;
    background: var(--border);
    border: 1px solid var(--border);
}
.stat-grid > div { background: var(--panel); padding: 13px 15px; }
.stat-label { font-family: var(--mono); font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.stat-value { font-size: 17px; font-weight: 600; color: var(--text); }

/* A world row with the game's own sprite: picture on the left, label and value
   stacked to the right of it. `flex: none` keeps the sprite its own size when
   the box is narrow — a squashed 32px sprite is a smudge.

   No `pixelated` here on purpose. The sprites that are already 32px are drawn
   at their own size and so are untouched by it either way, while the two that
   are not — a 38px tile and a 192px drawing — are being scaled down, and
   nearest-neighbour drops rows unevenly on a fraction like 38→32. `contain`
   keeps whatever shape they came in. */
.stat-iconed { display: flex; align-items: center; gap: 12px; }
.stat-icon { flex: none; width: 32px; height: 32px; object-fit: contain; }

/* Listing grids --------------------------------------------------------- */

.listing { display: block; }
.listing-head,
.listing-row { display: grid; gap: 12px; padding: 12px 20px; align-items: center; }
.listing-head {
    background: var(--panel-dark);
    border-bottom: 1px solid var(--border);
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--muted);
    white-space: nowrap;
}
.listing-row { border-bottom: 1px solid var(--border); font-size: 14px; }
.listing-row:hover { background: var(--panel-alt); }
.listing-row:last-child { border-bottom: 0; }

/* A whole row that is a link — the houses list. It keeps the row's own
   colours: the underline and link blue belong on words, not on a table. */
a.listing-row { color: inherit; text-decoration: none; }
a.listing-row:hover .cell-name { text-decoration: underline; }

/* Previous / next under a long listing. */
/* Page links. Numbers rather than only Previous and Next, because twenty pages
   of houses is twenty clicks to the end otherwise. Sized so a number is a
   comfortable target on a touchscreen without the row growing tall. */
.pager { display: flex; align-items: center; justify-content: space-between; gap: 12px 16px; flex-wrap: wrap; padding: 14px 20px; }
.pager-pages { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }

.pager-page,
.pager-step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    height: 34px;
    padding: 0 9px;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--panel-dark);
    color: var(--text-soft);
    font-family: var(--mono);
    font-size: 13px;
    text-decoration: none;
}

a.pager-page:hover,
a.pager-step:hover { border-color: var(--accent); color: var(--accent-light); background: var(--panel-alt); text-decoration: none; }

/* Where you are. Filled rather than outlined, so it reads at a glance as the
   one that is not a link. */
.pager-page.is-current {
    background: var(--accent-dark);
    border-color: var(--accent);
    color: #1a1410;
    font-weight: 700;
}

/* Previous at page one, Next at the last. Kept in place rather than removed:
   a row that changes width moves the numbers out from under the pointer. */
.pager-step.is-off { color: var(--faint); border-color: var(--panel-alt); background: transparent; }

.pager-gap { color: var(--faint); padding: 0 2px; font-family: var(--mono); }
.pager-count { color: var(--muted); font-size: 13px; margin-left: auto; }

/* On a phone the row is the width of the screen, and the full run wraps onto
   four lines. Dropping the outermost neighbours keeps it to two without
   costing any page you cannot still reach in one more tap. */
@media (max-width: 560px) {
    .pager { padding: 12px 14px; gap: 10px; }
    .pager-page.is-far { display: none; }
    .pager-step-label { display: none; }
    .pager-count { margin-left: 0; }
}
.cell-clip { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cell-num { font-family: var(--mono); }
.cell-name { font-weight: 600; color: var(--accent); }

.listing-guilds .listing-head,
.listing-guilds .listing-row { grid-template-columns: 52px minmax(150px, 2fr) minmax(110px, 1.4fr) 80px 100px; gap: 14px; min-width: 0; padding-top: 14px; padding-bottom: 14px; }
/* The columns are sized to fit the content column beside the sidebar, which is
   about 760px on a 1280px screen. They used to ask for 780px, which bought a
   horizontal scrollbar on an ordinary desktop for the sake of eighteen pixels.
   Below the min-width the row still scrolls, which is the right answer on a
   phone and the same bargain the highscores table makes. */
.listing-houses .listing-head,
.listing-houses .listing-row { grid-template-columns: minmax(150px, 1.9fr) minmax(84px, 0.9fr) 74px 52px minmax(96px, 1fr) minmax(120px, 1.1fr); gap: 10px; min-width: 660px; }
.listing-scores .listing-head,
.listing-scores .listing-row { grid-template-columns: 50px minmax(160px, 1.6fr) minmax(130px, 1.2fr) minmax(80px, 1fr) 80px; min-width: 620px; white-space: nowrap; }
.listing-members .listing-head,
.listing-members .listing-row { grid-template-columns: minmax(90px, 1fr) minmax(140px, 1.8fr) minmax(100px, 1.2fr) 60px 76px; min-width: 0; white-space: nowrap; }

/* The same list seen by its leader, with the rank picker on the end.

   No min-width on either. The guild page keeps its members inside a column
   narrower than the window, and a table told to be 940px wide in a 762px column
   hands the leader a sideways scrollbar on a full-sized screen — which is what
   these numbers used to do. The columns are free to shrink to their content
   instead, and below 900px the rows stop being a table altogether. */
.listing-members-manage .listing-head,
.listing-members-manage .listing-row { grid-template-columns: minmax(80px, 0.9fr) minmax(130px, 1.5fr) minmax(90px, 1fr) 52px 70px minmax(128px, 200px); min-width: 0; }

/* The rank picker and the Remove button share the last column. */
.member-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

.rank-form { display: flex; gap: 8px; align-items: center; margin: 0; }

.rank-form select {
    flex: 1 1 auto;
    min-width: 0;
    padding: 6px 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text);
    font: inherit;
    font-size: 13px;
}
.rank-form select:focus { outline: none; border-color: var(--accent); }

/* The leader's own row: no picker, so the column says why. */
.rank-fixed { color: var(--muted); font-size: 13px; }

/* Below this the members list stops pretending to be a table: five or six
   columns cannot be fitted across a phone, and the alternative — the sideways
   scrollbar this used to have — hides half of every member behind a gesture
   nobody thinks to make. Each member becomes a block, and the column headings
   move onto the cells themselves, which is what the data-labels are for. */
@media (max-width: 900px) {
    .listing-members .listing-head,
    .listing-guilds .listing-head { display: none; }

    /* The guilds list keeps its logo beside the name and stacks the rest. */
    .listing-guilds .listing-row {
        grid-template-columns: 52px minmax(0, 1fr);
        gap: 4px 14px;
        white-space: normal;
    }
    .listing-guilds .listing-row > :first-child { grid-row: span 4; align-self: start; }
    .listing-guilds .listing-row > [data-label] { display: flex; gap: 8px; align-items: baseline; }
    .listing-guilds .listing-row > [data-label]::before {
        content: attr(data-label);
        flex: none;
        width: 66px;
        font-family: var(--mono);
        font-size: 10px;
        letter-spacing: 1px;
        text-transform: uppercase;
        color: var(--muted);
    }

    .listing-members .listing-row,
    .listing-members-manage .listing-row {
        grid-template-columns: minmax(0, 1fr);
        gap: 4px;
        padding: 14px 16px;
        white-space: normal;
    }

    /* The name leads, at reading size; everything else is a labelled line. */
    .listing-members .listing-row > [data-label] { display: flex; gap: 8px; align-items: baseline; }
    .listing-members .listing-row > [data-label]::before {
        content: attr(data-label);
        flex: none;
        width: 74px;
        font-family: var(--mono);
        font-size: 10px;
        letter-spacing: 1px;
        text-transform: uppercase;
        color: var(--muted);
    }
    .listing-members .listing-row > [data-label="Character"] { order: -1; font-size: 16px; }
    .listing-members .listing-row > [data-label="Character"]::before { display: none; }

    /* The picker and the buttons get the full width rather than a stub of it. */
    .listing-members .member-actions,
    .listing-members .rank-fixed { margin-top: 6px; }
    .listing-members .rank-form { flex: 1 1 100%; }
}

/* Labels that only a screen reader needs — one per rank picker, where a visible
   label would repeat the column heading on every row. */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.guild-motto { font-size: 13px; color: var(--muted); }

/* Guild logos sit where the placeholder square does, so they take the same
   border and the same hard-edged scaling as the rest of the art. */
.guild-logo { border: 1px solid var(--border); background: var(--panel-dark); object-fit: contain; image-rendering: pixelated; }
.guild-logo-52 { width: 52px; height: 52px; }
.guild-logo-96 { width: 96px; height: 96px; }

/* The image panel: current picture beside the upload field, stacking on a
   narrow screen. */
.logo-form { display: flex; flex-wrap: wrap; gap: 20px; align-items: flex-start; }
.logo-form-fields { flex: 1 1 260px; }
.logo-form-fields form:last-child { margin-top: 4px; }
.logo-form .field input[type="file"] { padding: 7px 10px; cursor: pointer; }
.rank { font-family: var(--pixel); font-size: 12px; color: var(--muted); }
.rank-top { color: var(--accent); }
.is-online { color: var(--success); font-size: 13px; }
.is-offline { color: var(--muted); font-size: 13px; }
.price { font-family: var(--mono); color: var(--accent); }

.tag {
    padding: 3px 9px;
    border: 1px solid var(--border);
    border-radius: 3px;
    font-family: var(--mono);
    font-size: 11px;
    color: var(--muted);
}
.tag-war { color: var(--danger); }
.tag-open { color: var(--success); }
.tag-boost { background: var(--panel-alt); border-color: var(--accent-dark); color: var(--accent); padding: 4px 10px; }
.tag-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }

/* Characters ------------------------------------------------------------ */

.char-list { display: flex; flex-direction: column; gap: 1px; background: var(--border); border: 1px solid var(--border); }
.char-row { background: var(--panel); padding: 14px 16px; display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; gap: 14px; align-items: center; }
.char-name { font-weight: 600; font-size: 16px; }
.char-meta { font-size: 13px; color: var(--muted); }
.char-actions { display: flex; gap: 8px; align-items: center; }

/* Guild wars ------------------------------------------------------------ */

/* Like .char-list, without the sprite column: a war has two sides and a set of
   buttons, and no picture to put in front of it. */
.war-list { display: flex; flex-direction: column; gap: 1px; background: var(--border); border: 1px solid var(--border); }
.war-row { background: var(--panel); padding: 14px 16px; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 14px; align-items: center; }
.war-row-over { opacity: 0.6; }
.war-title { font-weight: 600; font-size: 16px; }
.war-meta { margin-top: 3px; font-size: 13px; color: var(--muted); }
.war-score { font-family: var(--mono); color: var(--text); }
.war-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* The terms of a declaration: frags, days, stake. Read across, not down. */
.war-terms { display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 8px 0 0; font-family: var(--mono); font-size: 12px; color: var(--muted); }

@media (max-width: 700px) {
    .war-row { grid-template-columns: minmax(0, 1fr); }
}

/* Boosted creature ------------------------------------------------------ */

.boosted-layout { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 24px; align-items: start; }
.boosted-layout h2 { margin: 0 0 6px; font-family: var(--display); font-size: 28px; color: var(--text); }
.boost-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; align-items: start; }
.boost-card { padding: 20px; background: var(--panel-alt); border: 1px solid var(--border); border-radius: 4px; text-align: center; }
.boost-card h2 { margin: 14px 0 4px; font-family: var(--display); font-size: 26px; color: var(--text); }
.boost-card p { margin: 0; font-family: var(--mono); font-size: 12px; }

/* Loot list under a boosted creature. The card is centred, the drops are not:
   a column of names reads far better left aligned. */
.loot-list { margin-top: 18px; text-align: left; }
.loot-list .stat-label { display: block; margin-bottom: 8px; }

.loot-grid { display: grid; gap: 1px; margin: 0; padding: 0; list-style: none; background: var(--border); border: 1px solid var(--border); }
.loot-row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 12px; padding: 7px 11px; background: var(--panel); }
.loot-name { font-size: 13px; color: var(--text-soft); }
.loot-meta { display: flex; align-items: baseline; gap: 8px; font-family: var(--mono); font-size: 11px; white-space: nowrap; }
.loot-amount { color: var(--muted); }

/* The rarer the drop, the warmer the label — common fades into the panel,
   very rare is picked out in the accent gold. */
.loot-rarity { text-transform: uppercase; letter-spacing: 0.5px; color: var(--faint); }
.loot-rarity.is-uncommon { color: var(--muted); }
.loot-rarity.is-semi-rare { color: var(--text-soft); }
.loot-rarity.is-rare { color: var(--accent-dark); }
.loot-rarity.is-very-rare { color: var(--accent); }
.loot-rarity.is-always { color: var(--success); }

/* Scoped past `.boost-card p`, which would otherwise win on specificity. */
.loot-list .loot-note { margin-top: 10px; font-size: 11px; line-height: 1.5; }

/* Creature art is pixel art: scale it up with hard edges, never blurred. */
.creature-sprite {
    display: flex; align-items: center; justify-content: center;
    min-height: 160px;
    margin-top: 12px;
    padding: 12px;
    background: var(--panel-dark);
    border: 1px solid var(--border);
    border-radius: 4px;
}
.creature-sprite img { max-width: 128px; max-height: 128px; image-rendering: pixelated; }
.creature-sprite span { font-size: 13px; text-align: center; line-height: 1.5; }

.creature-icon { width: 32px; height: 32px; object-fit: contain; image-rendering: pixelated; flex: none; }

.week-row { display: flex; flex-wrap: wrap; gap: 1px; background: var(--border); border: 1px solid var(--border); }
.week-day { flex: 1 1 120px; background: var(--panel); padding: 12px 14px; text-align: center; }
.week-day.is-today { background: var(--panel-alt); }
.week-day .stat-label { text-align: center; }
.week-day .sprite { height: 40px; margin: 8px 0; }
.week-name { font-size: 13px; color: var(--muted); }
.week-day.is-today .week-name { color: var(--accent); }
.week-name.is-unknown { color: var(--faint); }

/* Player profile -------------------------------------------------------- */

.player-head { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 20px; align-items: center; }
.player-head h1 { margin: 0 0 4px; font-size: 28px; }
.back-link { display: inline-block; margin-bottom: 12px; color: var(--muted); font-size: 13px; }
.death-row { display: flex; flex-wrap: wrap; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--border); }
.death-row:last-child { border-bottom: 0; }
.death-date { font-family: var(--mono); font-size: 13px; color: var(--muted); min-width: 130px; }

/* News ------------------------------------------------------------------ */

.news-post { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; }
.news-post:has(.news-image) { grid-template-columns: minmax(0, 240px) minmax(0, 1fr); }
.news-image img { width: 100%; height: 100%; max-height: 220px; object-fit: cover; border: 1px solid var(--border); border-radius: 4px; }
.news-body h2 { margin: 8px 0 10px; font-size: 22px; }
.news-body p { margin: 0 0 10px; color: var(--muted); }
.news-body p:last-child { margin-bottom: 0; }

@media (max-width: 700px) {
    .news-post:has(.news-image) { grid-template-columns: minmax(0, 1fr); }
}

/* Downloads, rules, support --------------------------------------------- */

.download-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
.download-card { display: flex; flex-direction: column; gap: 8px; padding: 18px; background: var(--panel-alt); border: 1px solid var(--border); border-radius: 4px; }
.download-card.is-primary { border-color: var(--accent-dark); }
.download-card h2 { margin: 0; font-size: 19px; }
.download-card p { margin: 0; }
.download-card .actions { margin-top: auto; padding-top: 8px; }
.download-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.download-size { font-family: var(--mono); font-size: 12px; color: var(--muted); }

/* Coin store ------------------------------------------------------------ */

/* The balance is a number players compare against a price, so it is set in the
   figure font and picked out in gold wherever it appears. */
.coin-balance { font-family: var(--mono); font-size: 17px; color: var(--accent-light); }
.coin-buy { margin-left: 10px; font-size: 13px; }

.coin-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 16px; }

.coin-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 20px 18px;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: 4px;
    text-align: center;
}
.coin-card.is-primary { border-color: var(--accent-dark); }
.coin-card p { margin: 0; font-size: 14px; }

/* The price is the button: one thing to read, one thing to click. */
.coin-card .actions { margin-top: auto; padding-top: 12px; justify-content: center; }
.coin-card .actions .button { font-family: var(--mono); }

.coin-amount { font-family: var(--display); font-size: 30px; line-height: 1.2; color: var(--accent-light); }
.coin-label {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--muted);
}

/* A data-table used as a real table rather than as label / value pairs. */
.data-table-rows th { width: auto; }

.rule-list, .steps { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 12px; }
.rule-list { list-style: square; }
.rule-list li, .steps li { color: var(--muted); line-height: 1.6; }
.rule-list strong { color: var(--text); }

.recovery-code {
    margin-top: 16px;
    padding: 18px 20px;
    background: var(--panel-alt);
    border: 1px solid var(--accent-dark);
    border-radius: 4px;
    font-family: var(--mono);
    font-size: 22px;
    letter-spacing: 3px;
    color: var(--accent);
    text-align: center;
    word-break: break-all;
}

/* Sidebar widgets ------------------------------------------------------- */

.widget { background: var(--panel); border: 1px solid var(--border); border-radius: 6px; padding: 18px; }
.widget-boost { border-color: var(--accent-dark); }
.widget h3 { margin: 0 0 12px; font-family: var(--pixel); font-size: 10px; letter-spacing: 1px; color: var(--accent); }

.status-line { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.status-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--success); }
/* Not accepting logins, and not asked. The dot is never the only thing that
   says so — the word beside it does too, for anyone who cannot tell the
   colours apart. */
.status-dot-down { background: var(--danger); }
.status-dot-unknown { background: var(--muted); }
.status-count { margin-left: auto; font-family: var(--mono); color: var(--accent); }
.meter { height: 6px; background: var(--bg); border: 1px solid var(--border); }
.meter > span { display: block; height: 100%; background: var(--accent-dark); }
.meter-foot { display: flex; justify-content: space-between; margin-top: 6px; font-size: 12px; color: var(--muted); }

.widget-boost .sprite-lg { aspect-ratio: auto; height: 120px; margin-bottom: 12px; }
.boost-row { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.boost-name { display: block; font-family: var(--display); font-size: 19px; color: var(--text); }
.boost-note { display: block; font-size: 13px; color: var(--muted); }

.mini-list { display: flex; flex-direction: column; }
.mini-row { display: flex; align-items: baseline; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--border); }
.mini-row:last-child { border-bottom: 0; }
.mini-rank { font-family: var(--mono); font-size: 12px; color: var(--muted); width: 18px; }
.mini-name { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 14px; }
.mini-level { font-family: var(--mono); font-size: 13px; }
.widget .button { margin-top: 12px; }
.auction-row { display: flex; justify-content: space-between; gap: 8px; font-size: 14px; margin-bottom: 8px; }
a.auction-row { color: inherit; text-decoration: none; }
a.auction-row:hover { color: var(--accent); }

/* Outfits --------------------------------------------------------------- */

/* A character, drawn from their outfit and colours by App\Outfits. The picture
   is made to fit these boxes exactly, so nothing here resizes it: pixel art the
   browser stretches is what turns an outfit into a smudge. */
.outfit-frame {
    display: flex; align-items: center; justify-content: center;
    width: 96px; height: 96px;
    background: var(--panel-dark);
    border: 1px solid var(--border);
    border-radius: 4px;
}
.outfit-frame img { image-rendering: pixelated; }

.outfit-frame-sm {
    width: 44px; height: 44px;
    border-radius: 3px;
}

/* Footer ---------------------------------------------------------------- */

.site-footer { border-top: 1px solid var(--border); background: var(--panel-dark); }
.site-footer .container {
    display: flex; flex-wrap: wrap; gap: 16px;
    justify-content: space-between; align-items: center;
    padding-top: 22px; padding-bottom: 22px;
    color: var(--muted); font-size: 13px;
}
.footer-links { display: flex; flex-wrap: wrap; gap: 18px; }

@media (max-width: 720px) {
    .boosted-layout { grid-template-columns: 1fr; }
    .hero-body h1 { font-size: 26px; }
}
